I am trying to implement the MVVM design patern for mt WPF application. In order to connect the view to the viewmodels, I use a ResourceDictionary
(used in Application.Resources
), that looks like
<DataTemplate DataType={x:Type viewmodel:SampleViewModel}>
<view:SampleView1 />
</DataTemplate>
The view models are then simply put into content presenters to display them.
Now, when the user presses a button, I'd like to display SampleViewModel
using a different view. How do I change the data template used for SampleViewModel
?
Less words more code.
As far as you said, you have the class SampleViewModel
. I added the property Title
for demonstration and ViewType
for identifying the correct view:
public enum ItemViewType { View1, View2 };
public class SampleViewModel
{
public string Title { get; set; }
public ItemViewType ViewType { get; set; }
}
The DataTemplateSelector
for two views depending on the ViewType
property:
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 code:
<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>
The main part is in the class MainViewModel
where I've put the logic for switching views:
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");
}
}
}
The SwitchViewCommand
can be any type of command, I use the command from the mvvmlight library.
Inside the handler of the command I change the type of viewmodel and update the property ItemViewModel
in a tricky way because a ContentControl
refreshes a view only if to change the Content property, and this property will not be changed unless you set a reference to different object.
I mean, even the code this.ItemViewModel = this.itemViewModel
will not change the view.
It's strange, but the workaround doesn't require much work.
You can achieve this in many different ways depends upon the architecture you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With