根据绑定对象的数据类型将模板应用于内容控件

Applying template to a contentcontrol based on data type of bound object

我遇到了以下问题:

我需要制作一个自定义的 ContentControl,当它没有聚焦时会有一个默认的 DataTemplate,里面有一个 TextBlock,但是当聚焦时(即通过鼠标或键盘)应该能够根据类型呈现另一个合适的 DataTemplate内容。例如,假设如果 Content 的类型是 String,那么应该显示一个带有 TextBox 的 DataTemplate,如果是 DateTime - 那么一个 DateTimePicker,等等。

我知道有一种方法可以根据 Focused/NotFocused 为 ListBoxItems 提供不同的 DataTemplates,我已经通过应用带有触发器的样式来实现它。但在这种情况下,我被困住了。 我已经尝试过使用 Style,但没有成功。

这是我到目前为止的想法:

Themes/generix.xaml 对于刚从 ContentControl 继承的 Gadget 控件:

<ControlTemplate x:Key="String">
    <Border BorderBrush="Green" BorderThickness="1">
        <TextBlock Text="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></TextBlock>
    </Border>
</ControlTemplate>
<ControlTemplate x:Key="Int32">
    <Border BorderBrush="Blue" BorderThickness="1">
        <TextBlock Text="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></TextBlock>
    </Border>
</ControlTemplate>
<ControlTemplate x:Key="Base">
    <Border BorderBrush="Yellow" BorderThickness="1">
        <TextBlock Text="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></TextBlock>
    </Border>
</ControlTemplate>
<local:DTC x:Key="DataTypeConverter"></local:DTC>
<Style TargetType="{x:Type local:Gadget}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:Gadget}},  Converter={StaticResource DataTypeConverter}}" Value="String}">
            <Setter Property="Template" Value="{StaticResource String}"></Setter>
        </DataTrigger>
        <DataTrigger Binding="{Binding Content,  RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:Gadget}}, Converter={StaticResource DataTypeConverter}}" Value="Int32}">
            <Setter Property="Template" Value="{StaticResource Int32}"></Setter>
        </DataTrigger>
    </Style.Triggers>
    <Setter Property="Padding"
            Value="2" />
    <Setter Property="Template" Value="{StaticResource Base}"> </Setter>
</Style>

Gadget 控件后端只有一个静态构造函数:

static Gadget()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Gadget),
                   new FrameworkPropertyMetadata(typeof(Gadget)));

    }

这是测试类:

public class TestClass
{
    public TestClass(string one, string two)
    {
        One = one;
        Two = two;
        Three = count++;
    }

    static int count = 0;

    public string One { get; set; } = "One1";
    public string Two { get; set; } = "Two2";
    public int Three { get; set; }
}

这是值转换器:

public class DTC : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
      CultureInfo culture)
    {
        return value.GetType();
    }

    public object ConvertBack(object value, Type targetType, object parameter,
      CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这就是我尝试在 ListBox 中使用它的方式

<ListBox Name="lstBox" Margin="10,10,172,40">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <local:Gadget Content="{Binding Path=One}"></local:Gadget>
                    <local:Gadget Content="{Binding Path=Two}"></local:Gadget>
                    <local:Gadget Content="{Binding Path=Three}"></local:Gadget>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

我到处搜索,但要么我没有很好地表达我的问题,要么可能从来没有人需要这个...

对于此事的任何建议,我将不胜感激!

非常感谢!

编辑

为了使 mm8 的建议生效,我将 DTC 对象编辑为 return 类型而不是字符串。上面截断的代码已相应修复。

绑定到 {RelativeSource Self} 的内容 属性 和 return 来自转换器 Convert 方法的实际类型:

<Style TargetType="{x:Type local:Gadget}" xmlns:s="clr-namespace:System;assembly=mscorlib">
    <Setter Property="Padding" Value="2" />
    <Setter Property="Template" Value="{StaticResource Base}"></Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Self}, Converter={StaticResource DataTypeConverter}}" 
                     Value="{x:Type s:String}">
            <Setter Property="Template" Value="{StaticResource String}"></Setter>
        </DataTrigger>
        <DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Self}, Converter={StaticResource DataTypeConverter}}" 
                     Value="{x:Type s:Int32}">
            <Setter Property="Template" Value="{StaticResource Int32}"></Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

public class DTC : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value.GetType();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}