views:

63

answers:

2

I've created a custom control with, amongst others, the following:

public partial class MyButton : UserControl
{
  public bool Enabled
  {
    get { return (bool)GetValue(EnabledProperty); }
    set { 
      SetValue(EnabledProperty, value); 
      SomeOtherStuff();
      }
    }
  }

  public static readonly DependencyProperty EnabledProperty =
     DependencyProperty.Register("Enabled", typeof(bool), typeof(MyButton), new PropertyMetadata(true));

  public static void SetEnabled(DependencyObject obj, bool value)
  {
    obj.SetValue(EnabledProperty, value);
  }
  public static bool GetEnabled(DependencyObject obj)
  {
    return (bool) obj.GetValue(EnabledProperty);
  }
}

In my XAML, I (try to) use binding to set the Enabled property:

<MyButton x:Name="myButtom1" Enabled="{Binding CanEnableButton}"/>

I know the bind between my control and the underlying data model is valid and working as I can bind 'IsEnabled' (a native property of the underlying UserControl) and it works as expected. However, my Enabled property is never set via the above binding. I've put breakpoints on my property set/get and they never get hit at all.

I can only imaging I've missed something relating to binding in my custom control. Can anyone see what?

I've tried implementing INotifyPropertyChanged on my control (and calling the PropertyChanged event from my Enabled setter) ... but that didn't fix it.

[ BTW: In case you are wondering "Why?": I can't intercept changes to the IsEnabled state of the base control, so I decided to implement and use my own version of a Enable/disable property (which I called Enabled) - one where I could plug my own code into the property setter ]

+2  A: 

First of all drop the SetEnabled and GetEnabled pair, these only make sense for an attached property which is not what you are doing.

Now your main problem is that you are under the false assumption that the get/set members of your propery get called during binding, they don't.

What you need is to pass a call back method in the property meta data, it's here that you intercept changes and take other actions like so:-

    public bool IsEnabled
    {
        get { return (bool)GetValue(IsEnabledProperty); }
        set { SetValue(IsEnabledProperty, value); }
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.Register(
            "IsEnabled",
            typeof(bool),
            typeof(MyButton),
            new PropertyMetadata(true, OnIsEnabledPropertyChanged));

    private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyButton source = d as MyButton;
        source.SomeOtherStuff();

    }

    private void SomeOtherStuff()
    {
         // Your other stuff here
    }

With this in place regardless of how the propery is changed the SomeOtherStuff procedure will execute.

AnthonyWJones
I think using the built in IsEnabledChanged event is a better choice over implementing another "enabled" property on a control. (See my answer).
WPCoder
Thanks. This is useful to know. As pointed out below, making use of the existing Enabled changed event is what I should (and will) be doing. However, I imaging I will need to create a bindable property on a control at some point and you're advice will be invaluable at that time.
Trevor
+2  A: 

I'd suggest using the IsEnabledChanged event which is part of every Control/UserControl.

That would allow you to hook up to the event and do whatever actions you want to take.

public MainPage()
{
    InitializeComponent();

    this.IsEnabledChanged += new DependencyPropertyChangedEventHandler(MainPage_IsEnabledChanged);
}

void MainPage_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    // Do SomeStuff
}
WPCoder
This is indeed the better solution, and the one I'll adopt - thanks. I have however marked Anthony's response as the 'answer' as it provides the relevant info needed to implement a bindable property.
Trevor