Изменение вида для модели представления
Я пытаюсь реализовать шаблон дизайна MVVM для приложения mt WPF. Чтобы подключить вид к моделям вида, я использую ResourceDictionary
(используется в Application.Resources
), это выглядит
<DataTemplate DataType={x:Type viewmodel:SampleViewModel}>
<view:SampleView1 />
</DataTemplate>
Модели представлений затем просто помещаются в предъявители контента для их отображения.
Теперь, когда пользователь нажимает кнопку, я хотел бы отобразить SampleViewModel
используя другой взгляд. Как изменить шаблон данных, используемый для SampleViewModel
?
3 ответа
Меньше слов, больше кода. Насколько вы сказали, у вас есть класс SampleViewModel
, Я добавил недвижимость Title
для демонстрации и ViewType
для определения правильного вида:
public enum ItemViewType { View1, View2 };
public class SampleViewModel
{
public string Title { get; set; }
public ItemViewType ViewType { get; set; }
}
DataTemplateSelector
для двух просмотров в зависимости от ViewType
имущество:
class ItemViewTemplateSelector : DataTemplateSelector
{
public DataTemplate View1Template { get; set; }
public DataTemplate View2Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var vm = item as SampleViewModel;
if (vm == null)
return null;
switch (vm.ViewType)
{
case ItemViewType.View1:
return View1Template;
case ItemViewType.View2:
return View2Template;
}
return null;
}
}
XAML код:
<Window.Resources>
<DataTemplate x:Key="view1Template">
<TextBlock Text="{Binding Title}" Foreground="Red"/>
</DataTemplate>
<DataTemplate x:Key="view2Template">
<TextBox Text="{Binding Title}" />
</DataTemplate>
<local:ItemViewTemplateSelector x:Key="viewTemplateSelector"
View1Template="{StaticResource view1Template}"
View2Template="{StaticResource view2Template}"/>
</Window.Resources>
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<StackPanel>
<Button Content="ChangeView" HorizontalAlignment="Center" Command="{Binding SwitchViewCommand}"/>
<ContentControl Content="{Binding ItemViewModel}" ContentTemplateSelector="{StaticResource viewTemplateSelector}"/>
</StackPanel>
Основная часть в классе MainViewModel
где я положил логику для переключения видов:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
this.ItemViewModel = new SampleViewModel { Title = "Some title", ViewType = ItemViewType.View1 };
this.SwitchViewCommand = new RelayCommand(() =>
{
this.ItemViewModel.ViewType = this.ItemViewModel.ViewType == ItemViewType.View1
? ItemViewType.View2
: ItemViewType.View1;
//The magic senquence of actions which forces a contentcontrol to change the content template
var copy = this.ItemViewModel;
this.ItemViewModel = null;
this.ItemViewModel = copy;
});
}
public RelayCommand SwitchViewCommand { get; set; }
private SampleViewModel itemViewModel;
public SampleViewModel ItemViewModel
{
get { return itemViewModel; }
set
{
itemViewModel = value;
RaisePropertyChanged("ItemViewModel");
}
}
}
SwitchViewCommand
может быть команда любого типа, я использую команду из библиотеки mvvmlight.
Внутри обработчика команды я меняю тип viewmodel и обновляю свойство ItemViewModel
хитро, потому что ContentControl
обновляет представление, только если изменить свойство Content, и это свойство не будет изменено, если вы не установите ссылку на другой объект.
Я имею в виду, даже код this.ItemViewModel = this.itemViewModel
не изменит вид. Это странно, но обходной путь не требует большой работы.
Вы можете достичь этого разными способами, в зависимости от архитектуры, которую вы хотите.
- Вы можете написать собственный DataTemplateSelector и использовать его в ContentControl.ContentTemplateSelector и выбрать эти два шаблона соответствующим образом
- Если этот шаблон изменения представления происходит во многих разных местах и более частом UX, я бы также рекомендовал переключать эти два представления с помощью DataTemplate.DataTrigger на основе свойства в SampleViewModel [я предполагаю, что у вас может быть отличительное свойство в ViewModel для знаю это состояние]
Вы можете переопределить отображение, разместив аналогичный ресурс ниже в дереве. Поскольку WPF разрешит ресурс путем поиска вверх, такое переопределение заменит существующее сопоставление.