Raise an Event Whenever a Property's Value Changed

Raise an event whenever a property's value changed?

The INotifyPropertyChanged interface is implemented with events. The interface has just one member, PropertyChanged, which is an event that consumers can subscribe to.

The version that Richard posted is not safe. Here is how to safely implement this interface:

public class MyClass : INotifyPropertyChanged
{
private string imageFullPath;

protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}

protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}

public string ImageFullPath
{
get { return imageFullPath; }
set
{
if (value != imageFullPath)
{
imageFullPath = value;
OnPropertyChanged("ImageFullPath");
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
}

Note that this does the following things:

  • Abstracts the property-change notification methods so you can easily apply this to other properties;

  • Makes a copy of the PropertyChanged delegate before attempting to invoke it (failing to do this will create a race condition).

  • Correctly implements the INotifyPropertyChanged interface.

If you want to additionally create a notification for a specific property being changed, you can add the following code:

protected void OnImageFullPathChanged(EventArgs e)
{
EventHandler handler = ImageFullPathChanged;
if (handler != null)
handler(this, e);
}

public event EventHandler ImageFullPathChanged;

Then add the line OnImageFullPathChanged(EventArgs.Empty) after the line OnPropertyChanged("ImageFullPath").

Since we have .Net 4.5 there exists the CallerMemberAttribute, which allows to get rid of the hard-coded string for the property name in the source code:

    protected void OnPropertyChanged(
[System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}

public string ImageFullPath
{
get { return imageFullPath; }
set
{
if (value != imageFullPath)
{
imageFullPath = value;
OnPropertyChanged();
}
}
}

Raise event when property is changed


Raise event when property is changed

For this scenario, you could create a DependencyPropertyWatcher to detect DependencyProperty changed event. The follow is tool class that you could use directly.

public class DependencyPropertyWatcher<T> : DependencyObject, IDisposable
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(object),
typeof(DependencyPropertyWatcher<T>),
new PropertyMetadata(null, OnPropertyChanged));

public event DependencyPropertyChangedEventHandler PropertyChanged;

public DependencyPropertyWatcher(DependencyObject target, string propertyPath)
{
this.Target = target;
BindingOperations.SetBinding(
this,
ValueProperty,
new Binding() { Source = target, Path = new PropertyPath(propertyPath), Mode = BindingMode.OneWay });
}

public DependencyObject Target { get; private set; }

public T Value
{
get { return (T)this.GetValue(ValueProperty); }
}

public static void OnPropertyChanged(object sender, DependencyPropertyChangedEventArgs args)
{
DependencyPropertyWatcher<T> source = (DependencyPropertyWatcher<T>)sender;

if (source.PropertyChanged != null)
{
source.PropertyChanged(source.Target, args);
}
}

public void Dispose()
{
this.ClearValue(ValueProperty);
}
}

Usage

var watcher = new DependencyPropertyWatcher<string>(this.MyWebView, "Source");
watcher.PropertyChanged += Watcher_PropertyChanged;

private void Watcher_PropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{

}

How to add a PropertyChanged event for a property?

You typically do this by implementing INotifyPropertyChanged. This allows you to use one single event for all the properties. The property name is passed in the event arguments.

partial class AbilityScoreDisplay : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

...
}

In the properties do this (with AbilityModifier as an example):

private int _abilityModifier;
public int AbilityModifier
{
get { return _abilityModifier; }
private set {
if (value != _abilityModifier) {
_abilityModifier = value;
AbilityModifierTextBox.Text = value >= 0
? String.Format("+{0}", value)
: value.ToString();
OnPropertyChanged(nameof(AbilityModifier));
}
}
}

Assuming this event handler

private void ScoreDisplay_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
...
}

You can subscribe the event with

PropertyChanged += ScoreDisplay_PropertyChanged;

You need to use the add/remove syntax only in rare cases. Typically, when you create your own event store, because you have a lot of events and don't want to consume space for unsubscribed events.


You can use INotifyPropertyChanged together with data binding to immediately update the UI when changes are made to the data. To do this you would create a class with properties and the INotifyPropertyChanged implementation. In the form you then assign an instance of this class to the DataSource of a BindingSource. The controls are then bound to this BindingSource.

Then you can drop all the code used to read from or to write to text boxes or labels etc., as the binding mechanism does it automatically for you.

Raise an event in main whenever a variable's value changed in a class in c#?

