触发的数据触发器不会更改自定义控件的新添加属性

Posted

技术标签:

【中文标题】触发的数据触发器不会更改自定义控件的新添加属性【英文标题】:Fired datatrigger is not changing custom control's newly added property 【发布时间】:2013-09-30 06:40:56 【问题描述】:

我正在创建一个动画控件,并尝试在其中使用数据触发器。问题是我创建的 dp 属性在触发触发器时没有被更改/调用。以下是我注意到的行为摘要。

1) 后面的代码永远不会被调用。

2) 属性出现在 XAML 智能感知中,但 XAML 中给出的更改永远不会被应用(设计/运行时)。但是,如果我在“public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register("IsSpinning", typeof(bool), typeof(ProgressWaitSpinner), new UIPropertyMetadata(false));"中替换 'IsSpinning'对于其他东西(比如'xyz'),它开始为属性分配工作,但如果启用了样式,则会引发运行时异常。

3) 运行示例时,矩形应该被隐藏而不是显示为巧克力色,这不会发生。

4) 用于更改颜色的 Setter 正在工作,它来自用户控件,但是新创建的属性上的 setter 属性不起作用。

我在这里创建了一个简化的示例来显示问题。请问有人知道怎么回事吗?

用户控件 XAML:

<UserControl x:Class="CustomControls.ProgressWaitSpinner"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomControls" 
    Height="191" Width="191">
    <Grid x:Name="LayoutRoot">
        <Label Height="32" Name="label1" VerticalAlignment="Top" />
    </Grid>
</UserControl>

用户控制代码:

using System.Windows;
using System.Windows.Controls;

namespace CustomControls

    public partial class ProgressWaitSpinner : UserControl
    

        public ProgressWaitSpinner()InitializeComponent();

        public bool IsSpinning
        
            get 
            
                return (bool)GetValue(IsSpinningProperty); 
            
            set
            
                if (value == true)
                
                    this.Visibility = System.Windows.Visibility.Visible;
                
                else
                
                    this.Visibility = System.Windows.Visibility.Hidden;
                
                SetValue(IsSpinningProperty, value); 
            
        

        public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register("IsSpinning", typeof(bool), typeof(ProgressWaitSpinner), new UIPropertyMetadata(false));
    

主窗口 XAML:

<Window x:Class="WPFSpinnerWait.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:usrctrl="clr-namespace:CustomControls"
        Title="MainWindow" Height="208" Width="228">
    <Grid>
        <usrctrl:ProgressWaitSpinner Height="40" x:Name="WaitSpinner" Margin="110,103,0,0" HorizontalAlignment="Left" Width="84" VerticalAlignment="Top">
            <usrctrl:ProgressWaitSpinner.Style>
                <Style>
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="Binding ElementName=label1, Path=Content" Value="NotStarted"></Condition>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="usrctrl:ProgressWaitSpinner.Background" Value="Red" />
                            <Setter Property="usrctrl:ProgressWaitSpinner.IsSpinning" Value="false"/>
                        </MultiDataTrigger>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="Binding ElementName=label1, Path=Content" Value="Running"></Condition>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="usrctrl:ProgressWaitSpinner.Background" Value="Chocolate" />
                            <Setter Property="usrctrl:ProgressWaitSpinner.IsSpinning" Value="true" />
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </usrctrl:ProgressWaitSpinner.Style>
        </usrctrl:ProgressWaitSpinner>
        <Button Content="NotStarted" Height="28" HorizontalAlignment="Left" Margin="38,22,0,0" Name="checkBox1" VerticalAlignment="Top" Width="136" Click="checkBox1_Checked" />
        <Button Content="Running" Height="30" HorizontalAlignment="Left" Margin="38,56,0,0" Name="checkBox2" VerticalAlignment="Top" Width="136" Click="checkBox1_Checked" />
        <Label Content="NotStarted" DataContext="usrctrl:ProgressWaitSpinner" Height="25" HorizontalAlignment="Left" Margin="38,92,0,0" Name="label1" VerticalAlignment="Top" Width="114" />
    </Grid>
</Window>

主窗口代码:

using System.Windows;
using System.Windows.Controls;

namespace WPFSpinnerWait

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
        

        private void checkBox1_Checked(object sender, RoutedEventArgs e)
        
            label1.Content = ((Button)sender).Content.ToString();
        

    

【问题讨论】:

不会调用代码隐藏,DependancyPropertyies 不使用支持属性,它们仅用于代码隐藏,在 Xaml 绑定中没有用 【参考方案1】:

后面的代码不会被调用,DependancyProperties 在 Xaml 中更改/使用属性时不使用支持属性,它们仅用于在后面的代码中作为帮助程序,在 Xaml 绑定中没有用处

您可以改用DependancyPropertyPropertyChanged 事件

    public bool IsSpinning
    
        get  return (bool)GetValue(IsSpinningProperty); 
        set  SetValue(IsSpinningProperty, value); 
    

    // Using a DependencyProperty as the backing store for IsSpinning.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSpinningProperty =
        DependencyProperty.Register("IsSpinning", typeof(bool), typeof(ProgressWaitSpinner), new PropertyMetadata(false, OnIsSpinningChanged));

    private static void OnIsSpinningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        if (((bool)e.NewValue) == true)
        
            (d as ProgressWaitSpinner).Visibility = System.Windows.Visibility.Visible;
        
        else
        
            (d as ProgressWaitSpinner).Visibility = System.Windows.Visibility.Hidden;
        
    

编辑:

对于您的第二个问题,请尝试为您的Style 添加TargetType,以便您可以直接访问属性

 <Style TargetType="x:Type usrctrl:ProgressWaitSpinner">
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="Binding ElementName=label1, Path=Content" Value="NotStarted"></Condition>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" Value="Red" />
            <Setter Property="IsSpinning" Value="false"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="Binding ElementName=label1, Path=Content" Value="Running"></Condition>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" Value="Chocolate" />
            <Setter Property="IsSpinning" Value="true" />
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

【讨论】:

太棒了...感谢您的快速回复...它解决了我的核心问题...谢谢 sa_ddam213.. :)...还有一个小问题。我正在尝试将此控件属性用作 xaml 中的常规属性,如何使这成为可能?行为编号:2 在我的问题中。 添加了更新,当我将正确的 TargetType 添加到您的样式并设置属性时,它似乎正在工作 感谢您的回复。这里有点混乱......我做了什么:(1)添加了你的代码(2)修改了xaml:

以上是关于触发的数据触发器不会更改自定义控件的新添加属性的主要内容,如果未能解决你的问题,请参考以下文章

如何在不覆盖现有样式的情况下向 WPF 自定义控件添加触发器?

在自定义控件中,有CheckBox控件,当触发OnCheckedChanged事件时

Angular2自定义表单控件防止发射事件

WPF: WPF 中的 Triggers 和 VisualStateManager

WPF: WPF 中的 Triggers 和 VisualStateManager

winform用户控件timer控件三级联动