Dynamically display a control depending on bound property using WPF
You could do a combination of style with setters and DataTemplates. You basically have the start for it in your code, although I don't think ContentPresenter
is the right control to style, since it does not have a template.
Create a style like this:
<Style x:Key="TypedValueHelper" TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataType}" Value="Char">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding Path=.}" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataType}" Value="Integer">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Slider Maximum="100" Minimum="0" Value="{Binding Path=.}"
Orientation="Horizontal" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Then use the style in the ContentControl
:
<ContentControl Content="{Binding MyValue}"
Style="{StaticResource TypedValueHelper}">
While the Style
solution might work, the proper way to implement the dynamic content behavior would be to use DataTemplates as Sdry suggested. However, you would be using an enumeration to determine which DataTemplate to use, which essentially means you want to map a single type to multiple DataTemplates. This problem is solved by the DataTemplateSelector
class, the following description is straight from MSDN:
"Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object."
You dynamic content should be hosted by a ContentControl
like this:
<ContentControl Content="{Binding Path=ReferenceToYourViewModel}" ContentTemplateSelector="{DynamicResource MyTemplateSelector}"/>
The implementation of MyTemplateSelector
:
public class MyTemplateSelector: DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement elem = container as FrameworkElement;
if(elem == null)
{
return null;
}
if (item == null || !(item is YourViewModel))
{
throw new ApplicationException();
}
if ((item as YourViewModel).DataType == DataType.Char)
{
return elem.FindResource("CharDataTemplate") as DataTemplate;
}
if ((item as YourViewModel).DataType == DataType.Date)
{
return elem.FindResource("DateDataTemplate") as DataTemplate;
}
if ((item as YourViewModel).DataType == DataType.Integer)
{
return elem.FindResource("IntegerDataTemplate") as DataTemplate;
}
throw new ApplicationException();
}
}
Then as you would expect, here are the DataTemplates to pick from:
<DataTemplate x:Key="CharDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate>
<DataTemplate x:Key="DateDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate>
<DataTemplate x:Key="IntegerDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate>
With this, the appropriate DataTemplate
will be chosen based on the DataType
Property of your View Model. Which in my opinion is a lot cleaner than using Visibility
or Styles.