As other posted you should impement INotifyPropertyChanged, but in addition I would suggest the following as well:

  1. In the setter of your property check whether the value, that is assigned to your property really changes the property's value. Otherwise you probably fire the notify change to often.
  2. You should also implement ISupportInitialize. Usually, you fire the property changed event to inform your main form that data has changed and needs to be saved. But if you load your instances from e.g. a database, the property changed event would also fire, indicating data has changed, which is not true in that sense. With ISupportInitialize you can tell your instances that they are being initialized and that they should not fire the notify property changed event.

Here is some sample code:

class MyTest : INotifyPropertyChanged, ISupportInitialize
{
public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
private bool _IsInitializing;

private bool _MyProperty;
public void BeginInit()
{
_IsInitializing = true;
}

public void EndInit()
{
_IsInitializing = false;
}

public bool MyProperty {
get { return _MyProperty; }
set {
if (_MyProperty == value)
return;

_MyProperty = value;
OnPropertyChanged("MyProperty");
}
}

private void OnPropertyChanged(string propertyName)
{
if (_IsInitializing)
return;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

For initialization you would write (to prevent the property changed event from firering):

MyTest thisTest = new MyTest();
thisTest.BeginInit();
thisTest.MyProperty = true;
thisTest.EndInit();

How to create a property changed event when the property has only a getter in C#

You need something like this:

public class Person : INotifyPropertyChanged
{
private string firstName;
private string lastName;

private void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private bool CheckPopulationRegistry(Person p)
{
// TODO:
return false;
}

public string FirstName
{
get { return firstName; }
set
{
if (firstName != value)
{
firstName = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsRealPerson));
}
}
}

public string LastName
{
get { return lastName; }
set
{
if (lastName != value)
{
lastName = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsRealPerson));
}
}
}

// IdNumber is omitted

public bool IsRealPerson => CheckPopulationRegistry(this);

public event PropertyChangedEventHandler PropertyChanged;

}

C# raise event when property changes in foreign class

Unfortunately due to your constrains your only option is poling to see if the data has changed.

sealed class SomethingChanged : INotifyPropertyChanged, IDisposable
{
private Something sth;
private string _oldName;
private System.Timers.Timer _timer;

public string Name { get { return sth.Name; }

public SomethingChanged(Something Sth, double polingInterval)
{
sth = Sth;
_oldName = Name;
_timer = new System.Timers.Timer();
_timer.AutoReset = false;
_timer.Interval = polingInterval;
_timer.Elapsed += timer_Elapsed;
_timer.Start();
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(_oldName != Name)
{
OnPropertyChanged("Name");
_oldName = Name;
}

//because we did _timer.AutoReset = false; we need to manually restart the timer.
_timer.Start();
}

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var tmp = PropertyChanged; //Adding the temp variable prevents a NullRefrenceException in multithreaded environments.
if (tmp != null)
tmp(this, new PropertyChangedEventArgs(propertyName));
}

public void Dispose()
{
if(_timer != null)
{
_timer.Stop();
_timer.Dispose();
}
}
}

Raising property changed event for an object in another class not working

To propagate changes happening in a "child" component, you would need to subscribe to the child's PropertyChanged event as suggested in this answer.

In your case that could look something like:

public class ClassB : INotifyPropertyChanged
{
// stuff left out for brevity

public ClassB()
{
ClassAObject = new ClassA();

// Subscribe to ClassAObject's event and let subscribers of
// ClassB know that something changed
ClassAObject.PropertyChanged += (sender, eventArgs) =>
{
RaisePropertyChanged(nameof(Property_B));
};
}
}

How to raise a changed event in WPF on property of data item

If you don't want to implement INotifyPropertyChanged in your model classes, then you could create two Date properties on your ViewModel that DO raise the PropertyChanged event.

You could simply map these two properties from your model class in your constructor.

Obviously, you'd have to copy the values back to your model object when you're done. Typically in a 'Save Changes' style of ICommand ;)

How to raise an event when an Bitmap property is changed?

If you want to take the simple route for one property, you add an event, and in the set you invoke it:

public event EventHandler BitmapChanged;

private Bitmap _hostBitmap;
public Bitmap HostBitmap { get => _hostBitmap;
set{
_hostBitmap = value;
BitmapChanged?.Invoke(this, EventArgs.Empty);
}
}

If you want to pass more info about the event you can provide a modified EventArgs subclass and declare the BitmapChanged property type to be EventHandler<YourEventArgsSubclass>

If you have a lot of properties to associate with events, look at implementing INotifyPropertyChanged



Related Topics



Leave a reply



Submit