0
votes

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

    }
}
1
The codebehind wont get called, DependancyPropertyies do not use the backing property, thay are only there for use in codebehind, thay have no use in Xaml bindingssa_ddam213

1 Answers

2
votes

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>