앞의 글 ( File-based App으로 프로토타이핑하는 Windows Forms ) 에 이어서 WPF도 소개합니다. ![]()
#:sdk Microsoft.NET.Sdk
#:property OutputType=WinExe
#:property TargetFramework=net10.0-windows
#:property PublishAot=False
#:property UseWPF=True
#:property UseWindowsForms=False
#:package CommunityToolkit.Mvvm@8.4.0
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
// https://github.com/dotnet/winforms/issues/5071#issuecomment-908789632
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
var countText = new TextBlock
{
FontSize = 24,
Margin = new Thickness(8),
HorizontalAlignment = HorizontalAlignment.Center,
};
countText.SetBinding(TextBlock.TextProperty, new Binding(nameof(CounterViewModel.Count)));
var incButton = new Button { Content = "Increment (+1)", Margin = new Thickness(8), };
incButton.SetBinding(Button.CommandProperty, new Binding(nameof(CounterViewModel.IncrementCountCommand)));
var decButton = new Button { Content = "Decrement (-1)", Margin = new Thickness(8), };
decButton.SetBinding(Button.CommandProperty, new Binding(nameof(CounterViewModel.DecrementCountCommand)));
var root = new StackPanel { Margin = new Thickness(16) };
root.Children.Add(countText);
root.Children.Add(incButton);
root.Children.Add(decButton);
var window = new Window
{
Title = $"Hello, World! - {Thread.CurrentThread.GetApartmentState()}",
Width = 320,
Height = 240,
Content = root,
DataContext = new CounterViewModel(),
WindowStartupLocation = WindowStartupLocation.CenterScreen,
};
var app = new Application
{
ShutdownMode = ShutdownMode.OnMainWindowClose,
};
app.DispatcherUnhandledException += (_, e) =>
{
MessageBox.Show(e.Exception.ToString(), "Unhandled", MessageBoxButton.OK, MessageBoxImage.Error);
e.Handled = true;
};
app.Run(window);
public sealed partial class CounterViewModel : ObservableObject
{
[ObservableProperty]
private int _count = 0;
[RelayCommand]
private void IncrementCount()
=> Count++;
[RelayCommand]
private void DecrementCount()
=> Count--;
}
Windows Forms 사례와 크게 다르지는 않지만, 여기서는 CommunityToolkit.Mvvm을 사용했습니다. 소스 제너레이터가 이 환경에서도 매우 잘 작동할 뿐 아니라, 아래 그림처럼 인텔리센스에도 제대로 반영이 되고, 만들어진 소스 코드도 확인할 수 있습니다.
좀 더 테스트해봐야겠지만, Directory.Build.Props 파일을 같은 위치에 넣어둔다면 XAML 파일도 리소스로 포함시키게 지정할 수 있을 것으로 보입니다. 이것도 후속으로 테스트해보고 공유드려보겠습니다. 있습니다. 그러나 예상했던 대로 현재 FBA 문법의 한계와 마주하는 부분이라 다소 아쉽지만, 기술적으로는 가능하다는 것에 의미를 두어도 충분할 것 같습니다. ![]()
(하단 글 참조)



