Fire event on value change of double - c#

I've used INotifyPropertyChanged within a custom class to fire an event when a variable has changed, but I was wondering if there was a simple way to fire an event on a single variable's change, such as a double.
For instance, in a WPF app, if I have
private double a;
in MainWindow.xaml.cs, is there a simple way to fire the event any time a is assigned to?

A field doesn't have any means of tracking changes. In order to make it work, it would need to be a property, and something would need to handle the tracking. That is the purpose of the INotifyPropertyChanged interface.
The normal means of tracking changes to this value would be to implement INotifyPropertyChanged in your class.

If I understand you correctly, you need to create a Setter for a, which then fires the properychange event/custom event instead of encapsulate a into a class.
Something like this:
private double a;
public double A
{
get { return a; }
set { a = value;
firepropertyChange(a);
}
}

Yes (depends), if you wrap your variable access through a property and fire your event on change, and make sure all access to that variable is through the property, like
private double a;
public double PropertyA
{
get
{
return a;
}
set
{
// set value and fire event only when value is changed
// if we want to know when value set is the same then remove if condition
if (a != value)
{
a = value;
PropertyChanged("PropertyA");
}
}
}
// when changing a, make sure to use the property instead...
PropertyA = 5.2;
...otherwise, no

If you are using C# 5.0, you can employ CallerMemberName attribute this way:
class MyData : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged();
}
}
private string _anotherProperty;
public string AnotherProperty
{
get { return _anotherProperty; }
set
{
_anotherProperty = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
}
As you see you just have to call RaisePropertyChanged(); in set for each property, without typing the property names over and over.
Another approach would be to define a ModelBase class:
class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (!Object.Equals(field, value))
{
field = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And then derive your model from ModelBase:
class Conf : ModelBase
{
NodeType _nodeType = NodeType.Type1;
public NodeType NodeType
{
get { return _nodeType; }
set { Set(ref _nodeType, value); }
}
}

Related

Overriding RaisePropertyChanged to execute additional code

In my model i have properties which i want to execute some extra code for when the property gets changed. I want to add the new value and the property name to my database. I also want to keep a list of current alarms (value is equal to true).
public Boolean ActionAlarmLowLow
{
get
{
return _ActionAlarmLowLow;
}
set
{
if (value != this._ActionAlarmLowLow)
{
Boolean oldValue = _ActionAlarmLowLow;
_ActionAlarmLowLow = value;
RaisePropertyChanged("ActionAlarmLowLow", oldValue, value, true);
}
}
}
How can i do this properly?
I am wondering if i should add two lines of code to the property:
DB.Log.addLogItem("ActionAlarmLowLow", value);
AlarmList.UpdateItem("ActionAlarmLowLow", value);
Or if i can somehow extend/override the RaisePropertyChanged and do some extra stuff elsewhere for specific properties. I.e calling something called
RaisePropertyChangedWriteToDbUpdateAlarmList();`
Yes it is quite simple, all you need is to create a base class with INotifyPropertyChanged and call whatever you want inside.
public abstract class NotifyPropertyChangedBase: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> expression)
{
var memberExpression = (MemberExpression) expression.Body;
var propertyName = memberExpression.Member.Name;
var handler = PropertyChanged;
if (handler != null)
{
// Do your common actions here, before property change notification is fired
handler(this, new PropertyChangedEventArgs(propertyName));
// Do your common actions here, after property change notification is fired
}
}
}
public class MyClass : NotifyPropertyChangedBase
{
public Boolean ActionAlarmLowLow
{
get
{
return _ActionAlarmLowLow;
}
set
{
if (value != this._ActionAlarmLowLow)
{
_ActionAlarmLowLow = value;
OnPropertyChanged(() => this.ActionAlarmLowLow);
}
}
}
}

How to implement INotifyPropertyChanged for derived classes?

I have a base class:
public class PersonBaseClass : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
if (value != name)
{
name = value;
NotifyPropertyChanged("Name");
}
}
}
}
and a derived class
public class TeacherClass : PersonBaseClass, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (value != id)
{
id = value;
NotifyPropertyChanged("Id");
}
}
}
}
and this magic code at the end of each one above!
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Then I show a list of Teachers collection in a list in xaml. Now if I change Id, changes will appear for user, but changes in Name which is a property in base class doesn't appear. In debug, I see after setting Name value, the handler inside NotifyPropertyChanged method is null which seems it is the problem.
How can I solve it to changes of base class also appear in the list?
Have only PersonBaseClass implementing INotifyPropertyChanged and make NotifyPropertyChange as protected so you can call it from child classes. There is not need to implement it twice. That should fix the problem as well.
Your "magic code" section should only be in PersonBaseClass. You can make the NotifyPropertyChanged function protected so that the same function can be called from TeacherClass as well.

Wrapping the property setter

I find that I'm repeating myself alot and that is of course no good. So I wondered if I could do something about it. This is a common code in my WPF application:
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged("Name");
}
}
}
So I was wondering if I could wrap the setter somehow to make it better and more readable. One idea was something like this:
protected void PropertySetter<T>(T property, T value, string name)
{
if (EqualityComparer<T>.Default.Equals(property, value))
{
property = value;
OnPropertyChanged(name);
}
}
Usage like this:
private string _name2;
public string Name2
{
get { return _name2; }
set
{
PropertySetter<string>(Name2, value, "Name2");
}
}
But I'm not sure this is really smart or would work as well with Value types?
I guess I'm not the first one to try something like this so if someone knows a good foolproof way to something like this please chime in. I guess I couldn't make the propertyChanged typesafe without reflection but any ideas there would also help.
Yes - this is completely acceptable and normal code.
Here's an example I found that's pretty standardized (I see a lot of this type of usage in code samples).
public event PropertyChangedEventHandler PropertyChanged;
private void SetProperty<T>(ref T field, T value, string name)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Wrap this code inside of a class that implements INotifyPropertyChanged, and inherit your data objects from this class.
In your example, you are calling the event directly - never do this. You could lose the event reference from the time the method starts to the time you call the event. Always create a local cache of the event before invoking it.
Maybe this could help you
public class ObservableObject : INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Protected Methods
protected virtual void SetAndNotify<T>(ref T field, T value, Expression<Func<T>> property)
{
if (!object.ReferenceEquals(field, value))
{
field = value;
this.OnPropertyChanged(property);
}
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> changedProperty)
{
if (PropertyChanged != null)
{
string name = ((MemberExpression)changedProperty.Body).Member.Name;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Usage:
private String _myField;
public String MyProperty
{
get
{ return _myField; }
set
{ SetAndNotify(ref _myField, value, () => MyProperty); }
}
Edit: Your class must inherit from this OservableObject class

How to let a parent class know about a change in its children?

This is an example code:
public class MyParent : INotifyPropertyChanged
{
List<MyChild> MyChildren;
public bool IsChanged
{
get
{
foreach (var child in MyChildren)
{
if (child.IsChanged) return true;
}
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
Let's say I now have two instances of my classes, one as myParent, and the other as myChild.
I have two visual elements, that each have a property bound to the IsChnaged property of my instances; ElementA bound to myParent.IsChanged and ElementB bound to myChild.IsChanged.
When myChild.Value differs from its default value, the myChild.IsChanged is set to true and the ElementB is updated accordingly.
What I need is when either of the myParent children (which here is only one) have their IsChanged value set to true, its own (the parent's) IsChanged value be set to true and its corresponding
element (ElementA here) be updated accordingly.
The myParent.IsChanged is only read once (when the binding is set) and it has no sense about its children changing. Where should i put the RaiseChanged("IsChanged") for MyParent? How can I let the parent know when its children have changed?
Thanks in advance
INotifyPropertyChanged has already provided the mechanism for you: the PropertyChanged event. Just have the parent add a handler to its children's PropertyChanged, and then in that handler call RaiseChanged("IsChanged");
Also, you may want to put the INotifyPropertyChanged implementation in a base class, and have your (what appear to be) ViewModels inherit from that. Not required for this option, of course, but it will make the code a little cleaner.
Update: In the parent object:
// This list tracks the handlers, so you can
// remove them if you're no longer interested in receiving notifications.
// It can be ommitted if you prefer.
List<EventHandler<PropertyChangedEventArgs>> changedHandlers =
new List<EventHandler<PropertyChangedEventArgs>>();
// Call this method to add children to the parent
public void AddChild(MyChild newChild)
{
// Omitted: error checking, and ensuring newChild isn't already in the list
this.MyChildren.Add(newChild);
EventHandler<PropertyChangedEventArgs> eh =
new EventHandler<PropertyChangedEventArgs>(ChildChanged);
newChild.PropertyChanged += eh;
this.changedHandlers.Add(eh);
}
public void ChildChanged(object sender, PropertyChangedEventArgs e)
{
MyChild child = sender as MyChild;
if (this.MyChildren.Contains(child))
{
RaiseChanged("IsChanged");
}
}
You don't actually have to add anything to the child class, since it is already raising the correct event when it changes.
Doing this kind of communication can be tricky, especially if you want to avoid memory leaks due to the event handlers that you hook up. There is also the case of handling items that are added / removed from the collection.
I've really enjoyed the power and simplicity of the Continuous LINQ project on codeplex. It has some very rich features for setting up "Reactive Objects", "Continuous Values", and "Continuous Collections". These let you define your criteria as a Linq expression and then let the CLINQ library keep the underlying values up to date in real time.
In your case, you could set up the parent with a ContinuousFirstOrDefault() linq query that watched for any child where "IsChanged == true". As soon as a child sets the value to true and raises PropertyChanged, the continuous value will detect the change and raise a corresponding PropertyChanged in the parent.
The benefits:
Weak references and weak events are used to prevent the event handlers in the parent from locking the child in memory. It can get very messy to add / remove these handlers from all the children.
You can declare the dependency in the parent without need to make special changes in the child or make the child aware of the parent. Rather, the child just needs to properly implement INotifyPropertyChanged. This puts the "logic" close to the object that cares, rather than spreading event craziness and inter-dependencies all over the code.
Here's what the code might look like:
public class MyParent : INotifyPropertyChanged
{
private ObservableCollection<MyChild> _MyChildren;
private ContinuousValue<MyChild> _ContinuousIsChanged = null;
public MyParent()
{
_MyChildren = new ObservableCollection<MyChild>();
// Creat the ContinuousFirstOrDefault to watch the MyChildren collection.
// This will monitor for newly added instances,
// as well as changes to the "IsChanged" property on
// instances already in the collection.
_ContinuousIsChanged = MyChildren.ContinuousFirstOrDefault(child => child.IsChanged);
_ContinuousIsChanged.PropertyChanged += (s, e) => RaiseChanged("IsChanged");
}
public ObservableCollection<MyChild> MyChildren
{
get { return _MyChildren; }
}
public bool IsChanged
{
get
{
// If there is at least one child that matches the
// above expression, then something has changed.
if (_ContinuousIsChanged.Value != null)
return true;
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
The above code sets up the ContinuousFirstOrDefault in the constructor so that it is always monitoring. However, in some cases you can optimize this by lazily instantiating the ContinuousFirstOrDefault only when the getter for "IsChanged" is called. That way you don't start monitoring for changes until you know that some other piece of code actually cares.
You can simplify things for yourself by storing your children in an ItemObservableCollection<T>, as discussed in this answer. That would allow you to do this:
private ItemObservableCollection<MyChild> children;
public MyParent()
{
this.children = new ItemObservableCollection<MyChild>();
this.children.ItemPropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
if (string.Equals("IsChanged", e.PropertyName, StringComparison.Ordinal))
{
this.RaisePropertyChanged("IsChanged");
}
};
}
Something I do not see in your code sample provide is an actually reference of parent to child. It is not enough to simply have interface to communicate through, but you must also create the reference. Something like myChild.parent = this; followed by the binding of the event handlers across the channel, in the "parent" property of the child object it would look like:
public INotifyPropertyChanged parent
{
get{return _parent;}
set
{
_parent = value;
this.PropertyChanged += _parent.RaiseChanged();
}
}
I don't have enough context to perfect this code for you but this should move you in the right direction.

Injecting (INotifyPropertyChanged functionality) to an instance of an class

I have a class that implements INotifyPropertyChanged.
I create an instance of a class in some viewModel.
Is it possible to remove this functionality from the class and inject it after the instance was created? I heard that ICustomTypeDescriptor would make this happen, but i dont know how to use it.
public class C : ICustomNotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int _id;
public string _name;
public int Id
{
get { return _id; }
set
{
if (_id == value)
{
return;
}
_id = value;
OnPropertyChanged("Id");
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
OnPropertyChanged("Name");
}
}
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
If you are just trying to prevent the notifications from being fired when the object is first created and properties set, you can add boolean flag(s) that is/are false until the properties have been set once. You only execute the notification if the flag is true.
Edit:
I don't think there's a clean way to get the functionality in there after removing all the INotifyPropertyChanged code, but there are many ways to control the functionality from outside the instance.
Please note that I wrote all this code in the text editor, not in VisualStudio; it has not been tested in any way.
Add a method to enable notifications:
public class OptionalNotification : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string name) ...
bool _shouldNotify;
public void EnableNotifications()
{
_shouldNotify = true;
}
string _someProperty;
public string SomeProperty
{
get { return _someProperty; }
set
{
if(_someProperty == value) return
_someProperty = value;
if(_shouldNotify) OnPropertyChanged("SomeProperty");
}
}
}
You could do the same thing without the method, if you knew at the time of instantiation whether or not the instance should produce notifications, in which case you'd just need a boolean parameter in the constructor.
Another variation would be to use the Factory pattern, where your Factory has internal access to the boolean flag and sets it upon construction.
Encapsulate the condition in a proxy:
public interface IEntity : INotifyPropertyChanged
{
string SomeProperty { get; set; }
}
public class Entity : IEntity
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name) ...
string _someProperty;
public string SomeProperty
{
get { return _someProperty; }
set
{
if(_someProperty == value) return
_someProperty = value;
OnPropertyChanged("SomeProperty");
}
}
}
public class EntityNotificationProxy : IEntity
{
IEntity _inner;
public EntityNotificationProxy(IEntity entity)
{
_inner = entity;
_inner.PropertyChanged += (o,e) => { if(ShouldNotify) OnPropertyChanged(o,e); }
}
public bool ShouldNotify { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(object sender, PropertChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null) handler(sender, e);
}
public string SomeProperty
{
get { return _inner.SomeProperty; }
set
{
if(_inner.SomeProperty == value) return
_inner.SomeProperty = value;
}
}
}
Here your consuming classes get the entity proxy instead of the entity itself (but is none the wiser because it references only IEntity when you program to interfaces/abstractions). The wrapping of the proxy can happen in a factory or through an IoC container/DI framework.
The main advantage to this approach is that your entity maintains a pure INotifyPropertyChanged implementation, and the conditional aspect is handled from without. Another advantage is that it helps to enforce programming to abstractions and inversion of control.
The main disadvantage is that you'll need to create proxies for each INotifyPropertyChanged implementation that you want to have this conditional behaviour.
Create a registry to keep track of what instances should or should not raise notifications:
public static class PropertyNotificationRegistry
{
static IDictionary<INotifyPropertyChanged, bool> _registeredClasses
= new Dictionary<INotifyPropertyChanged, bool>;
static void Register(INotifyPropertyChanged o, bool shouldNotify)
{
if(!(_registeredClasses.ContainsKey(o)) _registeredClasses.Add(o, shouldNotify);
// could also implement logic to update an existing class in the dictionary
}
public static void ShouldNotifyWhenPropertiesChange(this INotifyPropertyChanged o)
{
Register(o, true);
}
public static void ShouldNotNotifyWhenPropertiesChange(this INotifyPropertyChanged o)
{
Register(o, false);
}
public static void NotifyPropertyChanged(this INotifyPropertyChanged o, Action notificationAction)
{
if(_registeredClasses.ContainsKey(o))
{
bool shouldNotify = _registeredClasses.Where(x => x.Key == o).Single().Value;
if(shouldNotify) notificationAction();
}
}
}
public class EntityUsingNotificationRegistry : INotifyPropertyChanged
{
... // all the standard INotifyPropertyChanged stuff
string _someProperty;
public string SomeProperty
{
get { return _someProperty; }
set
{
if(_someProperty == value) return;
_someProperty = value;
this.NotifyPropertyChanged(() => OnPropertyChanged("SomeProperty"));
}
}
}
public class SomethingInstantiatingOurEntity
{
public void DoSomething()
{
var entity1 = new EntityUsingNotificationRegistry();
entity1.ShouldNotifyWhenPropertiesChange();
var entity2 = new EntityUsingNotificationRegistry();
entity2.ShouldNotNotifyWhenPropertiesChange();
entity1.SomeProperty = "arbitrary string"; // raises event
entity2.SomeProperty = "arbitrary string"; // does not raise event
var entity3 = new EntityUsingNotificationRegistry();
entity3.SomeProperty = "arbitrary string"; // does not raise event
entity3.ShouldNotifyWhenPropertiesChange();
entity3.SomeProperty = "another arbitrary string"; // now raises event
}
}
Now, the registry has a distinct shortcoming in that it holds references to every instance and will prevent those instances from being picked up by the garbage collector. There may be a solution to this by implementing the registry with WeakReferences, but I'm not up-to-snuff on their usage to recommend a particular implementation.
This will not work. You COULD subclass and inject it, but you would have to change the byte-code to make sure the proper methods are CALLED - and that is the harder method.

Categories

Resources