将属性绑定到依赖项属性时触发器不起作用
本文关键字:属性 触发器 不起作用 依赖 绑定 | 更新日期: 2023-09-27 17:55:32
我正在尝试使用触发器设置矩形 (WPF) 的颜色,具体取决于布尔依赖项属性,我将其绑定到矩形的 Tag 属性。
我有以下代码:
public partial class MainWindow : Window
{
public Boolean isAutoStart
{
get { return (Boolean)GetValue(isAutoStartProperty); }
set { SetValue(isAutoStartProperty, value); }
}
public static readonly DependencyProperty isAutoStartProperty =
DependencyProperty.Register("isAutoStart", typeof(Boolean),
typeof(MainWindow), new PropertyMetadata(true));
private void Window_Loaded(object sender, RoutedEventArgs e)
{
isAutoStart = false;
}
}
在 XAML 中:
<Window.Resources>
<Style x:Key="TriggerDark" TargetType="Rectangle">
<Setter Property="Fill" Value="Green" />
<Style.Triggers>
<Trigger Property="Tag" Value="False">
<Setter Property="Fill" Value="Red" />
</Trigger>
<Trigger Property="Tag" Value="True">
<Setter Property="Fill" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Rectangle Style="{StaticResource ResourceKey=TriggerDark}" Tag="{Binding Path=isAutoStart, UpdateSourceTrigger=PropertyChanged}">
如果我将"True"或"False"硬编码到矩形的标签属性中,触发器将正常工作。如果我在运行时将 tag 属性的值打印到控制台,绑定有效,但触发器不会触发。
知道我做错了什么吗?
谢谢!
触发器尝试将布尔值 true 与字符串"True"进行比较,因为 Tag 是 Object 属性,因此将存储布尔值,而触发器的值是字符串。PHP想要它,而不是WPF。;)
如果要保留触发器而不是数据触发器,可以创建一个静态类:
public static class BooleanHelper {
public static bool False {
get { return false; }
}
public static bool True {
get { return true; }
}
}
然后样式将写成:
<Style x:Key="TriggerDark" TargetType="Rectangle">
<Setter Property="Fill" Value="Green"/>
<Style.Triggers>
<Trigger Property="Tag" Value="{x:Static local:BooleanHelper.True}">
<Setter Property="Fill" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
感谢Michael Mairegger的想法。
您需要设置绑定的DataContext
。现在,您的绑定指向 Rectangle.DataContext.isAutoStart
,但是Rectangle.DataContext
为 null,因此您的绑定不会解析为任何内容。有关DataContext
的更多详细信息,请参阅此答案。
因为您在此处提到您不想使用 DataTrigger
进行硬编码,所以您可能希望手动设置绑定Source
以将可视化树搜索到第一个Window
对象,并绑定到该对象的 isAutoStart
属性。
<Rectangle Tag="{Binding Path=isAutoStart, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" .. />
正如此答案所指出的那样,您还遇到了额外的问题,您将布尔值与字符串进行比较,因此它始终评估为 False。有很多方法可以解决这个问题,例如IValueConverter
,但我发现最简单的方法是导入系统命名空间并为布尔 true 创建一个静态值,如下所示:
<s:Boolean x:Key="TrueValue">True</s:Boolean>
...
<Trigger Property="Tag" Value="{StaticResource TrueValue}">
其中s
命名空间定义为
xmlns:s="clr-namespace:System;assembly=mscorlib"
用户 nkoniishvt 已经给出了解释,触发器将Tag
属性值与字符串文本"True"和"False"进行比较,而不是bool
值。
此问题的另一种解决方法可能是不使用 Tag
属性,而是使用正确类型的附加属性,例如声明
public static class StyleHelper
{
public static readonly DependencyProperty StateProperty =
DependencyProperty.RegisterAttached(
"State", typeof(bool), typeof(StyleHelper));
public static bool GetState(DependencyObject obj)
{
return (bool)obj.GetValue(StateProperty);
}
public static void SetState(DependencyObject obj, bool value)
{
obj.SetValue(StateProperty, value);
}
}
你将在 XAML 中使用它,如下所示:
<Window.Resources>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Green" />
<Style.Triggers>
<Trigger Property="local:StyleHelper.State" Value="False">
<Setter Property="Fill" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Rectangle local:StyleHelper.State="{Binding isAutoStart}}" />
您可以尝试使用 DataTrigger:
(请注意,您也可以通过删除触发器来举例说明您的风格)
<Style x:Key="TriggerDark" TargetType="Rectangle">
<Setter Property="Fill" Value="Green" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=isAutoStart}" Value="False">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
同时将数据上下文设置为窗口:
public MainWindow()
{
DataContext = this;
}
编辑:如果你愿意,你可以使用IValueConverter:
public class BoolToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
并将绑定更改为:
<Window.Resources>
<local:BoolToStringConverter x:Key="BtSConv"/>
<Style x:Key="TriggerDark" TargetType="Rectangle">
<Setter Property="Fill" Value="Green" />
<Style.Triggers>
<Trigger Property="Tag" Value="False">
<Setter Property="Fill" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Rectangle Style="{StaticResource TriggerDark}" Tag="{Binding isAutoStart, Converter={StaticResource BtSConv}}" />
甚至有很多来自其他人的美丽解决方案。