将属性绑定到dependecyproperty时触发器不起作用

时间:2016-07-07 12:30:09

标签: c# wpf xaml data-binding triggers

我正在尝试使用触发器设置矩形(WPF)的颜色,具体取决于布尔值DependencyProperty,我将其绑定到矩形的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属性中,则触发器可以正常工作。 如果我在运行时将tag属性的值打印到控制台,则绑定有效,但触发器不会触发。

任何想法我做错了什么?

谢谢!

4 个答案:

答案 0 :(得分:2)

你的触发器试图将布尔值true与字符串&#34; True&#34;进行比较。因为Tag是一个Object属性所以将存储布尔值,而Trigger的值是一个String。 PHP希望它,而不是WPF。 ;)

如果要保留Trigger而不是DataTrigger,可以创建一个静态类:

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这个想法。

答案 1 :(得分:1)

您可以尝试使用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>

将datacontext设置为窗口:

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}}" />

即使其他人也有很多美丽的解决方案。

答案 2 :(得分:1)

您需要设置绑定的DataContext。现在,您的绑定指向Rectangle.DataContext.isAutoStart,但Rectangle.DataContext为空,因此您的绑定不会解析为任何内容。有关DataContext的详细信息,请参阅this answer

因为您提到here您不想使用DataTrigger进行硬编码,您可能需要手动设置绑定的Source以搜索可视树到第一个而是Window对象,并绑定到该属性的isAutoStart属性。

<Rectangle Tag="{Binding Path=isAutoStart, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" .. />

您还有this answer所指出的额外问题,您将布尔值与字符串进行比较,因此它总是评估为False。有很多方法可以解决这个问题,例如IValueConverter,但我发现最简单的方法是导入系统命名空间并为布尔值true创建一个静态值,如图here所示:

<s:Boolean x:Key="TrueValue">True</s:Boolean>
...
<Trigger Property="Tag" Value="{StaticResource TrueValue}">

s命名空间定义为

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

答案 3 :(得分:1)

用户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}}" />