[1. WPF시작] 1-5) HELLO WORLD! 소스 분석해 보기
1. HellowWorld Project를 구성하고 있는 내용은 오른쪽 그림과 같다. Properties, References, App.config, App.xaml, MainWindow.xaml로 구성되어 있으며 각각 어떤내용의 소스가 들어 있는지 확인해 보고자 한다.
1) Properties 부분은 클릭해 보면 AssemblyInfo.cs, Resources.resx, Settings.settings의 파일이 포함되어 있음을 알수 있다.
▷ AssemblyInfo.cs 파일을 열어보면 아래와 같은 내용을 확인할 수 있다.
아래 내용은 프로그램의 Assembly작성에서 활용하게될 내용들이 코드로 들어 있다.
10~17번째까지의 라인에는 Assembly의 일반적인 속성을 넣을 수 있다. 알맞는 속성을 수정하면된다. 앞장에서 설명한 부분에서 수정하면 아래 내용이 수정된다.
22번째 줄에서의 내용은 Microsoft 에서 사용하는 COM과 관련있는 사항으로 true로 설정하면 COM에 나타난다.
31번째 줄의 주석문을 해제하면 미국 영어를 사용하는 환경이된다. 국가에 맞는 코드를 설정하면된다.
34, 35, 39, 44 번째 줄의 내용은 테마 관련 리소스 사전과, 일반 리소스사전을 등록하는 곳이다.
56, 57 번째 줄의 내용은 버전 정보로 주버전, 부버전, 빌드번호, 리버전으로 구성된다.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following// set of attributes. Change these attribute values to modify the information// associated with an assembly.
[assembly: AssemblyTitle("HelloWorld")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HelloWorld")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible// to COM components. If you need to access a type in this assembly from// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// In order to begin building localizable applications, set// <UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file// inside a <PropertyGroup>. For example, if you are using US english// in your source files, set the <UICulture> to en-US. Then uncomment// the NeutralResourceLanguage attribute below. Update the "en-US" in// the line below to match the UICulture setting in the project file.// [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None,
// where theme specific resource dictionaries are located// (used if a resource is not found in the page,// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly
// where the generic resource dictionary is located// (used if a resource is not found in the page,// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values://// Major Version// Minor Version// Build Number// Revision//// You can specify all the values or you can default the Build and Revision Numbers// by using the '*' as shown below:// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
▷ Resources.resx 파일을 열어보면 아래 내용과 같다. 프로그램에서 사용하게 될 여러 종류의 리소스를 정의하는 곳이다.
프로그램 내부에서 사용하게 될 internal static value를 선언할 때 사용한다. 사용하는 방법은 간단하다. Resources.resx파일을 열어서 이름, 값, 주석을 기록하고 저장하면 Resources.resx file의 마지막에 자동으로 소스를 삽입해 준다.
보통 프로그램에서 공용으로 사용하는 메시지나 컨터롤의 레이블네임, 이미지등을 등록해서 사용하면 된다. 기본적으로 get속성만을 제공하므로 읽기 전용으로 생각하면된다. 컴파일을 해보면 실행파일에 포함되는 것으로 알수 있으며 외부에서 수정이 불가하다.
//------------------------------------------------------------------------------// <auto-generated>// This code was generated by a tool.// Runtime Version:4.0.30319.42000//// Changes to this file may cause incorrect behavior and will be lost if// the code is regenerated.// </auto-generated>//------------------------------------------------------------------------------namespace HelloWorld.Properties
{
/// <summary>/// A strongly-typed resource class, for looking up localized strings, etc./// </summary>// This class was auto-generated by the StronglyTypedResourceBuilder// class via a tool like ResGen or Visual Studio.// To add or remove a member, edit your .ResX file then rerun ResGen// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal classResources
{privatestatic global::System.Resources.ResourceManager resourceMan;
privatestatic global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources(){
}
/// <summary>/// Returns the cached ResourceManager instance used by this class./// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HelloWorld.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>/// Overrides the current thread's CurrentUICulture property for all/// resource lookups using this strongly typed resource class./// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
▷ Settings.Designer.cs 파일을 열어보면 아래 내용을 확인할 수 있다. Resource.resx과 특별히 다른것은 없다. 속성에 대한 명확한 정의와 읽기 쓰기 등의 권한을 제한 할 수 있다는 잇점이 있다. 또 다른 장점은 컴파일을 후 에도 수정할 수 있도록 config 파일로 제공한다. 단점은 실행 시점에 속도가 늦어지는 단점이 있다.
Settings.Designer.cs 파일은 App.Config파일과 연계관계가 있다. Settings.Designer.cs파일을 수정하면 App.Config 파일이 수정되나, App.Config 파일을 수정한다고 하여 Settings.Designer.cs 파일이 수정되는 것은 아니므로 주의 해야 한다.
필자의 경우 되도록이면 외부에서 속성을 제어 할 수 있는 것을 좋아하므로 Settings.Designer.cs 파일을 많이 사용하나 실제는 별도로 속성파일을 만들어서 사용하거나 SQLite를 많이 사용하는 편이다.
//------------------------------------------------------------------------------// <auto-generated>// This code was generated by a tool.// Runtime Version:4.0.30319.42000//// Changes to this file may cause incorrect behavior and will be lost if// the code is regenerated.// </auto-generated>//------------------------------------------------------------------------------namespace HelloWorld.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial classSettings : global::System.Configuration.ApplicationSettingsBase
{
privatestatic Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
publicstatic Settings Default
{
get
{
return defaultInstance;
}
}
}
}
▷ Reference는 오른쪽 화면과 같이 구성되며, 프로그램에서 외부 모듈을 참조하는 역할을 한다. .net Framework 와 .net Core에 따라 약간은 다르지만, .net Framework의 기준으로 설명하자면 Add Reference, Add Service Reference, Add Connected Service, Managed NugGet Package 기능을 사용가능하다.
Add Reference는 과거부터 계속 사용해 왔던 내용으로 Assemblies, Projects, Shared Projects, COM등을 참조할 때 사용한다.
Add Service Reference는 Microsoft에서 제공하는 WCF Service를 참조할 때 사용하며, 최근에 추가된 NuGet Package는 글로벌하게 공개된 라이브러리를 참조할때 사용하게 된다.
필자의 경우 대부분의 프로젝트를 WCF 기반으로 개발하고 있으며, NuGet을 보고 난 후 많은 충격을 받았다, 이를 계기로 Open Source를 좋아하고, 동조하게 되었다.
▷ App.config 파일을 열어보면 아래쪽 소스코드와 같다. 위에서 설명했지만 Settings.Designer.cs내용이 XML 파일 형태로 작성되어 있다. App.config 파일에서 속성값을 변경 후 Settings.Settings를 클릭하면 수정사항을 반영하는 메시지를 주지만, 속성을 추가해 주지는 않는다. 위에서도 설명했지만 속성의 추가는 Settings.Settings를 사용하는 것이 좋다.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="HelloWorld.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="HelloWorld.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<userSettings>
<HelloWorld.Properties.Settings>
<setting name="Setting" serializeAs="String">
<value>0</value>
</setting>
</HelloWorld.Properties.Settings>
</userSettings>
<applicationSettings>
<HelloWorld.Properties.Settings>
<setting name="Setting1" serializeAs="String">
<value>2</value>
</setting>
</HelloWorld.Properties.Settings>
</applicationSettings>
</configuration>
지금부터 시작하는 내용은 실질적인 프로그램을 하면서 많이 접하게되므로 자세히 알아본다.
※ 아래 내용을 설명하기 전에 xaml파일과 xaml.cs파일은 연결에 주의를 해야하며, 연결된 후 속성이 동일하지 않으면 오류를 발생하게되고 뿐만아니라 편집 순서에 따라 소스를 읽어들이지 못하는 경우도 발생하니 주의해야 한다. 프로그램 중에 xaml파일을 수정하였다면 연결된 cs파일도 같이 검토해봐야 애러가 발생하지 않는다.
▷ App.xaml파일과 App.xaml.cs파일은 밀접하게 연결되어 있으므로 두 파일을 열어보면 아래쪽 소스코드와 같다.
App.xaml 파일의 태그인 <Application>, <Application.Resource> 이 존재한다. 이중 중요한 <Application>태그에 대하여 알아보자.
<Application> 태그는 x:Class, xmlns, xmlns:x, xmlns:local, StartupUri의 속성을 가진다.
x:Class 속성은 xaml파일과 cs파일을 연결하는 역할을 한다. x:Class 속성에 할당되는 값은 "namespace.classname"으로 구성된다. App.xaml.cs파일 9번째줄에서 namespace의 이름이 HelloWorld로 되어 있고, 12번째줄에서 classname이름이 App로 되어 있다. namespace와 classname이 cs파일의 내용과 다르면 오류를 발생한다.
xmlns 속성은 xaml에서 참조할 XAML Name Space로 WPF에 대한 XAML을 선언해 놓은 경로다.
xmlns:x 속성은 xmlns와 연결된 calss를 선언해 놓은 경로다. xmlns와 xmlns:x는 마이크로소프트에서 정의한 내용으로 그대로 사용하면된다.
xmlns:local 속성은 CLR(Common Language Runtime) 네임스페이스로 어셈블리에서 사용자가 외부로 어셈블리를 외부로 노츨할때 사용하는 이름이다.
StartupUri 속성은 App.xaml에서 사용자 프로그램의 첫 화면을 어떤것으로 지정할 것인가를 나타낸다. App.xaml파일 5번째줄에서 MainWindow.xaml을 확인할 수 있다.
App.xaml
<Application x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
▷ App.xaml.cs 파일을 열어 보면 아래와 같다. 정말 아무 내용이 없는것 같지만 Solution Explorer에서 App Class를 클릭해 보면 아래 소스 내용을 추가로 확인할 수 있다. 두 소스 모두 System.Windows.Application Class를 파생 받아서 App Class 가 생성됨을 알수 있다.
App Class에서 가지고 있는 함수를 살펴보면 InitializeComponent, Main 두가지를 볼수 있다. 자세히 살펴보면 Main()함수에서 InitializeComponent() 함수를 호출하고 있음을 볼 수 있다.
모든 프로그램의 시작점은 Main()함수이며, 이것이 C#이 C언어로 부터 파생되었다는 중요한 증거이기도 하다.
System.STAThreadAttribute()속성은 COM Threaded Model에서 사용하는 속성으로 선언하면 STA(Single Threaded Apartment)이고 선언하지 않으면 MTA(Multithreaded apartment)가 된다.
App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace HelloWorld
{
/// <summary>/// Interaction logic for App.xaml/// </summary>public partial classApp : Application
{
}
}
#pragma checksum "..\..\App.xaml""{8829d00f-11b8-4213-878b-770e8597ac16}""9BE00F2473F02C6D0478FA659F3B8567D2550502AE470C32DD3F848F14393E93"//------------------------------------------------------------------------------// <auto-generated>// This code was generated by a tool.// Runtime Version:4.0.30319.42000//// Changes to this file may cause incorrect behavior and will be lost if// the code is regenerated.// </auto-generated>//------------------------------------------------------------------------------using HelloWorld;
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 HelloWorld {
/// <summary>/// App/// </summary>public partial classApp : System.Windows.Application {
/// <summary>/// InitializeComponent/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
publicvoidInitializeComponent(){
#line 5 "..\..\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")]
publicstaticvoidMain(){
HelloWorld.App app = new HelloWorld.App();
app.InitializeComponent();
app.Run();
}
}
}
▷ MainWindow.xaml파일을 열어보면 아래 내용과 같다. App.xaml가 다른내용은 Window Class에서 파생받은 MainWindow Class를 사용하는것이다.
Window 태그에서 추가된 xmlns:d, xmlns:mc, mc:Ignorable, Title, Height, Width 속성을 볼 수 있다.
MainWindow.xaml
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="40">
Hello World!
</TextBlock>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace HelloWorld
{
/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial classMainWindow : Window
{
publicMainWindow(){
InitializeComponent();
}
}
}
#pragma checksum "..\..\MainWindow.xaml""{8829d00f-11b8-4213-878b-770e8597ac16}""3D2337E78F3C9FEBAB574356F1AD708C8150EAC1C56934D06DB191EB395573CA"//------------------------------------------------------------------------------// <auto-generated>// This code was generated by a tool.// Runtime Version:4.0.30319.42000//// Changes to this file may cause incorrect behavior and will be lost if// the code is regenerated.// </auto-generated>//------------------------------------------------------------------------------using HelloWorld;
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;