I have a traditional form layout with a menu bar at the top and status bar at the bottom. When the user selects a menu item, the space in-between (the form's entire remaining client area) gets replaced with a user control - think of an SDI app that can host multiple types of documents.
If you know of a better way to go about this, please chime in. For now, I'm trying to get it to work in a very simplified version with a ContentControl, but I cannot get it to update the screen when its DataContext is set.
Here's the very simple code for ViewModelA. ViewModelB is identical, except for the Bs.
namespace Dynamic_ContentControl
{
public class ViewModelA: ViewModelBase
{
public ViewModelA()
{
DisplayName = "This is A";
}
}
}
The main window is very simple. It basically declares a property to hold the view model of the hosted control and exposes two commands to assign view models A or B.
namespace Dynamic_ContentControl
{
public class MainViewModel: ViewModelBase
{
private ViewModelBase clientContent = null;
public ICommand ShowA { get; private set; }
public ICommand ShowB { get; private set; }
public ViewModelBase ClientContent {
get
{
return clientContent;
}
private set
{
clientContent = value;
OnPropertyChanged("ClientContent");
}
}
public MainViewModel()
{
ShowA = new RelayCommand((obj) =>
{
ClientContent = new ViewModelA();
});
ShowB = new RelayCommand((obj) =>
{
ClientContent = new ViewModelB();
});
}
}
}
Finally, the XAML declares a ContentControl and sets its ContentTemplate to a DataTemplate called ClientAreaTemplate, whose ContentPresenter points to another DataTemplate, named TextBlockLayout:
<Window x:Class="Dynamic_ContentControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Dynamic_ContentControl"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="TextBlockLayout">
<TextBlock Text="{Binding Path=DisplayName}" />
</DataTemplate>
<DataTemplate x:Key="ButtonLayout">
<Button Content="{Binding Path=DisplayName}" />
</DataTemplate>
<DataTemplate x:Key="CheckBoxLayout">
<CheckBox Content="{Binding Path=DisplayName}" />
</DataTemplate>
<DataTemplate x:Key="ClientAreaTemplate">
<ContentPresenter x:Name="ContentArea" ContentTemplate="{StaticResource ResourceKey=TextBlockLayout}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=DataContext}"
Value="{x:Type vm:ViewModelB}">
<Setter TargetName="ContentArea"
Property="ContentTemplate"
Value="{StaticResource ResourceKey=ButtonLayout}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataContext}"
Value="{x:Type vm:ViewModelB}">
<Setter TargetName="ContentArea"
Property="ContentTemplate"
Value="{StaticResource ResourceKey=CheckBoxLayout}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid>
<Button Content="Show A"
Command="{Binding Path=ShowA}"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="75" />
<Button Content="Show B"
Command="{Binding ShowB}"
HorizontalAlignment="Left"
Margin="90,10,0,0"
VerticalAlignment="Top"
Width="75" />
<Label Content="{Binding Path=ClientContent.DisplayName}"
HorizontalAlignment="Left"
Margin="170,8,0,0"
VerticalAlignment="Top" />
<ContentControl DataContext="{Binding Path=ClientContent}"
Content="{Binding}"
ContentTemplate="{StaticResource ResourceKey=ClientAreaTemplate}"
HorizontalAlignment="Left"
Margin="10,37,0,0"
VerticalAlignment="Top"
Height="198"
Width="211" />
</Grid>
</Window>
Expected behaviour
When the screen opens, I want TextBoxLayout to display. If the user then clicks on one of the two buttons, it should load either a ButtonLayout or CheckBoxLayout, depending on the actual runtime type of the view model that is assigned.
Actual behaviour
The screen opens with the TextBoxLayout loaded, but it never changes to another type as I click the buttons.
I think the problem is the way the DataTrigger tries to compare with the type, but there are no binding messages at all the Output window.