Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

INotifyPropertyChanged and static properties

Tags:

I'm tying myself in knots over a simple problem. I have a class that implements INotifyPropertyChanged. Some of the instance properties' getters use static properties and thus their values may change if the static property changes? Here's a simplified example.

class ExampleClass : INotifyPropertyChanged {      private static int _MinimumLength = 5;     public static int MinimumLength     {         get         {             return _MinimumLength;         }         set         {             if (_MinimumLength != value)             {                 _MinimumLength = value;                 //WHAT GOES HERE             }         }     }      private int _length = -1;     public int length     {         get         {             return (_length > _MinimumLength) ? _length : _MinimumLength;         }         set         {             var oldValue = (_length > _MinimumLength) ? _length : _MinimumLength;             if (_length != value)             {                 _length = value;                 var newValue = (_length > _MinimumLength) ? _length : _MinimumLength;                 if (newValue != oldValue)                 {                     OnPropertyChanged("length");                 }             }         }     }      public event PropertyChangedEventHandler PropertyChanged;      [NotifyPropertyChangedInvocator]     protected virtual void OnPropertyChanged(string propertyName)     {         if (PropertyChanged != null)         {             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));         }     }  } 

Clearly if the static property MinimumLength changes then every instance's property length may also change. But how should the static property signal the possible change to the instances? It cannot call OnPropertyChanged since that is not static.

I could keep a list at the class level of all the instances and call a method on each one, but somehow that feels like overkill. Or I could pull the static properties out into a singleton class but logically they live at the class level. Is there an established pattern for this or should I be thinking about this differently?

like image 573
dumbledad Avatar asked Jan 30 '13 21:01

dumbledad


People also ask

What is INotifyPropertyChanged?

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed. For example, consider a Person object with a property called FirstName .

How do you implement INotifyPropertyChanged?

To implement INotifyPropertyChanged you need to declare the PropertyChanged event and create the OnPropertyChanged method. Then for each property you want change notifications for, you call OnPropertyChanged whenever the property is updated.

How to use INotifyPropertyChanged event in WPF?

INotifyPropertyChanged works on instance properties. One solution is to use a singleton pattern and keep INotifyPropertyChanged, the other is to use your own event to notify listeners. EDIT: In WPF 4.5, they introduced property changed mechanic for static properties: You can use static properties as the source of a data binding.

How to fix INotifyPropertyChanged does not work?

But this time, INotifyPropertyChanged does not work. Any solution? INotifyPropertyChanged works on instance properties. One solution is to use a singleton pattern and keep INotifyPropertyChanged, the other is to use your own event to notify listeners.

How should the static property signal changes to the instance's property length?

Clearly if the static property MinimumLength changes then every instance's property length may also change. But how should the static property signal the possible change to the instances? It cannot call OnPropertyChanged since that is not static.

What is the difference between INotifyPropertyChanged and dependencyproperty?

Using INotifyPropertyChanged is sometimes more flexible than using DependencyProperty. Let me explain that. When you build a screen on which a lot of controls visibility dependsof some rules, you may declare a boolean which value is computed from other boolean.


2 Answers

If you're inclined to maintain that design then I would go with a solution like the following:

public static int MinimumLength {     get { return _MinimumLength; }     set     {         if (_MinimumLength != value)         {             _MinimumLength = value;             OnGlobalPropertyChanged("MinimumLength");         }     } } static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { }; static void OnGlobalPropertyChanged(string propertyName) {     GlobalPropertyChanged(         typeof (ExampleClass),          new PropertyChangedEventArgs(propertyName)); } public ExampleClass() {     // This should use a weak event handler instead of normal handler     GlobalPropertyChanged += this.HandleGlobalPropertyChanged; } void HandleGlobalPropertyChanged(object sender, PropertyChangedEventArgs e) {     switch (e.PropertyName)     {         case "MinimumLength":             if (length > MinimumLength)                 length = MinimumLength;             break;     } } 

This is pretty much equivalent to maintaining a list of instances but I find it more maintainable and clearer. Also, you really need to use a weak event handler strategy, otherwise, your instances will not be garbage collected because they will always be associated with the static event which acts like a GC root.

You can read more about weak event handlers in the following blog posts (which were written by me so I'm biased):

.NET Weak Event Handlers – Part I

.NET Weak Event Handlers – Part I

In an unrelated note your code is currently firing property changed when in fact the property value did not change. For example:

  1. Set MinimumLength to 5;
  2. Set length to 10; (event fires since the value changes from the default 0 to 5)
  3. Set length to 11; (event fires but it should not since the length is still 5)
like image 198
João Angelo Avatar answered Oct 04 '22 07:10

João Angelo


You could use the technique mentioned in Binding static property and implementing INotifyPropertyChanged but also raise a notification against "length", e.g.

class ExampleClass : INotifyPropertyChanged {     private static int _MinimumLength = 5;      public int MinimumLength     {         get         {             return _MinimumLength;         }         set         {             if (_MinimumLength != value)             {                 _MinimumLength = value;                  OnPropertyChanged("MinimumLength");                 OnPropertyChanged("length");             }         }     }     ... } 
like image 22
Phil Avatar answered Oct 04 '22 07:10

Phil