WPF, XAML

WPF HelloWorld C#코드기반의 HelloWorld, XAML없이 C# 코드로만 작성예제

FSP 0 24 10.05 11:52

WPF HelloWorld C#코드기반의 HelloWorld, XAML없이 C# 코드로만 작성예제 

 

WPF HelloWorld-2(C#코드 기반)

n  Visual Studio File -> New -> Project -> Visual C# -> WPF 응용프로그램

프로젝트명 : HelloWorld2

n  App.xaml, MainWindow.xaml 삭제

n  프로젝트 >> 추가 >> 새항목에서 MyMain.cs 파일 추가

 

 

[MyMain.cs]

using System;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

 

namespace HelloWorld2

{

    class MyMain : Application

    {

        [STAThread]

        public static void Main()

        {

            MyMain app = new MyMain();

            app.ShutdownMode = ShutdownMode.OnMainWindowClose;

            app.Run();

        }

 

        protected override void OnStartup(StartupEventArgs e)

        {

            base.OnStartup(e);

 

            Window mainWindow = new Window();

            mainWindow.Title = "WPF Sample(Main)";

            mainWindow.MouseDown += WinMouseDown;

            mainWindow.Show();

 

            for (int i = 0; i < 2; i++)

            {

                Window win = new Window();

                win.Title = "Extra Window No." + (i + 1);

                win.Show();

            }

        }

 

        void WinMouseDown(Object sender, MouseEventArgs args)

        {

            Window win = new Window();

            win.Title = "Modal DialogBox";

            win.Width = 400;

            win.Height = 200;

 

            Button b = new Button();

            b.Content = "Click Me!";

            b.Click += Button_Click;

 

            win.Content = b;

            win.ShowDialog();

        }

 

        private void Button_Click(object sender, EventArgs e)

        {

            MessageBox.Show("Button Click!", sender.ToString());

        }

    }

}

 

 

n  실행화면(F5)

 

 

[코드설명]

n  using System.Windows : 이 네임스페이스에는 Application, Window를 포함한 WPF 클래스, 구조체, 인터페이스, 열거형들을 포함한다.

 

n  WPF Main에는 [STAThread] 속성이 반드시 나타나야 하며 그렇지 않다면 InvalidOperationException이 발생한다. STAThread는 최초 응용프로그램을 Single-Thread Apartment로 실행한다는 의미이며, COM과 같이 사용되는 경우에 쓰이게 되서 응용프로그램이 멀티쓰레드를 허용하지 않는다는 의미로 사용된다. 일반적인 C# 응용프로그램은 기본적으로 Multi-Thread Apartment이다.

 

일반적으로 C#에서 STA를 사용하는 경우는 싱글 쓰레드로만 동작되는 COM 객체를 사용하는 경우인데 드래그 드롭 기능, 클립보드 관련 기능, OpenDialog, SaveFileDialog, 웹브라우저 컨트롤 등을 사용하는 경우 반드시 STAThread로 동작되어야 한다.

 

n  프로젝트에서 우측 마우스 클릭 후 속성창에서 실행형태를 Console로 하면 Console 창도 같이 뜨면서 실행되는데 이는 실행중이거나 디버깅시 Console.Wirte등을 이용하여 텍스트를 출력해 볼 수 있으므로 유용하다.

 

 

가령 윈도우 프로그램을 잘못짜서 무한 루프에 빠지게 했다면 콘솔창에서 Ctrl + C 키로 종료할 수 있다. 만약 콘솔창이 없다면 윈도우는 먹통이 되어서 중단시키기도 불편하다

 

n  응용프로그램의 시작이 되는 클래스는 Application 클래스를 상속받아야 하며 해당 인스턴스의 Run() 메소드를 통해 응용프로그램이 시작한다.

 

위 예제에서 Application 클래스를 상속받지 않는 형태로 윈도프로그램을 시작하려면 OnStartUp을 오버라이드 하지 않고 메인에서 다음과 같이 하면 된다.

 

using System;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

 

namespace HelloWorld2

{

    class MyMain

    {

        [STAThread]

        public static void Main()

        {

            Window mainWindow = new Window();

            mainWindow.Title = "WPF Sample(Main)";

            mainWindow.MouseDown += WinMouseDown;

            //mainWindow.Show();

 

            for (int i = 0; i < 2; i++)

            {

                Window win = new Window();

                win.Title = "Extra Window No." + (i + 1);

                win.Show();

            }

 

            // WPF Samplw(Main) 윈도우를 맨 마지막에 띄움

            Application app = new Application();

            app.Run(mainWindow);

        }

 

        static void WinMouseDown(Object sender, MouseEventArgs args)

        {

            Window win = new Window();

            win.Title = "Modal DialogBox";

            win.Width = 400;

            win.Height = 200;

 

            Button b = new Button();

            b.Content = "Click Me!";

            b.Click += Button_Click;

 

            win.Content = b;

            win.ShowDialog();

        }

 

        static void Button_Click(object sender, EventArgs e)

        {

            MessageBox.Show("Button Click!", sender.ToString());

        }

    }

}

 

Application 클래스는 하나의 프로젝트에서 하나만 사용 가능하고 Window는 보이지만 Application 객체는 보이지 않는다. Window 객체의 Show() 메소드를 호출하는 대신 Run() 메소드의 인자로 넘겨도 된다. App.Run(win); 이 경우 Run() 메소드는 win 객체의 Show()를 호출하는 것까지 담당한다.

 

응용프로그램은 Run() 메소드가 실행되기 전까지 실제 시작되지 않으며 호출된 후에 Window 객체가 사용자의 입력에 반응을 할 수 있다. 사용자가 창을 닫고 Run() 메소드를 종료하면 프로그램은 종료를 준비한다.

 

C# 윈폼, WPF 응용프로그램에서 프로그램이 대체로 하는 일은 사용자의 이벤트에 기반해서 프로그램이 작동되는데 이벤트란 키보드, 마우스, 스타일러스 팬의 입력을 의미한다. UIElement 클래스는 키보드, 마우스, 스타일러스 팬의 입력과 관련된 몇가지의 이벤트가 정의되어 있는데 Window 클래스는 이 모든 이벤트를 상속받는다. 본 예제에서는 이벤트 중 버튼 클릭, 마우스 다운과 관련된 이벤트를 사용하였다.

 

n  MouseDown 이벤트에서 첫 번째 인자는 object형의 이벤트 발생 객체이며 두 번째 인자인 MouseEventArgs는 마우스 관련 이벤트가 발생했을 때 넘어오는 데이터, 즉 왼쪽 또는 오른쪽 버튼을 눌렀는지, 몇 번 눌렀는지 등이 넘어오게 된다. 이 클래스는 System.Windows.Input 네임스페이스에 정의되어 있으므로 using문으로 선언을 해야 한다.

 

n  MessageBox 클래스는 System.Windows 네임스페이스에 정의되어 있으며 사용자에게 어떤 메시지를 보여주기 위한 것으로 대화상자라고 부른다.

 

n  Application 클래스는 유용한 몇 가지 이벤트가 정의되어 있는데 닷넷의 관례대로 대부분의 이벤트는 이를 처리하는 protected 메소드와 연관이 되어 있다. StartUp 이벤트는 OnStartUp 메소드와 연관되고 Run() 메소드가 호출된 직후에 실행된다. Run() 메소드가 리턴되기 전에 Exit 이벤트가 발생되고 이에 대응되는 OnExit() 메소드가 호출되게 된다.

 

사용자가 윈도우를 로그오프 하거나 컴퓨터를 종료시킬 때는 SessionEnding 이벤트가 발생한다. 이때 인자로 SessionEndingCancelEventArgs 타입의 이벤트 데이터를 넘기는데 만약 윈도우가 종료되는 것을 방지하고 싶다면 Cancle 프로퍼티로 설정하면 된다.

 

* 참고로 출력형식을 콘솔이 아닌 Window 응용 프로그램으로 컴파일한 경우에만 SessionEnding 이벤트를 받을 수 있다.

 

n  OnStartUp에서 생성된 윈도우는 이 응용프로그램 내에서 모두 동등하다고 할 수 있는데 어떤 창이라도 클릭하면 전면으로 나오게 되고 임의의 순서대로 닫을 수 있으며 마지막 창이 종료되면 프로그램은 종료된다.

 

예제를 실행하면 하단 태스크바에 윈도우 아이콘 세개가 나타나는데 하나만 나타나게 하려면 for 루프에 다음 코드를 추가하면 된다.

 

win.ShowInTaskbar = false;

 

하지만 문제가 하나 있다. Extra Window.1, 2가 떠있더라도 “WPF Sample(Main)” 메인 윈도우가 닫히면 태스크바 아이콘이 사라진다. 일반적으로 Run() 메소드가 리턴될 때 프로그램이 종료된다.

 

마지막 창을 닫을 때 Run() 메소드가 리턴되므로 이러한 동작은 ApplicationShutdownMode 프로퍼티를 어떻게 설정하느냐에 따라 다르게 동작하는데 열거형 멤버로 설정한다. 기본값은 ShutdownMode.OnLastWindowClose 이며 마지막 윈도우가 닫힐 때 프로그램이 종료되는 것으로 값을 OnMainWindowClose로 변경하여 다시 실행해 보자. Run() 메소드를 호출하기전에 아래 코드를 삽입 후 실행하여 결과를 확인하자.

 

// “WPF Sample(Main)” 윈도우 닫을 때 서브 윈도우 같이 닫힌다.

app.ShutdownMode = ShutdownMode.OnMainWindowClose;

 

OnStartUp() 메소드에 다음처럼 삽입해도 동일한 결과를 얻는다.

this.ShutdownMode = ShutdownMode.OnMainWindowClose;

 

위 코드를 그대로 두고 for 루프안에서 아래처럼 설정해보자.

this.MainWindow = win;

 

결론적으로 마지막에 뜨는 윈도우가 메인 윈도우가 되므로 이 창을 닫으면 프로그램이 종료된다. 마지막으로 ShutdownMode에 대입가능한  ShutdownMode.OnExplicitShutdown 값이 있는데 Application 클래스의 Shutdown 메소드를 명시적으로 호출하는 경우에만 응용프로그램이 종료된다.

 

이번에는 여러 창의 계층구조를 만드는 방법에 대해 살펴보자.

 

Window 클래스의 Owner 속성을 이용하는데 여기에 다른 윈도우 객체를 대입하면 된다. for 루프에 다음코드를 추가해 보자.

//메인창이 나머지 두 개의 창을 소유한 Owner가 된다.

win.Owner = mainWindow; 

 

소유된 창이 소유한 창앞에 나타나게 되어 있으며 Owner를 최소화 시키면 하위 창들도 자동으로 최소화 되고 닫으면 같이 닫힌다.

 

 

 

 

Comments