Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Property assigned with value binding does not work

I have a usercontrol with a dependency property.

public sealed partial class PenMenu : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }         

    public bool ExpandCollapse
    {
        get
        {
            return false;
        }

        set
        {
            //code
        }
    }
public static readonly DependencyProperty ExpandCollapseProperty = DependencyProperty.Register("ExpandCollapse", typeof(bool), typeof(PenMenu), null);
//some more code
}

And I am assigning value in XAML page as:

<Controls:PenMenu x:Name="penMenu" Opened="Menu_Opened" 
                         ExpandCollapse="{Binding PenMenuVisible}" />

But it is not hitting GET-SET part of ExpandCollapse property in the usercontrol. So I added bool to bool converter just to check what value is being passed with binding like:

<Controls:PenMenu x:Name="penMenu" Opened="Menu_Opened" 
                         ExpandCollapse="{Binding PenMenuVisible, Converter={StaticResource booleanToBooleanConverter}}" />

And with breakpoint in Converter, I see the value being passed is correct. What is the possible reason it's not assigned to the Dependency Property?

Also in XAML page if I say:

<Controls:PenMenu x:Name="penMenu" Opened="Menu_Opened" 
                         ExpandCollapse="true"/>

then it hits the GET-SET part of ExpandCollapse property in the usercontrol. I am stuck. This is weird. Please help.

like image 775
ashish nirkhe Avatar asked Nov 19 '13 19:11

ashish nirkhe


2 Answers

It's frustrating isn't it? First, include a changed event handler. Like this:

public string Title
{
    get { return (string)GetValue(TitleProperty); }
    set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register("Title", typeof(string), 
    typeof(MyControl), new PropertyMetadata(string.Empty, Changed));
private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var c = d as MyControl;
    // now, do something
}

Then, please read this article so you see there are more gotchas than just that one: http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html

Best of luck!

like image 29
Jerry Nixon Avatar answered Nov 12 '22 06:11

Jerry Nixon


The getter and setter of a dependency property are not guaranteed to be run, and in particular the WPF binding engine / XAML processor is documented to bypass these. Have a look on MSDN - the getter/setter should just be a wrapper around GetValue/SetValue on the DependencyProperty itself.

Instead of reacting in the setter of your property, you should add a property changed handler in the original call to DependencyProperty.Register, when you can act on the new value.

(see other questions).

like image 59
Nicholas W Avatar answered Nov 12 '22 07:11

Nicholas W