Click here to Skip to main content
15,868,141 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Is there a way to call a notifier each time a property or field in a class is changed?

I created a simple demontration class Foo:
A container holds some other classes.
I need a notification if any field in the class or the sub class is changed. So the way in the boat class is not practicable (original class has a lot more fields).

Using reflection would be an option, but it would be great to have something like a strongly typed method (sketeched as method
C
Change<T>(...)
(not working, just to illustrate the forced solution..)

Thanks.

What I have tried:

C#
public static class Foo
{
    public static void TestChange()
    {
        var container = new Container();
        container.car.Model = "Tesla";      // should notify
        container.boat.Model = "Unknown";   // does notify

        Change<Container>(container.car.Model, "Pontiac");
    }
                                                
    public static void Change<T>(object obj, object value) where T : Container
    {
        // should change the given field or property and notify change

        obj = value;               
        NotifyChange();
    }


    public static void NotifyChange()
    {
        throw new System.Exception("Changed.");
    }
    public class Container
    {
        public Car car = new();
        public Boat boat = new();
    }
    public class Car
    {
        public string Model { get; set; }
        public string Owner { get; set; }
        public decimal Price { get; set; }
    }
    public class Boat
    {
        private string model = "";
        public string Model
        {
            get => model;

            set
            {
                model = value;
                NotifyChange();
            }
        }
    }
}
Posted
Updated 30-Nov-20 20:43pm

 
Share this answer
 
v2
Comments
Maciej Los 1-Dec-20 2:06am    
5ed!
BillWoodruff 1-Dec-20 10:26am    
+5 That thread on StackOverflow is a great resource !
Calling some code when Fields change value is not going to happen: change the Fields into Properties.

With individual Properties, you can implement the INotifyPropertyChanged interface in your class, and then modify the 'set methods of Properties to invoke your handlers: see the link Rick posted in the solution above.

The discussion here is valuable for insight into the issues in implementing INotifyPropertyChanged [^]

It does get tedious to implement all the boiler-plate code for each Property you want to monitor ! That's where AOP (aspect oriented programming) [^] is used to automate property change notification: tools like Fody (open source) [^] , and PostSharp (commercial, free limited edition) [^].

AOP tools integrated into C# modify/rewrite your code on the IL level.
 
Share this answer
 
Comments
Maciej Los 1-Dec-20 2:06am    
5ed!
Seems, you don't understand how property change notifier works...

I'd suggest to read Daniel's Pratt answer (and the comments below the answer) in this thread: ObservableCollection<T> in Winforms and possible alternatives - Stack Overflow[^]

Your class can looks like:
C#
public class Car: INotifyPropertyChanged
{
	private string m = string.Empty;
	private string o = string.Empty;
	private decimal p = 0;

    public string Model
	{
		get => m;
		set
		{
			if(value!=m)
			{
				m=value;
				OnPropertyChanged("Model");
			}
		}
	}
    public string Owner
	{
		get => o;
		set
		{
			if(value!=o)
			{
				o=value;
				OnPropertyChanged("Owner");
			}
		}
	}
    
	public decimal Price
	{
		get => p;
		set
		{
			if(value!=p)
			{
				p=value;
				OnPropertyChanged("Price");
			}
		}
	}
	
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler pceh = PropertyChanged;

        if (pceh != null)
		{
			Console.WriteLine($"Registering value change of '{name}' property");
        	pceh(this, new PropertyChangedEventArgs(name));
		}
    }

    public event PropertyChangedEventHandler PropertyChanged;
}


PropertyChanged event will be fired every time, when you change property of Car class via UI. This is how it works.
 
Share this answer
 
Comments
Sni.DelWoods 1-Dec-20 5:23am    
Thanks for your post Maciej. I know how the provided notifier works, but as mentioned that's not the pattern I wanted to use. I was looking for something that works without using the property setter. In my specific case my solution is good enough.
Thank you all for your comments. All concepts are more or less based on changing the setter of the property. That's not what I need.

For my specific case I've created the "dirty" solution using reflection.
(yes, it is not type safe and will crash on missing field... but it can be used on all and everything)
C#
public static void Change<T>(T instance, string field, object value) where T:class
{
   instance.GetType().GetProperty(field).SetValue(instance, value);
   NotifyChange();
}

Usage:
C#
void Test() {
    Change(container.car, "Model", "Pontiac");
}
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900