An abstract class implementing the INotifyPropertyChanging and INotifyPropertyChanged interfaces from System.ComponentModel via specialized get/set accessors.
using LazyINotifyLib;
using LazyINotifyLib.Miscellaneous; // For NewInstanceAsDefaultValueAttribute
using System.ComponentModel; // For DefaultValueAttribute
// ...
public class ApplicationViewModelClass : LazyINotify
{
// Default value is not set
public string? FirstProperty { get => NotifyGet(); set => NotifySet(value); }
// Default value for regular types
[DefaultValue("Default value for the second property")] // Attribute from System.ComponentModel namespace
public string SecondProperty { get => NotifyGet()!; set => NotifySet(value); }
// Default value via Activator.CreateInstance()
[NewInstanceAsDefaultValue(["First argument of the constructor", 2.0])] // Attribute from LazyINotifyLib.Miscellaneous namespace
public DummyClass ThirdProperty { get => NotifyGet()!; set => NotifySet(value); }
public class DummyClass(string FirstConstructorArgument, double SecondConstructorArgument)
{
public string FirstDummyProperty { get; } = FirstConstructorArgument;
public double SecondDummyProperty { get; } = SecondConstructorArgument;
}
}NewInstanceAsDefaultValueAttribute is Attribute class located in the LazyINotifyLib.Miscellaneous namespace.
The target value type of NotifyGet() and NotifySet() methods is dynamic to avoid needless type casts.
Both methods use [CallerMemberName] attribute for the string PropertyName = "" argument to identify target property name without constantly specifying it.
NotifySet()invokesPropertyChangingandPropertyChangedevents.NotifyGet()invokes additionalPropertyGettingevent added fromLazyINotifyLib.Miscellaneousnamespace.The
PropertyGettingevent is a small addition to justify the name of theNotifyGet()method (And just why not).
NotifyGet() and NotifySet() methods also accepts ValueFormattingInstructor delegate as an argument. This delegate is located in the LazyINotifyLib.Miscellaneous namespace. It allows to change the value through a specified method that must return an object?-type value. Alternatively, it can be used as a custom action for additional manipulations before getting/setting a value based on the property name and value to get/set.
Very basic example of said usages:
using LazyINotifyLib;
using System.ComponentModel; // For DefaultValueAttribute
// ...
public class ApplicationViewModelClass : LazyINotify
{
[DefaultValue(10.0)] // Testing property
public double NumberProperty { get => NotifyGet(ValueFormatting: NumberAcquiringNotify); set => NotifySet(value, ValueFormatting: NumberRangeAssertionOnSet); }
private static object? NumberRangeAssertionOnSet(string PropertyName, object? Value)
{
if (Value is double Number)
{
if (Number > 50)
{
Console.WriteLine($"[{DateTime.Now}] Excessive value '{Number}' received for \"{PropertyName}\".");
Number = 50;
}
else if (Number < 0)
{
Console.WriteLine($"[{DateTime.Now}] Insufficient value '{Number}' received for \"{PropertyName}\".");
Number = 0;
}
Value = Number;
}
return Value; // -> actually store by LazyINotify.NotifySet()
}
private static object? NumberAcquiringNotify(string PropertyName, object? Value)
{
Console.WriteLine($"[{DateTime.Now}] The value '{Value}' is returned from the \"{PropertyName}\" property.");
return Value; // -> return from LazyINotify.NotifyGet()
}
}LazyINotify class also contains a protected virtual property PropertyAcknowledgementLevel of type System.Reflection.BindingFlags. This property determines which access level properties should be accessible in NotifyGet / NotifySet. Base value is BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance (public / private / protected access levels).
Example of overriding with permission for only public properties (BindingFlags.Public | BindingFlags.Instance):
using LazyINotifyLib;
using System.Reflection; // For BindingFlags
using System.ComponentModel; // For DefaultValueAttribute
// ...
public class ApplicationViewModelClass : LazyINotify
{
// Overriding with permission for only `public` properties
protected override BindingFlags PropertyAcknowledgementLevel => BindingFlags.Public | BindingFlags.Instance;
[DefaultValue("Default string 1 (public)")] // public property
public string PublicStringProperty { get => NotifyGet(); set => NotifySet(value); }
[DefaultValue("Default string 2 (private)")] // private property
private string PrivateStringProperty { get => NotifyGet(); set => NotifySet(value); }
public void ShowAllData()
{
// [✓] This will work fine
Console.WriteLine($"Public string is: \"{PublicStringProperty}\"");
// [🞩] This will throw an ArgumentException
Console.WriteLine($"Private string is: \"{PrivateStringProperty}\"");
}
}