본문 바로가기

개발자/WPF(C#) UI

WPF 기본 동작구조

반응형

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]

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() 
  { 
    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 가 없기 때문에, 프로세스는 생성되지만 화면에는 아무것도 노출되지 않습니다.

 

 

반응형