I have a re-usable usercontrol with a viewmodel behind it. I'm trying to switch between different views of the same data. Currently trying to use a Mode property on the VM to accomplish this.
I've created a DataTemplateSelector like so:
&开发者_StackOverflow社区lt;UserControl x:Class="MyUserControl">
<UserControl.Resources>
<DataTemplate x:Key="ColumnTemplate">
<StackPanel>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding Address}"></Label>
<Label Text="{Binding Occupation}"></Label>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AvatarTemplate">
<StackPanel>
<Image Source="{Binding ProfilePicture}"></Image>
<Label Text="{Binding Name}"></Label>
</StackPanel>
</DataTemplate>
<local:DisplayTemplateSelector ColumnTemplate="{StaticResource ColumnTemplate}" AvatarTemplate="{StaticResource AvatarTemplate}" x:Key="displayTemplateSelector" />
</UserControl.Resources>
<Grid>
<ContentControl Name="cpDisplay" Content="{Binding}" ContentTemplateSelector="{StaticResource displayTemplateSelector}" />
</Grid>
</UserControl>
With the class:
class DisplayTemplateSelector : DataTemplateSelector
{
public DataTemplate ColumnTemplate {get;set;}
public DataTemplate AvatarTemplate {get;set;}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
MainViewModel vm = (MainViewModel)item;
switch (vm.Mode)
{
case MainViewModel.DisplayMode.Column:
return ColumnTemplate;
case MainViewModel.DisplayMode.Avatar:
return AvatarTemplate;
default:
return AvatarTemplate;
}
}
}
This usercontrol sits in MyWindow:
<Grid>
<controls:MyUserControl x:Name="MyUserControl" DataContext="{Binding}" Margin="0"/>
</Grid>
Which is instantiated with my viewmodel:
MyWindow w = new MyWindow(_vm);
w.Show();
The problem I have is that item
is null during MainViewModel vm = (MainViewModel)item
. It's like I'm trying to set the datatemplate based on data, before the data is bound?
Is there anyway to choose the desired datatemplate not based on the dataobject - but as a property or similar on the usercontrol?
There are many ways, but here are a couple:
<!-- assumes you have a data template selector implementation available as resource MyContentSelector -->
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplateSelector="{StaticResource MyContentSelector}"/>
or:
<!-- assumes you have appropriate boolean properties on your VM -->
<Grid>
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplate="{StaticResource column}" Visibility="{Binding IsColumnVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplate="{StaticResource avatar}" Visibility="{Binding IsAvatarVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</Grid>
See DataTemplateSelector Class
DataTemplateSelector
Ok, finally got this to work how I needed by using a property on the usercontrol and some code behind:
public enum DisplayMode
{
Column,
Avatar
}
public DisplayMode Mode { get; set; }
public MyUserControl()
{
InitializeComponent();
Mode = DisplayMode.Avatar;
}
private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
{
switch (Mode)
{
case DisplayMode.Column:
cpDisplay.ContentTemplate = (DataTemplate)this.Resources["ColumnTemplate"];
cpDisplay.ApplyTemplate();
break;
case DisplayMode.Avatar:
cpDisplay.ContentTemplate = (DataTemplate)this.Resources["AvatarTemplate"];
cpDisplay.ApplyTemplate();
break;
}
}
I removed the DataTemplateSelector code and simply defined the datatemplates and used:
<ContentPresenter Name="cpDisplay" Content="{Binding}" />
精彩评论