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]
/// <summary> /// GeneratedApplication /// </summary>
public partial class GeneratedApplication : System.Windows.Application
{
/// <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.Run();
}
}
역시 MSBuild 에 의해서 XAML 이 해석되고, 이를 바탕으로 partial 클래스가 생성되는 것이 맞네요.
이 상태에서 실행하면, StartupUri 가 없기 때문에, 프로세스는 생성되지만 화면에는 아무것도 노출되지 않습니다.
'개발자 > WPF(C#) UI' 카테고리의 다른 글
WPF UI 반응이 느려졌을 때 Tips (2) | 2020.04.09 |
---|---|
Enum 사용, WPF 및 GUI 디버깅 (0) | 2020.04.05 |
c# Joystick 거리, degree->좌표 변환 (0) | 2020.04.01 |
Visual Studio에서 프로그램 컴파일 시 dll 포함 (0) | 2020.03.30 |
[WPF] UI Thread 연동을 위한 팁 (0) | 2020.03.25 |