ContentControl DataTemplate 绑定到原始类型
ContentControl DataTemplate binding to primitive types
我有一个视图模型,其属性可以是原始类型:
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
}
}
}
}
Value
的类型可以是float
、int
或bool
。现在我想显示 TextBox
如果 Value
的类型是 float
或 int
和 CheckBox
如果它是 bool
。在 XAML 我试试这个:
<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>
它能正确显示每种类型的控件。但是我无法使用绑定通过在其文本框中键入新值来修改 Value
属性 的值。我应该如何进行双向绑定?有没有更好的方法来做我想做的事情?
正如您正确发现的那样,您需要为每个数据视图指定一个模板,您缺少的部分是您可以使用 DataTemplateSelector 选择正确的模板
例如
代码
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>
记得绑定模板内容到数据
我有一个视图模型,其属性可以是原始类型:
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
}
}
}
}
Value
的类型可以是float
、int
或bool
。现在我想显示 TextBox
如果 Value
的类型是 float
或 int
和 CheckBox
如果它是 bool
。在 XAML 我试试这个:
<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>
它能正确显示每种类型的控件。但是我无法使用绑定通过在其文本框中键入新值来修改 Value
属性 的值。我应该如何进行双向绑定?有没有更好的方法来做我想做的事情?
正如您正确发现的那样,您需要为每个数据视图指定一个模板,您缺少的部分是您可以使用 DataTemplateSelector 选择正确的模板
例如
代码
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>
记得绑定模板内容到数据