WPF 기본 동작구조




저는 C# 을 하다가, WPF 를 접하게 되었습니다.

당시에 생각하기로 XAML 은 단순히 UI 를 ML 을 통해서 작성할 수 있도록 해 주는 보조적인 것으로 생각했습니다.

왜냐면, C# 으로 WPF 프로그래밍이 가능하니까요.


그러다보니, C# 없는 XAML 은 동작이 불가능하다.

"존재 의미가 없다." /  "XAML 혼자 동작할 수 없다."

라고 무의식적으로 생각해 왔습니다.


그리고, 당장 개발하기 급급해서 내부적으로 어떻게 동작하는 줄 모르고,

그냥 사용하기에 바빴지요.


그래서, 오늘은 이 부분에 대해서 좀 살펴 보도록 하려 합니다. :)




WPF 빌드 및 동작 구조


먼저 WPF 응용프로그램을 만들었습니다.


App.xaml 과 MainWindow.xaml 이렇게 두개가 생성되었네요.


먼저 App.xaml 을 살펴보도록 하겠습니다.

왜냐면, 이게 프로그램의 Entry Point 니까요.



    [App.xaml]


 <Application x:Class="WPFApplication.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>




가장 처음 WPF(XAML) 를 접했을때, '뭐가 이렇게 네임스페이스가 많아?' 라고 생각했습니다. :)

xmlns 과 xmlns:x 는 clr 에서 정의된 내용이라고 추측하고 있습니다.

(이 부분에 대해서는 자료를 좀 찾아보려 했는데, 잘 보이지 않네요.)

모쪼록 이 두개의 네임스페이스는 꼭 필요하다고만 짚고 넘어가겠습니다.



x:Class 가 하는 일은?


x:Class 는 역시나 clr 내부적으로 정의된 부분인것으로 추측되는데요.

msdn 에 살펴보면, 


  • In markup, the Application element must include the x:Class attribute. When the application is built, the existence of x:Class in the markup file causes MSBuild to create a partial class that derives from Application and has the name that is specified by the x:Class attribute. This requires the addition of an XML namespace declaration for the XAML schema (xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml").


이렇게 설명되어 있습니다.


MSBuild 가 자동으로 x:Class 에 정의된 클래스의 partial 클래스를 생성해 준다고 되어 있습니다.

바로 '*.g.i.cs' 라는 확장자로 된 파일을 말하는 것이지요.


그럼 그 파일을 열어보죠.



    [App.g.i.cs]


public partial class App : System.Windows.Application {
        
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public void InitializeComponent() {
            
            #line 4 "..\..\App.xaml"
            this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
            
            #line default
            #line hidden
        }
        
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public static void Main() {
            WPFApplication.App app = new WPFApplication.App();
            app.InitializeComponent();
            app.Run();
        }
    }



바로 이것이 MSBuild 가 생성한 파일입니다.

Main 함수를 제외하면, 결국 자동생성된 내용은 InitializeComponent() 이 되겠습니다.



this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);



이 한줄인데, Application 에 StartupUri 프로퍼티를 set 해주는게 전부입니다.

잠깐!

StartupUri 프로퍼티를 어디서 본것 같지 않나요?

맞습니다. App.xaml 에서 정의되어 있었지요.



여기서 우리는 다음 사실을 유추해 낼 수 있습니다.


1. MSBuild 는 XAML 코드를 읽고, xmlns 를 확인한다.

2. x:Class 로 정의된 값이 있는지 확인한다.

3. x:Class 가 존재하면, 해당 클래스의 partial 을 생성한다.

4. partial 에 XAML 코드에 작성된 것을 바탕으로 코드를 자동생성한다.




x:Class 를 삭제한다면?


그럼 테스트를 한번 해 보도록 합시다.

App.xaml 에서 x:Class 부분을 삭제하고, 빌드해 보도록 하겠습니다.




    [x:Class 를 삭제]


<Application 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>





[삭제 전]



[삭제 후]



보시는 것 처럼, partial 인 App.g.i.cs 파일이 통째로 삭제되었습니다.

