티스토리 뷰
2022.11.30 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part6 - TabControl Region Navigation
2022.11.18 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part4 - Register Types
2022.11.15 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part3 - DelegateCommand
2022.10.28 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part2 - 프로젝트 구성 살펴 보기
2022.10.27 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part1
Prism을 사용하는 프로젝트와 이전에 Mvvm Toolkit을 이용해서 생성했던 CustomControlSample 프로젝트와 비교를 하도록 하겠습니다.
1. App.Xaml
CustomControlSample - App.xaml
<Application
x:Class="CustomControlSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlSample">
<Application.Resources />
</Application>
PrismStep1 - App.xaml
PrismApplication은 Application을 상속받은 녀석으로 내부에서 여러가지 일들을 처리하고 있습니다.
<prism:PrismApplication x:Class="PrismStep1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PrismStep1"
xmlns:prism="http://prismlibrary.com/" >
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
2. App.xaml.cs
CustomControlSample - App.xaml.cs
- App 생성자에서 ConfigureServices를 호출해서, 앱에서 사용할 Type을 등록합니다.
- OnStartup 메서드에서 MainWindow를 컨테이너에서 인스턴스해서 가져오고 화면에 출력합니다.
namespace CustomControlSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
Services = ConfigureServices();
//this.InitializeComponent();
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainWindow = Services.GetService<MainWindow>();
if(mainWindow != null)
{
mainWindow.Show();
}
else
{
Shutdown();
}
}
/// <summary>
/// Gets the current <see cref="App"/> instance in use
/// </summary>
public new static App Current => (App)Application.Current;
/// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary>
public IServiceProvider Services { get; }
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton(typeof(MainWindow));
services.AddSingleton(typeof(MainWindowViewModel));
services.AddTransient(typeof(UserConsent));
services.AddTransient(typeof(UserConsentViewModel));
services.AddTransient(typeof(CustomUserConsent));
return services.BuildServiceProvider();
}
}
}
PrismStep1 - App.xaml.cs
- 여러개의 인스턴스를 생성하는 Type은 containerRegistry에 등록할 필요가 없습니다. 아래 코드에서 MainWindow를 등록하지 않은 이유는 호출 할 때마다 새로운 MainWindow가 생성되서 반환되는 기본 유형이기 때문입니다.
- CreateShell() 메서드가 거의 OnStartup 메서드와 유사한 기능을 한다고 보시면 될 것 같습니다.
namespace PrismStep1
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}
위의 코드에 간단하게 몇가지 테스트 코드를 추가하겠습니다.
protected override Window CreateShell()
{
var win1 = Container.Resolve<MainWindow>();
var win2 = Container.Resolve<MainWindow>();
if(win1.Equals(win2))
{
Debug.WriteLine("Equals");
}
else
{
Debug.WriteLine("Not Equals");
}
return Container.Resolve<MainWindow>();
}
win1과 win2는 서로 다른 객체이고 return Container.Resolve<MainWindow>()를 통해서 반환되는 MainWindow도 새로운 객체입니다.
그렇다면, 단 1개의 MainWindow만 생성하고 사용하려면 어떻게 해야할까요?
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<MainWindow>();
}
containerRegistry를 이용해서 MainWindow는 Singleton 객체만을 사용한다고 선언해 주면 됩니다.
PrismStep1 프로젝트를 다시 실행하면, Equals라는 문자열을 출력합니다.
이 부분을 CustomControlSample의 ConfigureServices의 내용들과 비교를 하면 아래와 같습니다.
//싱글톤으로 사용하겠다고 등록
services.AddSingleton(typeof(MainWindow));
//여러개의 객체를 생성해서 반환하기 위해 등록
services.AddTransient(typeof(UserConsent));
3. MainWindow.xaml
CustomControlSample - MainWindow.xaml
<Window
x:Class="CustomControlSample.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:local="clr-namespace:CustomControlSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources />
<Grid>
//컨텐츠 영역
</Grid>
</Window>
PrismStep1 - MainWindow.xaml
- prism:ViewModelLocator.AutoWireViewModel="True" : 뷰모델 자동연결 기능을 사용한다는 것입니다.
- prism:RegionManager.RegionName="ContentRegion" : 프리즘에는 Region이라는 기능이 있는데, ContentControl의 Content 영역을 RegionName으로 선언해 놓으면, 그 곳의 컨텐츠를 RegionNavigate를 이용해서 변경할 수 있습니다.
<Window x:Class="PrismStep1.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525" >
<Grid>
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</Grid>
</Window>
4. MainWindowViewModel을 연결하는 방식의 차이점
CustomControlSample - MainWindow.xaml.cs
- MainWindow를 Resolve할 때 MainWindow(MainWindowViewModel viewModel) 생성자를 통해서 주입(Injection)되고, 그 ViewModel을 DataContext에 넣어주는 구조입니다.
- 각 화면마다 연결할 ViewModel을 수동으로 연결해야 합니다.
namespace CustomControlSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public MainWindow(MainWindowViewModel viewModel) : this()
{
ViewModel = viewModel;
}
public MainWindowViewModel ViewModel
{
//프로젝트 속성이 null 허용이 아니라 이렇게 처리했습니다
get => (MainWindowViewModel)DataContext;
set => DataContext = value;
}
}
}
PrismStep1 - MainWindow.xaml.cs
코드 비하인드에는 코드가 없습니다.
namespace PrismStep1.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
- 뷰와 뷰모델을 연결하는 방식은 클래스 이름을 통해서 강제로 연결해주는 방식입니다.
- 기본적으로 Views 폴더에 들어가있는 뷰 이름뒤에 ViewModels 폴더에 뷰모델이 있고, 뷰이름 + ViewModel로 구성되는 것으로 설정되어 있습니다.
- 그래서 Views/MainWindow.xaml 의 뷰모델은 ViewModels/MainWindowViewModel.cs를 사용한다고 정의 되어 있어서, 새로운 뷰를 만들고, 뷰모델을 만들 때 폴더 위치와 이름만 맞추면 자동으로 연결됩니다.
5. 프리즘에서 뷰와 뷰모델 이름 연결 방법을 변경하려면?
App.xaml.cs에 ConfigureViewModelLocator 메소드를 override해서 변경할 수 있습니다.
아래 예제는 기존 Views, ViewModels 폴더에 추가로 Controls와 ControlViewModel도 추가할려고 만들었습니다.
이 코드는 소스에 포함하지 않습니다.
/// <summary>
/// 뷰모델 로케이터 이름 설정
/// </summary>
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
Prism.Mvvm.ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
string viewName = viewType.FullName;
if (viewName == null)
{
return null;
}
if (viewName.EndsWith("View"))
{
viewName = viewName.Substring(0, viewName.Length - 4);
}
viewName = viewName.Replace(".Views.", ".ViewModels.");
//viewName = viewName.Replace(".Controls.", ".ControlViewModels.");
string viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
string viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
6. 소스
WpfTest/PrismStep1 at master · kaki104/WpfTest (github.com)
'WPF .NET' 카테고리의 다른 글
Prism Library를 사용하는 개발자를 위한 안내 Part4 - Register Types (1) | 2022.11.18 |
---|---|
Prism Library를 사용하는 개발자를 위한 안내 Part3 - DelegateCommand (0) | 2022.11.15 |
Prism Library를 사용하는 개발자를 위한 안내 Part1 (0) | 2022.10.27 |
사용자 정의 컨트롤 만들기 Custom XAML Control - part2 (0) | 2022.10.13 |
사용자 정의 컨트롤 만들기 Custom XAML Control - part1 (0) | 2022.10.06 |
- Total
- Today
- Yesterday
- #uwp
- XAML
- uno platform
- LINQ
- Cross-platform
- MVVM
- Behavior
- uno-platform
- dotNETconf
- Windows 10
- visual studio 2019
- Always Encrypted
- Visual Studio 2022
- Microsoft
- Build 2016
- PRISM
- ComboBox
- #prism
- windows 11
- C#
- kiosk
- .net 5.0
- IOT
- .net
- WPF
- Bot Framework
- UWP
- #MVVM
- #Windows Template Studio
- ef core
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |