基于对象类型的 WPF 触发器

Posted

技术标签:

【中文标题】基于对象类型的 WPF 触发器【英文标题】:WPF Trigger based on Object Type 【发布时间】:2010-12-11 18:15:47 【问题描述】:

有没有办法比较触发器的对象类型?

<DataTrigger Binding="Binding SelectedItem" Value="SelectedItem's Type">
</DataTrigger>

背景:我有一个工具栏,我想根据当前为所选项目对象设置的子类隐藏按钮。

谢谢

【问题讨论】:

【参考方案1】:

为什么不直接使用一个转换器,它接受一个对象并返回一个对象类型的字符串?

Binding="Binding SelectedItem, Converter=StaticResource ObjectToTypeString"

并将转换器定义为:

public class ObjectToTypeStringConverter : IValueConverter

    public object Convert(
     object value, Type targetType,
     object parameter, System.Globalization.CultureInfo culture)
    
        return value.GetType().Name;            
    

    public object ConvertBack(
     object value, Type targetType,
     object parameter, System.Globalization.CultureInfo culture)
    
        // I don't think you'll need this
        throw new Exception("Can't convert back");
    

您需要在 xaml 中的某处声明静态资源:

<Window.Resources>
    <convs:ObjectToTypeStringConverter x:Key="ObjectToTypeString" />
</Window.Resources>

这里的“convs”是转换器所在的命名空间。

希望这会有所帮助。

【讨论】:

+1 表示总体思路,但是转换器应返回 Type 对象而不是其名称... 这行得通吗?运行时不会将 String 类型的东西与 Type 类型的东西进行比较吗?我知道它处理转换/比较大多数值类型,但不熟悉它如何处理其他类型比较。 是的,它会起作用,您只需在 DataTrigger 的值中使用 x:Type 标记扩展。【参考方案2】:

使用 AndyG 建议的转换器是一个不错的选择。或者,您也可以为每种目标类型使用不同的DataTemplate。 WPF 会自动选择匹配对象类型的DataTemplate

【讨论】:

但它也会影响该数据类型的每个子元素【参考方案3】:

这是基于@AndyG 的回答,但更安全一些,因为它是强类型的。

实现一个名为 DataTypeConverter 的 IValueConverter,它接受一个对象并返回其类型(作为 System.Type):

public class DataTypeConverter:IValueConverter

    public object Convert(object value, Type targetType, object parameter, 
      CultureInfo culture)
    
        return value?.GetType() ?? Binding.DoNothing;
    

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

更改您的 DataTrigger 以使用转换器,并将值设置为类型:

<DataTrigger Binding="Binding SelectedItem,  
      Converter=StaticResource DataTypeConverter" 
      Value="x:Type local:MyType">
...
</DataTrigger>

在资源中声明DataTypeConverter:

<UserControl.Resources>
    <v:DataTypeConverter x:Key="DataTypeConverter"></v:DataTypeConverter>
</UserControl.Resources>

【讨论】:

这对我不起作用。如果我尝试在 DataTrigger.Value 中使用标记扩展,则会收到 XamlParseException,因此我只是使用了字符串比较方法。见这里:social.msdn.microsoft.com/Forums/en-US/wpf/thread/… 在尝试 GetType() 之前最好检查值是否为空。返回值!= null ? value.GetType() : null; Binding="Binding SelectedItem" Converter=StaticResource DataTypeConverter" 应该是Binding="Binding SelectedItem, Converter=StaticResource DataTypeConverter" 【参考方案4】:

不是触发器,但这对我有用。 (触发器方法没有,因为它无法为字符串创建复选框。这几乎是Thomas Levesque's suggestion)

使用:

xmlns:mscorlib="clr-namespace:System;assembly=mscorlib"

取决于类型的 CheckBox 或 TextBox:

<ContentPresenter Content="TemplateBinding SelectedItem">
      <ContentPresenter.Resources>
               <DataTemplate DataType="x:Type mscorlib:Boolean">
                    <CheckBox Height="25" Width="25" HorizontalAlignment="Left" IsChecked="Binding Path=."/>
               </DataTemplate>
                  <DataTemplate DataType="x:Type mscorlib:String">
                    <TextBox Height="25" Width="200" HorizontalAlignment="Left" Text="Binding Path=."/>
                </DataTemplate>
       </ContentPresenter.Resources>
</ContentPresenter>

注意:对于 Greg Sansom 的解决方案,您要么将类型返回为 String,要么使用上面的 mscorlib

【讨论】:

【参考方案5】:

如果您可以通过添加属性来修改分配给“SelectedItem”的(基本)类型:

public Type Type => this.GetType();

然后你可以像这样在 xaml 中使用 DataTrigger:

<DataTrigger Binding="Binding SelectedItem.Type" Value="x:Type local:MyClass">
</DataTrigger>

与 AndyG 的好答案相比的优势在于,您在 XAML 中没有您的类型的魔术字符串,但所有内容都可以安全编译。 缺点:您需要修改模型 - 这可能并不总是可行的。

【讨论】:

以上是关于基于对象类型的 WPF 触发器的主要内容,如果未能解决你的问题,请参考以下文章

WPF:InvalidCastException:无法将“System.Windows.Style”类型的对象转换为“System.Windows.ResourceDictionary”类型

WPF学习第五十五章 基于路径的动画

2021-09-26 WPF上位机 45-关键帧动画

WPF学习第三章 使用其他名称空间中的类型

无法为 Net Core 3.1 WPF 应用程序创建类型为“DbContext”的对象

WPF DataTemplate 绑定取决于属性的类型