반응형

기존에 ClickOnce로 배포했던 앱을 여러 이유로 새로운 명칭과 설치 URL 변경 등으로 새로 만들어서 배포를 할 경우, 기존 ClickOnce 앱의 삭제를 사용자에게 맡길 것인가 아니면 자동으로 삭제하고 설치도 자동으로 하고 싶을 경우 어떻게 하면 될까?

여러가지 방법이 있을 수 있다. 

기존 ClickOnce 배포 앱을 삭제하기 위한 스크립트를 만들어서 스크립트 실행을 통해서 삭제 또는 설치할 수가 있다.

이럴경우 스크립트 파일(WScript)의 디버깅이나 제어가 여러가지로 불편할 수가 있고, 편집기로 쉽게 스크립트 내용을 볼 수 있는 단점이 있다.

스크립트 파일로 삭제/설치도 좋지만 요즘 보안이다 뭐다 해서 주요 정보들을 스크립트로 제공하는 것도 문제가 될 수 있다.

아래는 이러한 문제를 개선한 실행 앱(exe)을 통해서 기존의 ClickOnce 앱을 삭제하고 설치하는 소스이다.

public class ClickOnceRemoveInstall
    {        
        public static void Main(string[] args)
        {
            //CMD 창을 숨긴다.
            var handle = GetConsoleWindow();
            ShowWindow(handle, SW_HIDE); // 숨기기

            //활성화된 ClickOnce App. Kill            
            Process.Start("taskkill", "/F /IM ClickOnce앱명칭*");
            Process killProc = Process.GetProcessesByName("taskkill").FirstOrDefault();
            killProc.WaitForExit();
            killProc.Close();
            
            //기존 설치된 ClickOnce App. 제거
            string app = "dfshim.dll,ShArpMaintain ClickOnceAppName.application, Culture=neutral, PublicKeyToken=e5ccc1554e61cee3, processorArchitecture=x86";
            Process.Start("rundll32.exe", app);
            Process removeProc = Process.GetProcessesByName("dfsvc").FirstOrDefault();
            System.Threading.Thread.Sleep(3500); //제거 창이 뜰때까지 잠깐 대기
            if (removeProc != null)
            {
                IntPtr h = removeProc.MainWindowHandle;               
                SetForegroundWindow(h);                
                SendKeys.SendWait("O"); //제거 창에서 확인 버튼 클릭을 위해 Key 입력
                removeProc.Close();                
            }
            
            System.Threading.Thread.Sleep(500);
            
            //새로운 ClickOnce App. 설치
            string appUrl = "http://ClickOnce배포서버명 또는 접속URL/ClickOnceAppName.application";
            Process.Start("rundll32.exe", "dfshim.dll,ShOpenVerbApplication " + appUrl);
            Process installProc = Process.GetProcessesByName("dfsvc").FirstOrDefault();
            System.Threading.Thread.Sleep(2500); //설치 창이 뜰때까지 잠깐 대기
            if (installProc != null)
            {
                IntPtr h = installProc.MainWindowHandle;                
                SetForegroundWindow(h);                                
                SendKeys.SendWait("I"); //설치 창에서 설치 버튼 클릭을 위해 Key 입력               
                installProc.Close();
            }            
        }
        
        [DllImport("User32.dll")]
        static extern int SetForegroundWindow(IntPtr point);
        
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        const int SW_HIDE = 0; // 숨기기
        const int SW_SHOW = 1; // 보이기
    }

 

반응형
반응형

프로그램에서 언어나 문화권에 대한 설정 값을 받아와서 요일 정보를 반환하는 함수

DateTime 을 입력하면 그에 맞는 요일을 반환한다. 

반환하는 값은 월요일, 화요일 .... 토요일, 일요일 로 값을 반환한다.

