Using INotifyPropertyChanged is a good alternative to DependencyProperties.
Up vote 0 down vote favorite share g+ share fb share tw.
Maybe a stupid question. I have a lot of existing business objects with many properties and collections inside which I want to bind the userinterface to. Using DependencyProperty or ObservableCollections inside these objects is not an option.
As I know exactly when I modify these objects, I would like to have a mechanism to update all UI controls when I do this. As an extra I also don't know which UI controls bind to these objects and to what properties. Here is a simplified code of what I tried to do by now: public class Artikel { public int MyProperty {get;set;} } public partial class MainWindow : Window { public Artikel artikel { get { return (Artikel)GetValue(artikelProperty); } set { SetValue(artikelProperty, value); } } public static readonly DependencyProperty artikelProperty = DependencyProperty.
Register("artikel", typeof(Artikel), typeof(MainWindow), new UIPropertyMetadata(new Artikel())); public MainWindow() { InitializeComponent(); test. DataContext = this; } private void Button_Click(object sender, RoutedEventArgs e) { artikel. MyProperty += 1; // What can I do at this point to update all bindings?
// What I know at this point is that control test or some of it's // child controls bind to some property of artikel. } } This is, I tried to pack my object into a DependencyProperty and tried to call UpdateTarget on this, but didn't succeed. What could I do to update the corresponding UI controls?
I hope I described my situation good enough. Wpf xaml data-binding update dependency-properties link|improve this question asked Mar 29 '11 at 12:05MTR1958 62% accept rate.
Using INotifyPropertyChanged is a good alternative to DependencyProperties. If you implement the interface you can raise the PropertyChanged event with null as parameter to notify the UI that all properties changed.
Thank you, I didn't think about that. I tried it and it works for simple properties, but it doesn't work for a List property with . I add new listitems and the UI doesn't show them.
– MTR Mar 29 '11 at 12:51 Collections need to implement INotifyCollectionChanged changed for the bindings to update on their own if you add items, ObservableCollection would be the standard implementation which you appear to know already. – H.B. Mar 29 '11 at 12:57 Yes, but I can't change my collections in Artikel to ObservableCollection. – MTR Mar 29 '11 at 13:00 +1 since whilst my answer covers the case where it's not possible to modify the data source, using INotifyPropertyChanged and INotifyCollectionChanged is certainly preferable.
– El Zorko Mar 29 '11 at 13:04 @MTR I suspected as much, not sure how I would approach the situation but your class seems useless for binding so I would probably create a class BindableArtikel which is a duplicate of it which implements all the interfaces and transfer all the data if that is not too bad in terms of performance. Of course you would need to transfer if you need to hand out Artikels again at some point. – H.B. Mar 29 '11 at 13:12.
(I'm going to assume you can't add INotifyPropertyChanged to your business objects either, and that you don't want to add another "view of the data model" layer of wrapper objects a la MVVM. ) You can manually update bound properties from their data source by calling BindingExpression.UpdateTarget(). MyTextBlock.
GetBindingExpression(TextBlock. TextProperty).UpdateTarget(); To update all bindings on a control or window, you could use something like this: using System.Windows. Media; ... static void UpdateBindings(this DependencyObject obj) { for (var i=0; I GetChildrenCount(obj); ++i) { var child = VisualTreeHelper.
GetChild(obj, i); if (child is TextBox) { var expression = (child as TextBox). GetBindingExpression(TextBox. TextProperty); if (expression!
= null) { expression.UpdateTarget(); } } else if (...) { ... } UpdateBindings(child); } } If you're binding a diverse set of properties then rather than handling them individually as above, you could combine the above with this approach to enumerate all dependency properties on a control and then get any BindingExpression from each; but that relies on reflection which will not be particularly performant. As a footnote, you can also use BindingExpression.UpdateSource() if you want to explicitly write back to the data source. Controls usually do this anyway when their value changes or when they lose focus, but you control this and do it by hand with {Binding Foo, UpdateSourceTrigger=Explicit}.
Doing things like that is not a very good idea because you do not have access to the internal binding mechanims of the framework which means things get very complicated. I'd imagine that this code does not even work properly because it assumes everything to be a TextBox which hardly covers everything. And if you try to make that method completely generic I think you will end up with an algorithm that has the complexity of O(n^3), which is quite insane.
– H.B. Mar 29 '11 at 12:36 No, this is O(n) where n is the number of controls. The "..." are indeed placeholders where other bound properties may be added. I'm not claiming it's a tasteful solution, and in an ideal world the data source objects would notify the bound controls when their properties change; but in some situations this just isn't plausible and a more pragmatic - if ugly - solution may be required.
Now if you have a solution which is less ugly and doesn't require changes in or to the data source, I'm sure the OP would be interested to hear it. – El Zorko Mar 29 '11 at 12:42 I was talking about the complexity of a completely generic method which is higher, since every control has a certain amount of dependency properties, there is no proper O-notation for this but you need to iterate over all controls and whitin each iteration you need to iterate over all dps of the control (and even beyond because there are also attached dps), O(n^3) would be an overstatement, it's more like O(n^2) I guess. – H.B. Mar 29 '11 at 12:49 I think I can make a container object wich implements INotifyPropertyChanged.
But I will also look into this UpdateBindings function, maybe I can do this for all elements not just TextBox. – MTR Mar 29 '11 at 12:55 @H.B. I certainly take your point that the most generic solution may not be very performant; I've edit the answer accordingly. But there is proper O-notation for this; it's O(n) where n is the number of controls, since O-notation is an indicator of complexity, not performance.
– El Zorko Mar 29 '11 at 13:00.
As I know exactly when I modify these objects, I would like to have a mechanism to update all UI controls when I do this. You will find that the most straightforward and maintainable way to deal with this is to implement view model classes for each class you want to present in the UI. This is probably true if you can modify the underlying classes, and almost certainly true if you can't.
You don't need to be using dependency properties for this. Dependency properties are only necessary on the targets of binding, which is to say the controls in the UI. Your view model objects are the source; they need only implement INotifyPropertyChanged.
Yes, this means that you will need to build classes that contain a property for each property exposed in the UI, and that those classes will need to contain observable collections of child view models, and you'll have to instantiate and populate those classes and their collections at runtime. This is generally not as big a deal as it sounds, and it may be even less of one in your case. The traditional way to build a view model that's bound to a data model is to build properties like this: public string Foo { get { return _Model.
Foo; } set { if (value! = _Model. Foo) { _Model.
Foo = value; OnPropertyChanged("Foo"); } } } But if, as you've claimed, you know when the objects are being updated, and you just want to push the updates out to the UI, you can implement read-only properties, and when the underlying data model gets updated make the view model raise PropertyChanged with the PropertyName property of the event args set to null, which tells binding, "Every property on this object has changed; update all binding targets.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.