Binding IsEnabled and other Properties to Public Properties, does it work like Dependency Properties?
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}}"
Howe开发者_StackOverflow中文版ver, 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
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 thePropertyChanged
event after changingIsEverythingLoaded
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); }
}
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:
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.
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.
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.
If done properly, creating a DependencyProperty as a source of data is less code (and simpler) than the corresponding CLR property that supports INotifyPropertyChanged.
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.
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.
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.
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.
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.
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
}
精彩评论