public static string WeekDay(DateTime dateTime)
{
    //반환할 요일
    String weekDay = string.Empty;
    //입력받은 일자에 대한 요일정보
    var dt = dateTime.DayOfWeek;
    //프로그램에서 언어나 문화권에 대한 설정값을 받아온다.
    CultureInfo cultureInfo = CultureInfo.CurrentCulture;
    weekDay = cultureInfo.DateTimeFormat.GetDayName(dateTime.DayOfWeek);
    return weekDay;
}
반응형
반응형
//사용자가 선택한 ComboBox의 Index값을 이용해서 Value 값을 가져온다.

var prop = cboTime.Items[cboTime.SelectedIndex].GetType().GetProperty(cboTime.ValueMember);
Time = prop.GetValue(cboTime.Items[cboTime.SelectedIndex], null).ToString();

C#을 이용해서 WinForm 개발을 하다 보면 ComboBox 컨트롤 사용을 자주 하게 된다.
매번 ComboBox를 사용하면서 특정 값 또는 텍스트로 ComboBox의 목록 중 1개를 선택하고자 할 경우가 많다.
다양한 방법이 있겠지만, 간단하게 구현해서 사용할 수 있는 방법을 소개하고자 한다.

ComboBox를 이용해서 선택할 수 있는 시간을 콤보박스에 보여주기 위해 Items에 추가하는 로직과 특정 시간대의 값에 따라 콤보박스가 선택되어져 있도록 하기 위한 코드를 남겨둔다.

 

아래는 ComboBox에 간단하게 DisplayMember와 ValueMember로 구분해서 Items에 추가하는 방법.

cboTime.DisplayMember = "Text";
cboTime.ValueMember = "Value";
cboTime.Items.Add(new { Text = "09:00", Value = "0900" });
cboTime.Items.Add(new { Text = "09:30", Value = "0930" });
cboTime.Items.Add(new { Text = "10:00", Value = "1000" });
cboTime.Items.Add(new { Text = "13:30", Value = "1330" });
cboTime.Items.Add(new { Text = "14:00", Value = "1400" });
cboTime.Items.Add(new { Text = "14:30", Value = "1430" });

 

아래는 사용자가 입력한 값에 따라 ComboBox가 선택되어져 있도록 하는 방법

string Time = "1000";
//Time 값이 비어 있을 경우에는 첫번째 항목이 선택되도록 처리
if (string.IsNullOrEmpty(Time) || string.IsNullOrWhiteSpace(Time)) cboTime.SelectedIndex = 0;
else
{
    //ComboBox 항목 수 만큼 돌면서 Time 변수와 같은 값을 가진 항목을 검색
    for(int i = 0; i < cboTime.Items.Count; i++)
    {
        var prop = cboTime.Items[i].GetType().GetProperty(cboTime.ValueMember);
        if (prop != null && prop.GetValue(cboTime.Items[i], null).ToString() == Time)
        {
            cboTime.SelectedIndex = i;
            break;
        }
    }
}

 

사용자가 ComboBox에서 특정 값을 선택했을 경우 가져오는 방법

//사용자가 선택한 ComboBox의 Index값을 이용해서 value을 가져온다.
var prop = cboTime.Items[cboTime.SelectedIndex].GetType().GetProperty(cboTime.ValueMember);
Time = prop.GetValue(cboTime.Items[cboTime.SelectedIndex], null).ToString();

 

반응형
반응형

마우스 Move 또는 Left Button Click 시에 마우스 포인트가 어떠한 선 위에 있는지를 체크하는 방법이다.

하기의 코드에 문제가 있거나, 개선이 필요한 부분이 있다면 의견 주시면 감사하겠습니다.

 

 

