I have a viewmodel with a propety that can be a primitive type:
class VM : VMBase // implements INotifyProperty
{
// can be float, int or bool (System.Single, System.Int32, System.Boolean)
private object _Value;
public object Value {
get{return _Value;}
set{
if(_Value!=value){
_Value=value;
OnPropertyChanged(nameof(Value)); // notify bindings
}
}
}
}
The type of Value
can be float
, int
or bool
. Now I'd like to display a TextBox
if Value
's type is float
or int
and a CheckBox
if it's a bool
. In XAML I try this:
<Grid> <!-- DataContext is VM -->
<Grid.Resources>
<DataTemplate DataType="{x:Type sys:Single}">
<TextBox Width="64" Text="{Binding Path=DataContext.Value, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Int32}">
<TextBox Width="64"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Boolean}">
<CheckBox Width="64"/>
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding Value}" IsTabStop="False"/>
</Grid>
It displays the controls correctly for each type. But I'm unable to use the binding to modify the value of Value
property by typing a new value in its text box. How should I make a two-way binding? Is there a better method to do what I'm trying to do?
As you've correctly spotted you need to specify a Template for each view of the data, the part that you are missing is that you can then use a DataTemplateSelector to choose the correct one
eg
code
public class CustomTemplateSelector : DataTemplateSelector
{
public DataTemplate Template1{get;set;}
public DataTemplate Template2{get;set;}
public DataTemplate Template3{get;set;}
public DataTemplate Template4{get;set;}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if(item is float)
return Template1;
else if(item is int)
return Template1;
else if(item is string)
return Template2;
else if(item is bool)
return Template3;
//etc
else
return Template4;
}
}
xaml
<local:CustomeDataTemplate>
<local:CustomeDataTemplate.Template1>
<DataTemplate>
<TextBox Text="{Binding }" />
</DataTemplate>
</local:CustomeDataTemplate.Template1>
<local:CustomeDataTemplate.Template2>
<DataTemplate>
<CheckBox IsChecked="{Binding }"/>
</DataTemplate>
</local:CustomeDataTemplate.Template2>
</local:CustomeDataTemplate>
remember to bind the content of the template to the data