티스토리 뷰
반응형
ContentControl의 Content에는 View를 생성해서 넣을 수 있습니다.
다만, ViewModel에서 View를 생성해서 바인딩하는 방식을 사용하지는 않습니다.
이렇게되면, View가 ViewModel에 종속된 모양이되어서 메모리 누수가 발생할 수 있기 때문입니다.
2가지 방법이 있는데 여기서는 Behavior를 이용하는 방법에 대해서 알아 보도록 하겠습니다.
이 셈플은 PrismStep7 프로젝트에 추가로 작업되었습니다.
1. ContentControlBehavior.cs
/// <summary>
/// 컨텐츠 컨트롤 비헤이비어
/// </summary>
public class ContentControlBehavior : Behavior<ContentControl>
{
protected override void OnAttached()
{
//AssociatedObject에 이벤트를 연결 할 필요가 있으면 여기에
ResolveView();
}
protected override void OnDetaching()
{
//AssociatedObject에 연결했던 이벤트 해제는 여기서
}
public string ViewName
{
get => (string)GetValue(ViewNameProperty);
set => SetValue(ViewNameProperty, value);
}
/// <summary>
/// 뷰이름
/// </summary>
public static readonly DependencyProperty ViewNameProperty =
DependencyProperty.Register("ViewName", typeof(string), typeof(ContentControlBehavior), new PropertyMetadata(null));
public Type ViewType
{
get => (Type)GetValue(ViewTypeProperty);
set => SetValue(ViewTypeProperty, value);
}
/// <summary>
/// 뷰유형
/// </summary>
public static readonly DependencyProperty ViewTypeProperty =
DependencyProperty.Register("ViewType", typeof(Type), typeof(ContentControlBehavior), new PropertyMetadata(null));
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
switch (e.Property.Name)
{
case nameof(ViewName):
case nameof(ViewType):
//ViewName이나 ViewType이 변경되면 ResolveView()를 실행합니다.
ResolveView();
break;
}
base.OnPropertyChanged(e);
}
private void ResolveView()
{
//AssociatedObject 연결되지 않았으면 종료합니다.
if (AssociatedObject == null)
{
return;
}
//ViewName이 있을 때
if (string.IsNullOrEmpty(ViewName) == false)
{
Type type = Type.GetType(ViewName);
if (type != null)
{
object view = App.ContainerProvider.Resolve(type);
AssociatedObject.Content = view;
}
}
//ViewType이 있을 때
else if (ViewType != null)
{
object view = App.ContainerProvider.Resolve(ViewType);
AssociatedObject.Content = view;
}
//todo : AssociatedObject.Content에 이미 연결된 View가 있을 경우 반드시 뷰를 제거하고 입력해야함
}
}
- Behavior는 ContentControl에 붙어있는 형태이기 때문에 ViewModel과는 연결관계가 없이 사용할 수 있습니다.
- ViewModel과 Binding이 되는 프로퍼티는 ViewName과 ViewType입니다.
- 둘 중 1개의 한개라도 값이 변경되거나, 혹은 OnAttached()가 실행될 때 ResolveView()를 실행해서 View를 생성하고, ContentControl.Content 속성어 넣게 됩니다.
- ViewName에는 AssemblyQualifiedName을 이용하거나 문자열을 조합해서 사용할 수 있습니다.
- PrismStep7.Views.InjectionView, PrismStep7, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- ContentControl.Content에 생성된 View를 넣기 전에 이미 들어가있던 View 인스턴스가 있다면 제거를 하고 넣어주는 것이 좋습니다.
- Behavior는 생성자 주입을 할 수 없기 때문에, App.xaml.cs에 ContainerProvider라는 static 프로퍼티를 추가했습니다.
App.xaml.cs에 ContainerProvider를 사용하는 방법 말고 다른 방법도 있는데, 나중에 기회가되면 올리도록 하겠습니다.
2. App.xaml.cs
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
private static IContainerProvider _containerProvider;
/// <summary>
/// 컨테이너 프로바이더 - 생성자 인젝션 할 수 없는 환경에서 사용하기 위해 추가
/// </summary>
public static IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
_containerProvider = Container;
//AppContext 싱글톤으로 등록
_ = containerRegistry.RegisterSingleton<IAppContext, AppContext>();
//Region Navigation할 화면 등록
containerRegistry.RegisterForNavigation(typeof(Login), nameof(Login));
containerRegistry.RegisterForNavigation(typeof(Home), nameof(Home));
}
}
3. Home.xaml
<!-- ContentControl에 View Injection -->
<Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ContentControl>
<b:Interaction.Behaviors>
<behaviors:ContentControlBehavior ViewName="{Binding ViewName}" ViewType="{Binding ViewType}" />
</b:Interaction.Behaviors>
</ContentControl>
<ContentControl Grid.Row="1" />
</Grid>
- Behavior를 사용하기 위해서는 Microsoft Behavior nuget package가 설치되어 있어야하고, xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 네임스페이스가 필요합니다.
- ViewName과 ViewType 프로퍼티가 ViewModel의 ViewName, ViewType 프로퍼티와 바인딩되어있는 것을 알 수 있습니다.
4. HomeViewModel.cs
/// <summary>
/// BehaviorCommand에 연결된 메서드
/// </summary>
/// <param name="para"></param>
private void OnBehavior(string para)
{
switch (para)
{
case "Name":
//어셈블리 이름만 주면 인젝션 시킬 수 있기 때문에, 참조를 추가하지 않아도 생성 시킬 수 있음
ViewName = typeof(InjectionView).AssemblyQualifiedName;
break;
case "Type":
//생성할 Type을 반환해야해서 참조가 필요
ViewType = typeof(InjectionView);
break;
}
}
5. 소스
kaki104/WpfTest at PrismStep7/add-contentcontrol-behavior (github.com)
이 셈플은 PrismStep7 프로젝트에 추가로 작업되었습니다.
반응형
'WPF .NET' 카테고리의 다른 글
Kiosk 만들기 - Part4 (2) | 2023.10.23 |
---|---|
Kiosk 만들기 - Part3 (0) | 2023.10.20 |
Kiosk 만들기 - Part2 (0) | 2023.10.18 |
Kiosk 만들기 - Part1 (0) | 2023.10.16 |
Kiosk 만들기 - Part0 (0) | 2023.10.13 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- visual studio 2019
- #MVVM
- WPF
- Cross-platform
- PRISM
- Behavior
- MVVM
- XAML
- #prism
- .net
- C#
- IOT
- Bot Framework
- Microsoft
- dotNETconf
- Build 2016
- UWP
- kiosk
- uno-platform
- ComboBox
- #uwp
- LINQ
- .net 5.0
- ef core
- #Windows Template Studio
- windows 11
- Always Encrypted
- Windows 10
- Visual Studio 2022
- uno platform
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함