Function의 첫번째 파라미터는 선의 시작 포인트, 두번째 파라미터는 선의 종료 포인트, 세번째 파라미터는 마우스의 포인트를 말한다.

    public static bool CheckPointOnLine(Point startP, Point endP, Point point)
    {
        bool check = false;

        double dx = endP.X - startP.X;
        double dy = endP.Y - startP.Y;
        double dx1 = point.X - startP.X;
        double dy1 = point.Y - startP.Y;
        double a = 0, b = 0, c = 0;

        if (Math.Abs(dx) > 0 && Math.Abs(dy) < Math.Abs(dx))
        {
            if (dx * dx1 >= 0 && Math.Abs(dx1) <= Math.Abs(dx))
            {
                a = (dy * dx1);
                b = (dx * dy1);
                c = Math.Abs(dx * 5);
                if (Math.Abs(a - b) <= c)
                {
                    check = true;
                }
            }
        }
        else if (Math.Abs(dy) > 0)
        {
            if (dy * dy1 >= 0 && (Math.Abs(dy1) <= Math.Abs(dy)))
            {
                a = (dx * dy1);
                b = (dy * dx1);
                c = Math.Abs(dy * 5);
                if (Math.Abs(a - b) <= c)
                {
                    if (Math.Abs(a - b) <= c)
                    {
                        check = true;
                    }
                }
            }
        }

        return check;
    }

 

반응형
반응형

내가 만든 컨트롤 위에서 특정 위치에 마우스를 가져 갔을 때 풍선도움말로 사용자에게 메시지를 주고 싶을 때가 있다.

User Control 상의 특정 좌표에 마우스가 오면 풍선도움말을 제공하는 방법이다.

 

먼저 User Control에 대한 핸들 정보를 가져와야 한다.

IWin32Window window = Control.FromHandle(사용자컨트롤.Handle);

//툴팁 생성

ToolTip toolTip = new ToolTip();

toolTip.AutomaticDelay = 500;

toolTip.AutoPopDelay = 5000;
toolTip.InitialDelay = 500;
toolTip.ReshowDelay = 100;

MouseHover 이벤트에서 특정 조건에 맞을 경우 아래의 내용으로 Show를 하면 풍선 도움말이 제공된다.

if (조건이 참이면) {

    toolTip.Show("풍선도움말", window, X좌표, Y좌표);

} else { //그렇지 않을 경우 풍선도움말을 숨긴다.

    toolTip.Hide(window);

}

 

 

반응형
반응형

실제 생성한 Form의 소스가 Form1.cs 라고 하자. 

해당 폼을 개발하면서 UI/Event/Biz. 로직 등을 개발하다보면 Form1.cs파일의 사이즈가 점점 커지게 되고 해당 소스를 유지보수 하기도 불편하게 된다.

이러한 문제를 피하기 위해서 Form1.cs파일에서는 폼과 직접 연관되는 UI 영역만 커버하고 각 컨트롤의 이벤트 처리하는 영역은 별도의 클래스를 만들어서 처리할 수 있게 된다.

이렇게 하면 소스 즉 클래스에 대한 책임과 권한을 명확하게 분리하고 개발 및 유지보수가 편리해진다.

이렇게 설정하기 위해서는 WinForm 소스가 있는 프로젝트 파일에 아래와 같이 설정을 하면 된다.

 

<Compile Include="Form1.cs">

    <SubType>Form</SubType>

</Compile>

<Compile Include="Form1.Designer.cs">

    <DependentUpon>Form1.cs</DependentUpon>

</Compile>

<Compile Include="Form1.Event.cs">

    <DependentUpon>Form1.cs</DependentUpon>

    <SubType>Form</SubType>

</Compile>

반응형
반응형

한 주의 시작요일을 일요일로 했을 경우의 주차 정보 가져오기

Console.WriteLine("2015.01.01 주차는 " + GetWeekNumber(2015, 01, 01, DayOfWeek.Sunday));
Console.WriteLine("2015.02.01 주차는 " + GetWeekNumber(2015, 02, 01, DayOfWeek.Sunday));

 

한주의 시작요일을 월요일로 했을 경우의 주차 정보 가져오기
Console.WriteLine("2015.01.01 주차는 " + GetWeekNumber(2015, 01, 01, DayOfWeek.Monday));
Console.WriteLine("2015.02.01 주차는 " + GetWeekNumber(2015, 02, 01, DayOfWeek.Monday));

 

public static int GetWeekOfYear(DateTime sourceDate, CultureInfo cultureInfo, DayOfWeek dayOfWeek)
{
    if (cultureInfo == null)
    {
        cultureInfo = CultureInfo.CurrentCulture;
    }

    //해당 주의 첫째 요일 전까지 4일 이상이 있는 첫째 주가 해당 연도의 첫째 주가 되도록 지정
    CalendarWeekRule calendarWeekRule = CalendarWeekRule.FirstFourDayWeek;
    //주의 시작요일이 일요일 또는 월요일인지 확인. dayOfWeek가 일/월이 아닌 경우 월요일로 설정
    DayOfWeek firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek;
    if (dayOfWeek == DayOfWeek.Sunday || dayOfWeek == DayOfWeek.Monday) 
    {
        firstDayOfWeek = dayOfWeek;
    } else firstDayOfWeek = DayOfWeek.Monday;
    
    int WeekOfYear = cultureInfo.Calendar.GetWeekOfYear(sourceDate, calendarWeekRule, firstDayOfWeek);

    return WeekOfYear;
}
반응형
반응형

GDI+를 이용해서 특정 이미지 또는 특정 위치에 글자를 정렬하고 싶을 때는 StringFormat을 이용하면 된다.

아래는 GDI+에서 Rectangle 영역에서 문자에 대한 Left/Center/Right 정렬을 하기 위해서 구현한 소스의 일부분이다.

 

//헤더 정렬이 Left일 경우
if (columns[i].HeaderAlign == HorizontalAlignment.Left)
{
    StringFormat sf = new StringFormat();
    sf.LineAlignment = StringAlignment.Center;
    sf.Alignment = StringAlignment.Near;
    Rectangle colRec = new Rectangle(startVSplitePos + leftHeaderWidth, 0, columns[i].Width, columns[i].Height);
    graphics.DrawString(columns[i].Text, headerFont, darkBlueBrush, colRec, sf);
}
else if (columns[i].HeaderAlign == HorizontalAlignment.Right) //헤더 정렬이 Right일 경우
{
    StringFormat sf = new StringFormat();
    sf.LineAlignment = StringAlignment.Center;
    sf.Alignment = StringAlignment.Far;
    Rectangle colRec = new Rectangle(startVSplitePos + leftHeaderWidth, 0, columns[i].Width, columns[i].Height);
    graphics.DrawString(columns[i].Text, headerFont, darkBlueBrush, colRec, sf);
}
else if (columns[i].HeaderAlign == HorizontalAlignment.Center) //헤더 정렬이 Center일 경우
{
    StringFormat sf = new StringFormat();
    sf.LineAlignment = StringAlignment.Center;
    sf.Alignment = StringAlignment.Center;
    Rectangle colRec = new Rectangle(startVSplitePos + leftHeaderWidth, 0, columns[i].Width, columns[i].Height);
    graphics.DrawString(columns[i].Text, headerFont, darkBlueBrush, colRec, sf);
}

반응형
반응형

특정 일자간의 일 수 차이를 가져오는 방법이다.

간단하게 말하면 2019-01-09와 2019-01-08 일 간의 일 수 차이는 1일이 된다.

이렇게 차이나는 일 수를 가져오는 방법을 간략하게 구현해 보자.

통상 일자의 경우 DB에 저장할때 Date타입으로 저장하기도 하지만 8자리의 문자로 저장하기도 한다. ('20090109' 이런 식으로...)

 

현재일자를 기준으로 특정일자 와의 일 수 차이를 계산해 보도록 하자.

 

//현재 일자를 가져오는데...시간은 제외하고 일자만 가져온다.

//일자 저장 시에 시스템 일자를 저장한 DateTime 변수를 strTarget이라고 하자.

 

string strCrntDate = DateTime.Today.ToString("yyyy-MM-dd");

string strTargetDate = mArranged.ToString("yyyy-MM-dd");

 

//날짜만을 가지고 DateTime 타입의 변수를 생성해서 두 날짜 간의 minus 연산을 한다.

DateTime crntDate = Convert.ToDateTime(strCrntDate);
DateTime targetDate = Convert.ToDateTime(strTargetDate);
double chai = (crntDate - targetDate).TotalDays;

반응형

+ Recent posts