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的类型可以是floatintbool。现在我想显示 TextBox 如果 Value 的类型是 floatintCheckBox 如果它是 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>

记得绑定模板内容到数据