digitally_inspired
digitally_inspired

Reputation: 777

Fired datatrigger is not changing custom control's newly added property

I am creating an animation control and where I am trying to use data triggers. The issue is the dp property which I created is not getting changed/called when the trigger is fired. Here is the summary of behaviour I noticed.

1) The code behind of never gets called.

2) Property appears in XAML intellisense but the changes given in XAML never gets applied (design/runtime). But if I replace 'IsSpinning' in "public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register("IsSpinning", typeof(bool), typeof(ProgressWaitSpinner), new UIPropertyMetadata(false));" to something else( say 'xyz') it starts working for property assignment, but throws runtime exception if styles are enabled.

3) When running the sample, The rectangle should be hidden instead of showing as Chocolate color, which is not happening.

4) Setter for changing color is working, which is from the user control, however the setter property on newly created property is not working.

I created a simplified sample here which shows the problem. Anyone got a clue what is going on please?

UserControl 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>

UserControl Code:

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));
    }
}

MainWindow 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>

MainWindow Code:

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();
        }

    }
}

Upvotes: 0

Views: 1451

Answers (1)

sa_ddam213
sa_ddam213

Reputation: 43636

The code behind won't get called, DependancyProperties do not use the backing property when the property is change/used in Xaml, thay are only there for use in code behind as a helper, thay have no use in Xaml bindings

You can use the PropertyChanged event of the DependancyProperty instead

    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;
        }
    }

Edit:

For your second question, Try adding the TargetType for your Style so you can access the properties directly

 <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>

Upvotes: 2

Related Questions