tags:

views:

94

answers:

3

In my scenario I have a lot of buttons or other controls which I want to depend upon a public property inside the code-behind file. Let's call this IsEverythingLoaded and it's a boolean.

Now I would like to have a button look like this

<Button Click="DoTheMagic" 
     IsEnabled="{Binding Path=IsEverythingLoaded}">Click Me</Button>

To even get this running I figured out I need to point it to the Relative Source, so by adding this to my <Window> decleration, I got the initiation and visualisation to work.

DataContext="{Binding RelativeSource={RelativeSource Self}}"

However, lets say that I raise an event with another button, which then were to set IsEverythingLoaded to true, I would imagine that IsEnabled on each button would too. And therefore be clickable again, but I was wrong, isn't this how DependencyProperties should work?

To Clarify..

I do NOT wish to write IsEverythingLoaded as a DependencyProperty. I want the Button to Depend on A CLR Property

+2  A: 

Your class needs to implement INotifyPropertyChanged, so that it can notify the binding that the property value has changed.

public class MyClass : INotifyPropertyChanged
{
    public bool IsEverythingLoaded
    {
        get { return _isEverythingLoaded; }
        set
        {
            _isEverythingLoaded = value;
            OnPropertyChanged("IsEverythingLoaded");
        }
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
       PropertyChangedEventHandler handler = PropertyChanged;
       if (handler != null)
           handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}
Thomas Levesque
Ah.. interesting..
Filip Ekberg
+3  A: 

Your Button (i.e. it's databinding) needs to be notified that your public property has changed. This can be done in two ways:

  • Have your class implement INotifyPropertyChanged and raise the PropertyChanged event after changing IsEverythingLoaded or
  • make your public property a DependencyProperty, in which case the notification is done by the framework automatically. The DependencyProperty MSDN page contains further explanations and an example of how to do this.

For the first option, Thomas wrote an example; for the second option, your code would look like this:

public static readonly DependencyProperty IsEverythingLoadedProperty =
    DependencyProperty.Register("IsEverythingLoaded", typeof(Boolean),
                                 typeof(YourCodeBehindClass), new PropertyMetadata(false));

public Boolean IsEverythingLoaded {
    get { return (Boolean)this.GetValue(IsEverythingLoadedProperty); }
    set { this.SetValue(IsEverythingLoadedProperty, value); } 
}
Heinzi
I know how to create DPs and how to use them, my question was why it didn't behave like ordernary DPs when you change the values.
Filip Ekberg
So you're saying that `IsEverythingLoaded` is already a dependency property? If it is, you really shouldn't need INotifyPropertyChanged.
Heinzi
No it's not, And I don't want it to be either. As I've written, I want to bind a DependencyProperty ( IsEnabled ) to a Code Behind property and when I trigger the CLR Property, I want the DP to be Notified. Please read my question again.
Filip Ekberg
I did read your question. Please read my answer. :-) If you want to do databinding (with the *target* being a DependencyProperty), the *source* needs to either (1) implement INotifyPropertyChanged or (2) also be a DependencyProperty, in which case the notification process is done automatically. Is my answer clearer now?
Heinzi
I've updated my answer to make this clearer. When I wrote my answer, I was under the impression that you assumed that your *public property* was a dependency property.
Heinzi
Sorry if it was a bit unclear, hope it's a bit clearer now. I just feel that DP -> DP is a "Bad" design, i rahter use the INotifyPropertyChanged.
Filip Ekberg
I see, thanks for the clarification. I understand your point about DP -> DP; nevertheless, it's used quite often (hence my misunderstanding) in the Model-View-ViewModel paradigm (see my comment on your question).
Heinzi
+3  A: 

I strongly disagree with your blanket statement that binding DP -> DP is "bad design".

Here are some of the reasons why DP -> DP binding might be considered good design, not bad:

  1. Binding a DependencyProperty to another DependencyProperty is much more efficient than binding it to a CLR property that implements INotifyPropertyChanged. This use case has been heavily optimized in WPF, and is the way you are expected to go.

  2. DependencyProperties are much less error-prone for keeping your data in sync. It is very easy to forget to call the PropertyChanged event or not properly analyze all the situations in which you might need to call it. DependencyProperties relieve you of this burden. Since I switched from primarily using INotifyPropertyChanged to primarily using DependencyProperties, my data mis-synchronization bugs have reduced perhaps 100x to almost zero, and those that are left almost invariably are found in the INotifyPropertyChanged code.

  3. When writing demos of your code you often unexpectedly come across the need to animate what you've always viewed as a pure "data" property. If it is not a DependencyProperty, it can't be done. I could show you several examples where using DependencyProperties really saved the day.

  4. If done properly, creating a DependencyProperty as a source of data is less code (and simpler) than the corresponding CLR property that supports INotifyPropertyChanged.

  5. If you use a DependencyProperty as your source, you can add coercion and validation using business rules, which can't be done with a CLR property.

  6. Storage for numerous DependencyProperties is more efficent than for numerous CLR properties, making them great for data objects with many 'null', 0, 'false', or 'Empty' property values.

  7. DependencyProperties provide an excellent thread safety mechanism because they immediately alert you if you try to use them improperly rather than silently doing the wrong thing.

  8. Bindings can automatically and safely cross threads when necessary if you are binding to DependencyProperties. If you are binding to CLR properties there is no protection at all, so the only safe way is to lock() code to your object if your application has multiple threads. Not doing so is fraught with peril due to the subtle threading issues that can come about with caching and the load/store ordering rules.

  9. DependencyProperties can efficiently support varying default values by object type using OverrideMetadata. Classic CLR properties can only do this by running extra code every time the object is constructed.

I could go on and list quite a few other good reasons to use DependencyProperties as the source of your bindings, but I think you get the idea.

WPF was built based on the assumption that you would be binding to DependencyProperties, and INotifyPropertyChanged was only added later (and inefficiently). This is evidence that a group of very good software architects clearly thought binding DP -> DP was a good design.

I realize that there are some advantages to using INotifyPropertyChanged instead of DPs in certain scenarios. Nevertheless, DP -> DP binding is certainly is not "bad design," and in many cases it is the very best design.

Ray Burns
This makes everything argumentative, if you were to add a solution to your Answer it would be very good. I get your point and I guess that I've just not seen it from that perspective before. Thanks.
Filip Ekberg
You're right. Sorry I came on rather strong. I've toned down my comments quite a bit. Heinzi gave a good direct answer to your question and I voted for it, so for an actual solution I will simply refer to his answer.
Ray Burns