Каким образом можно в главном окне подсовывать нужный UserControl без изменения параметра видимости. К примеру есть окно при запуске отображается FirstUserControl потом при каком нибудь событие (например нажатие на кнопку) FirstUcerControl отрабатывает (закрывается), и отображается новый SecondUserControl.
Asked
Active
Viewed 1,392 times
0
KJfe
- 123
1 Answers
2
Для этого используется DataTemplateSelector. Я покажу небольшой пример.
Допустим, у меня есть VM-классы CarVm и UserVm, которые я хочу отображать в одном окне, я набросал такую простую MainVm:
class MainVm : Vm
{
object innerVm;
public object InnerVm
{
get => innerVm;
set => Set(ref innerVm, value, nameof(InnerVm));
}
public DelegateCommand ChangeCommand { get; }
public MainVm()
{
ChangeCommand = new DelegateCommand(_ => InnerVm = (InnerVm is UserVm) ? (object)new CarVm() : (object)new UserVm());
}
}
Тут всё просто, по команде у нас меняется свойство InnerVm, причем оно каждый раз будет менять тип.
Займемся разметкой, я в Grid добавлю ContentPresenter для отображения InnerVm и кнопку для вызова команды:
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentPresenter Content="{Binding InnerVm}">
</ContentPresenter>
<Button Grid.Row="1" Content="Change"
HorizontalAlignment="Center"
Command="{Binding ChangeCommand}"/>
</Grid>
Теперь нам для каждого отображаемого типа необходимо реализовать DataTemplate-разметку, я добавлю ее в ресурсы ContentPresenter:
<ContentPresenter.Resources>
<DataTemplate x:Key="UserTemplate">
<StackPanel d:DataContext="{d:DesignInstance Type=c:UserVm}">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Age}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CarTemplate">
<StackPanel d:DataContext="{d:DesignInstance Type=c:CarVm}">
<TextBlock Text="{Binding Model}"/>
<TextBlock Text="{Binding MaxSpeed}"/>
</StackPanel>
</DataTemplate>
</ContentPresenter.Resources>
Теперь пишем класс-наследник DataTemplateSelector:
class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var fe = (FrameworkElement)container;
if (item is UserVm) return fe.FindResource("UserTemplate") as DataTemplate;
if (item is CarVm) return fe.FindResource("CarTemplate") as DataTemplate;
return null;
}
}
Создаем экземпляр этого класса в ресурсах Grid:
<Grid.Resources>
<c:MyTemplateSelector x:Key="MyTemplateSelector"/>
</Grid.Resources>
И подключаем его к нашему ContentPresenter: ContentTemplateSelector="{StaticResource MyTemplateSelector}"
Готово!
Андрей NOP
- 28,687
-
а чем этот подход лучше, чем просто выкинуть старый контрол и засунуть новый в ContentControl? – tym32167 Jan 23 '18 at 09:00
-
Не уверен, что понимаю зачем в данном случае использовать селектор - на мой взгляд проще установить
DataType– Jan 23 '18 at 09:00 -
-
@FoggyFinder, хорошо знать несколько способов, в зависимости от ситуации можно использовать тот или иной подход – Андрей NOP Jan 23 '18 at 09:39
-
-
2@tym32167, селектором удобно пользоваться, когда на один и тот же тип могут выдаваться разные шаблоны, например, в зависимости от каких-то других обстоятельств. Или наоборот, один и тот же шаблон на разные типы. В разметке такое не всегда возможно, да и громоздко обычно выходит. – Андрей NOP Jan 23 '18 at 10:04
-
@tym32167 В случае ContentPresenter по идее не будет нарушаться MVVM. Если просто менять UserControl в Content, то это значит, что VM будет напрямую управлять View, что несколько противоречит паттерну. В Presenter твоя VM будет управлять только другим VM, а вот View будет сама выбирать нужный View в зависимости от типа VM – Иван Jan 23 '18 at 11:03
-
2@John MVVM может быть нарушен, если менять тем способом, что вы описали. Но это не единственный способ. Для таких вещей делают всякие контент-хелперы, регион-менеджеры, вью-адаптеры. Например, RegionManager – tym32167 Jan 23 '18 at 11:23
-
-

без изменения параметра видимости- т.е. смена изменениемVisibilityвас не устраивает? – Андрей NOP Jan 23 '18 at 08:11SecondUserControlбудет храниться в памяти и т.д. как только отработаетFirstUserControlего параметры надо сразу же почистить ну или что то в этом вроде. – KJfe Jan 23 '18 at 08:15ContentControl. В его свойствеContentвы можете выставлять нужный вамUserControlв любой момент времени. В MVVM вы просто создаете свойство типаobject, к которому будете байндить свойствоContent. – Иван Jan 23 '18 at 08:21