【问题标题】:Trigger not working, when binding property to dependecyproperty将属性绑定到dependecyproperty时,触发器不起作用
【发布时间】:2016-11-09 18:36:46
【问题描述】:

我正在尝试使用触发器设置矩形 (WPF) 的颜色,具体取决于我绑定到矩形的 Tag 属性的布尔 DependencyProperty。

我有以下代码:

 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”硬编码到矩形的标记属性中,触发器就会正常工作。 如果我在运行时将标签属性的值打印到控制台,则绑定有效,但触发器不会触发。

任何想法我做错了什么?

谢谢!

【问题讨论】:

  • 除非您设置源对象,否则绑定将不起作用,例如通过将 Window 的 DataContext 设置为自身,或指定 Binding 的 RelativeSource 属性。除此之外,设置 UpdateSourceTrigger 没有任何意义,因为它在这里没有任何作用。
  • 最好不要绑定 Tag 属性并在其 Value 上设置 Trigger,而是使用直接绑定到 isAutoStart 属性的 DataTrigger。
  • 如果你没有设置DataContext,试试Tag="{Binding isAutoStart, RelativeSource={RelativeSource AncestorType=Window}}"
  • 我已将 DataContext 设置为 DataContext="{Binding RelativeSource={RelativeSource Self}}",但它仍然无法正常工作,也无法设置 RelativeSource。
  • 你必须像前面消息中所说的@Clemens 设置相对源。在这种情况下,Self 表示(矩形而不是窗口)

标签: c# wpf xaml data-binding triggers


【解决方案1】:

您的触发器尝试将布尔值 true 与字符串“True”进行比较,因为 Tag 是 Object 属性,因此布尔值将被存储,而触发器的值是字符串。 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 的想法。

【讨论】:

    【解决方案2】:

    您需要设置绑定的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,但我发现最简单的方法是导入系统命名空间并为布尔真值创建一个静态值,如here 所示:

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

    s 命名空间定义为

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        即使其他人为你提供了很多漂亮的解决方案。

        【讨论】:

        • 我不想直接将依赖属性与 DataTrigger 绑定,因为我想重用这个“模板”并在 Tag 属性中传递不同的依赖属性。
        猜你喜欢
        • 1970-01-01
        • 2010-12-20
        • 2017-11-18
        • 2012-04-03
        • 2017-11-23
        • 2019-12-14
        • 2014-06-18
        • 1970-01-01
        相关资源
        最近更新 更多