I've got a property which is a database data type (char
, DateTime
, int
, float
etc...) and I want to change the control used to enter a value of the selected type. So for text values I want a TextBox
and for date values I want a DatePicker
.
One way I thought about doing it was to have one of each control on my form and set their Visibility
using an appropriate IValueConverter
implementation. I know this will work, but it would create a lot of code and doesn't feel very nice.
The other way I thought was to use a ContentPresenter
and set its content with a Style
and DataTriggers
but I can't get it to work.
<Style x:Key="TypedValueHelper" TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataType}" Value="Char">
<Setter Property="Content" Value="???"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataType}" Value="Date">
<Setter Property="Content" Value="???"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataType}" Value="Integer">
<Setter Property="Content" Value="???"/>
</DataTrigger>
</Style.Triggers>
</Style>
If anyone can fill in my "???" or offer a better solution please do.
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.
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