덕분에 Main 메소드까지 사라졌네요.


이로서, MSBuild 가 XAML 을 바탕으로, x:Class 에 정의된 클래스의 partial 을 자동생성 해 준다는 사실을 확인하였습니다.

그런데!




Main 메소드가 없이도 실행이 된다?


Main 이 없어졌다면.. 프로그램은 어떻게 실행될까요? 아니 빌드는 될까요? 실행은 될까요?

신기하게도, 빌드도 정상적으로 되고, 실행도 잘 됩니다. :)



이유는 솔루션 탐색기에서 노출이 안되는 것 뿐이고, App.g.i.cs 는 여전히 어딘가에 살아 있습니다.

그리고 그 코드를 보면, 요렇게 바뀌어 있습니다.




    [App.g.i.cs]


#pragma checksum "..\..\App.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "6A5D1236E94AE7445F15103C4E132DF4"
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18444
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;


namespace XamlGeneratedNamespace {
    
    
    /// <summary>
    /// GeneratedApplication
    /// </summary>
    public partial class GeneratedApplication : System.Windows.Application {
        
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public void InitializeComponent() {
            
            #line 4 "..\..\App.xaml"
            this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
            
            #line default
            #line hidden
        }
        
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public static void Main() {
            XamlGeneratedNamespace.GeneratedApplication app = new XamlGeneratedNamespace.GeneratedApplication();
            app.InitializeComponent();
            app.Run();
        }
    }
}




바뀐부분은 아래 코드 한줄이네요.


[삭제 전]

WPFApplication.App app = new WPFApplication.App();


[삭제 후]

XamlGeneratedNamespace.GeneratedApplication app = new XamlGeneratedNamespace.GeneratedApplication();



App 과 GeneratedApplication 의 차이는 그냥 Class 이름이 변경된것 뿐입니다.

(Framework 에 있는 클래스가 아니라, 코드를 잘 보시면 아시겠지만, 그냥 자기 자신 클래스 이름입니다.)


즉, App.xaml 에 대해서는 명시적으로 x:Class 를 써 주느냐, 마느냐의 차이 밖엔 없는것으로 보여집니다.

App.xaml 을 아래처럼 수정하고, x:Class 를 정의한 상태에서 빌드. 삭제한 상태에서 빌드. 각각 비교해 보면,

App 이 GeneratedApplication 으로 바뀌는것 이외에는 차이가 없음을 알 수 있습니다.




<Application
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
        </Style>
    </Application.Resources>
</Application>






StartupUri 가 없다면?


이번엔 한번 App.xaml 에서 StartupUri 설정 부분을 삭제하고 빌드해 보죠.

다음처럼 App.g.i.cs 가 바뀌었습니다.



    [App.g.i.cs]


/// &lt;summary&gt;
/// GeneratedApplication
/// &lt;/summary&gt;
public partial class GeneratedApplication : System.Windows.Application {
        
    /// &lt;summary&gt;
    /// Application Entry Point.
    /// &lt;/summary&gt;
    [System.STAThreadAttribute()]
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
    public static void Main() {
        XamlGeneratedNamespace.GeneratedApplication app = new XamlGeneratedNamespace.GeneratedApplication();
        app.Run();
    }
}



역시 MSBuild 에 의해서 XAML 이 해석되고, 이를 바탕으로 partial 클래스가 생성되는 것이 맞네요.

이 상태에서 실행하면, StartupUri 가 없기 때문에, 프로세스는 생성되지만 화면에는 아무것도 노출되지 않습니다.





다음에는 MainWindow.xaml 부분을 이것저것 수정하여, 테스트 해 보도록 하겠습니다.




'Microsoft > WPF' 카테고리의 다른 글

TypeConverter  (0) 2014.05.12
XAML 의 문법구조  (0) 2014.05.12
xaml 과 cs 파일의 관계  (0) 2014.05.08
WPF 기본 동작구조  (0) 2014.05.08
WPF 3D Tutorial  (4) 2011.04.09
Animated Image  (0) 2010.12.10