Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set WPF behavior property using a data trigger

Tags:

c#

.net

wpf

xaml

I am trying to set a WPF behavior property using a style in the following way:

<StackPanel>
    <CheckBox Name="IsFemaleChkBox" Content="Is Female ?" />
    <TextBlock>
        <Hyperlink> <!--setting property directly like this:  local:MyHyperLinkBehavior.Salutation="Mr." isn't working either-->
            <TextBlock Text="My Hyperlink"/>
            <Hyperlink.Style>
                <Style TargetType="Hyperlink">
                    <Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Mr." />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=IsFemaleChkBox}" Value="True">
                            <Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Miss" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Hyperlink.Style>
        </Hyperlink>
    </TextBlock>
</StackPanel>

And the behavior class code is this:

class MyHyperLinkBehavior : Behavior<Hyperlink>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += AssociatedObject_Click;
    }

    public static bool GetIsFemale(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFemaleProperty);
    }

    public static void SetIsFemale(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFemaleProperty, value);
    }

    // Using a DependencyProperty as the backing store for IsFemale.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsFemaleProperty =
        DependencyProperty.RegisterAttached("IsFemale", typeof(bool), typeof(MyHyperLinkBehavior), new PropertyMetadata(false));


    public static string GetSalutation(DependencyObject obj)
    {
        return (string)obj.GetValue(SalutationProperty);
    }

    public static void SetSalutation(DependencyObject obj, string value)
    {
        obj.SetValue(SalutationProperty, value);
    }

    // Using a DependencyProperty as the backing store for Salutation.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SalutationProperty =
        DependencyProperty.RegisterAttached("Salutation", typeof(string), typeof(MyHyperLinkBehavior), new PropertyMetadata(default(string)));

    void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        MessageBox.Show(Convert.ToString(GetValue(SalutationProperty)));
    }
}

I can't figure out why this is not working. Or setting a behavior's property using style isn't valid at all ? What is the other way round, if this is not valid.

like image 360
Randeep Singh Avatar asked May 27 '15 11:05

Randeep Singh


Video Answer


2 Answers

There are two types of behaviors in WPF:

  1. System.Windows.Interactivity Behaviors, called also Blend Behaviours

    These behaviours are classes inherited from System.Windows.Interactivity.Behavior and you can use them by adding to used them by Adding it to Behaviours collection, e.g:

    <Rectangle>
        <i:Interaction.Behaviors>
            <ei:MouseDragElementBehavior />
        </i:Interaction.Behaviors>
    </Rectangle>
    

    notice, that these behaviors does not have any custom attached properties. OnAttached and OnDetached methods are automatically called.

    • Pros: Easy to implement
    • Cons: Does not work with styles (however, it works with ControlTemplates and DataTemplates)
  1. Behaviors implemented as Custom Attached Property

    In these behaviors the logic defined in PropertyChangedCallback of the custom attached property.

    public static readonly DependencyProperty SalutationProperty =
       DependencyProperty.RegisterAttached("Salutation",
            typeof(string),
            typeof(MyHyperLinkBehavior),
            new PropertyMetadata(OnSalutationPropertyChanged));
    
    
    private static void OnSalutationPropertyChanged(object sender,
                                             DependencyPropertyChangedEventArgs e)
    {
         //attach to event handlers (Click, Loaded, etc...)
    }
    
    • Pros: Can be defined in styles, easier to use
    • Cons: Chatty code, a little more difficult to implement

You are mixing those two types of behaviors together. Choose one and use it! Since you want to use it in style, you shoud choose behavior implemented as custom attached property

like image 179
Liero Avatar answered Oct 19 '22 23:10

Liero


I got it working, it was a small miss by me.

  1. I forgot to set the behavior on the hyperlink.
  2. I need to get the property of the attachedObject and not of the
    behavior.

Following code works fine:

<StackPanel>
    <CheckBox Name="IsFemaleChkBox" Content="Is Female ?" />
    <TextBlock>
        <Hyperlink>
            <TextBlock Text="My Hyperlink"/>
            <i:Interaction.Behaviors> <!--Missed setting behavior-->
                <local:MyHyperLinkBehavior />
            </i:Interaction.Behaviors>
            <Hyperlink.Style>
                <Style TargetType="Hyperlink">
                    <Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Mr." />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=IsFemaleChkBox}" Value="True">
                            <Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Miss" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Hyperlink.Style>
        </Hyperlink>
    </TextBlock>
</StackPanel>

And the behavior:

class MyHyperLinkBehavior : Behavior<Hyperlink>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += AssociatedObject_Click;
    }

    public static bool GetIsFemale(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFemaleProperty);
    }

    public static void SetIsFemale(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFemaleProperty, value);
    }

    // Using a DependencyProperty as the backing store for IsFemale.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsFemaleProperty =
        DependencyProperty.RegisterAttached("IsFemale", typeof(bool), typeof(MyHyperLinkBehavior), new PropertyMetadata(false));


    public static string GetSalutation(DependencyObject obj)
    {
        return (string)obj.GetValue(SalutationProperty);
    }

    public static void SetSalutation(DependencyObject obj, string value)
    {
        obj.SetValue(SalutationProperty, value);
    }

    // Using a DependencyProperty as the backing store for Salutation.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SalutationProperty =
        DependencyProperty.RegisterAttached("Salutation", typeof(string), typeof(MyHyperLinkBehavior), new PropertyMetadata(default(string)));

    void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        // Changing "GetValue(SalutationProperty)" to "this.AssociatedObject.GetValue(SalutationProperty)" works
        MessageBox.Show(Convert.ToString(this.AssociatedObject.GetValue(SalutationProperty)));
    }
}
like image 35
Randeep Singh Avatar answered Oct 20 '22 00:10

Randeep Singh