Skip to content

A source generated approach, to turn your backing fields into properties that can fire events.

License

Notifications You must be signed in to change notification settings

thomhurst/NotifyValueChanged

Repository files navigation

NotifyValueChanged - Automatic Event Firing on Property Value Changes

A source generated approach, to turn your backing fields into properties that can fire events when their value changes - Automagically!

nuget Codacy Badge CodeFactor

Support

If this library helped you, consider buying me a coffee

Buy Me A Coffee

Installation

Install via Nuget Install-Package TomLonghurst.Events.NotifyValueChanged

Features

  • Auto-generated properties for backing fields that fire events
  • Events that fire for computed properties
  • Events that fire for specific types
  • Events that fire for any type
  • Custom property names
  • Custom accessors for property getters and setters

Example

This small class will generate this class!

Usage

Fields

  • Make your class partial
  • Declare a private field - This is the backing field for which the property will be generated for.
  • Add the [NotifyValueChange] attribute to the field
  • That's it!
public partial class Person
{
    [NotifyValueChange]
    private string _name;
}

Your class now has a property called Name - And you can subscribe to an event called OnNameValueChange that will fire whenever the value of Name changes.

You can do this for multiple fields, and each one should generate you a separate event that you can subscribe to called On{PropertyName}ValueChange

var person = new Person();

person.OnNameValueChange += (sender, eventArgs) =>
{
    Console.WriteLine($"Name was: '{eventArgs.PreviousValue}' and is now '{eventArgs.NewValue}'\n");
};

person.Name = "Tom"; // Event will fire and log to the console "Name was: '' and is now 'Tom'"
person.Name = "Tom"; // No event will fire because the value hasn't changed
person.Name = ""; // Event will fire and log to the console "Name was: 'Tom' and is now ''"

NotifyValueChangeAttribute Options

PropertyName - Define a custom property name to be generated for your backing field

    [NotifyValueChange(PropertyName = "FamilyName")]
    private string _lastName;

Outputs

public String FamilyName { get { ... }; set { ... }; }

GetterAccessLevel and SetterAccessLevel - Define custom accessors for your generated properties

    [NotifyValueChange(GetterAccessLevel = PropertyAccessLevel.PrivateProtected, SetterAccessLevel = PropertyAccessLevel.Internal)]
    private string _middleName;

Outputs

  internal String MiddleName { private protected get { ... }; set { ... }; }

Computed Properties

If you have a property that has its value computed based on the value of a backing field with a [NotifyValueChange] attribute, then this should automatically produce an event to subscribe to also. This event will fire when any of the backing fields' values change.

public partial class Person
{
    [NotifyValueChange]
    private string _firstName;
    
    [NotifyValueChange]
    private string _lastName;
    
    public string FullName => $"{_firstName} {_lastName}";
}
var person = new Person 
{
    FirstName = "Tom",
    LastName = "Jones"
};

person.OnFullNameValueChange += (sender, eventArgs) =>
{
    Console.WriteLine($"The Person's Full Name was: '{eventArgs.PreviousValue}' and is now '{eventArgs.NewValue}'\n");
};

person.LastName = "Longhurst"; // Will output The Person's Full Name was: 'Tom Jones' and is now 'Tom Longhurst'

Interfaces

If your class implements an interface and you want this event to be exposed on the interface, then:

  • Make your interface partial
  • Declare the property on the interface as normal
  • Add the attribute [GenerateInterfaceValueChangeEvent]
public partial interface IPerson
{
    [GenerateInterfaceValueChangeEvent]
    public string Name { get; }
}

Class Attributes

NotifyAnyValueChange

Any field with the [NotifyValueChange] attribute will also fire an any value changed event

[NotifyAnyValueChange]
public partial class Person
{
    [NotifyValueChange]
    private string _name; // Will fire the AnyValueChange event because it has the NotifyValueChange attribute
    
    [NotifyValueChange]
    private int _age; // Will fire the AnyValueChange event because it has the NotifyValueChange attribute
}
var person = new Person();

person.OnAnyValueChange += (sender, eventArgs) =>
{
    Console.WriteLine($"Property Name: {eventArgs.PropertyName} | Previous Value: {eventArgs.PreviousValue} | New Value: {eventArgs.NewValue}\n");
};

NotifyTypeValueChange

Any field with the [NotifyValueChange] attribute will also fire an type specific value changed event if that type was passed into the [NotifyTypeValueChange(type)] attribute

[NotifyTypeValueChange(typeof(string))]
public partial class Person
{
    [NotifyValueChange]
    private string _name; // Will fire the OnTypeStringValueChange event because it has the NotifyValueChange attribute combined with the NotifyTypeValueChange(string) attribute
    
    [NotifyValueChange]
    private int _age; // Will not fire the OnTypeStringValueChange event because it is not a string
}
var person = new Person();

person.OnTypeStringValueChange += (sender, eventArgs) =>
{
    Console.WriteLine($"Property Name: {eventArgs.PropertyName} | Previous Value: {eventArgs.PreviousValue} | New Value: {eventArgs.NewValue}\n");
};

About

A source generated approach, to turn your backing fields into properties that can fire events.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published