It had been more than two months since my last post, in this post i will discuss about Self Aware Model in WPF .
Generaly in any application it is always convinient if all the data models are aware of being updated or changed by the application user. It will help the application
range from UI interaction to enhance performance. I assumed that you already set up your development environment correctly. For reference of the encvironment setting such as the IDE and required libraries. Please see this post for more information.
The project that represented here contains a object model that not only aware of changes, it also aware that whether itself is a valid model base on user-define business logic, the model validation
will be presented in another post
. I used this post as a reference.
There is some classes that will work together performing Self Aware and Self Validate Model, as the following ( DTO stands for Data Transfer Object ) :
- CommonDTO
- ValidatableDTO
- CommodityValidator
- Commodity
For your information this classes is taken from a simple WPF project that perform simple Create-Retrieve-Update-Delete or CRUD operations, download link to this project can befound at the end of this post.
In this post we will discuss only CommondDTO and Commodity class.
CommonDTO Class
This class implements INotifyPropertyChanged interface which is its main function is to raise an event that can be catch by the application due to properties change in the model itself.
I will not show you all the code due to its size but only will show important parts of it.
The following code is shown the empty CommonDTO class
public class CommonDTO : INotifyPropertyChanged
{
}
In the previous post the INotifyPropertyChanged is already used, the different is that in this project we make the INotifyPropertyChanged implementation into a more general and common implementations.
Instead of implement in through out our application model classes, it is always better to have one common implementation in a shared class.
Every class that implement INotifyPropertyChanged need to have the following method:
[field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged;
The above method will always be called whenever a property of a class that implements INotifyPropertyChanged is changed. [field: NonSerialized] is an annotation that indicate, if there is any serialization process done to the model
the PropertyChanged will be excluded from the serialization process.
The following code is a property that indicate whether the model is dirty or in other word one or more of its properties are changed:
public void CommitChanges()
{
this.HasChanges = false;
}
private bool hasChanges = false;
public bool HasChanges
{
get { return this.hasChanges; }
set { this.hasChanges = value; }
}
The code above methods are user-defined methods, this is only one of many ways to indicate a model is modified or dirty, maybe you can came up with better solution than me
.
The HasChanges property that will store the value of boolean type, where true means the model is modified otherwise is false.
Another method is CommitChanges basicaly just reset the HasChanges value to false.
public static PropertyChangedEventArgs GetPropertyChangedEventArgs(string propertyName)
{
if (String.IsNullOrEmpty(propertyName))
throw new ArgumentException(
"propertyName cannot be null or empty.");
PropertyChangedEventArgs args;
// Get the event args from the cache, creating them
// and adding to the cache if necessary.
lock (typeof(CommonDTO))
{
bool isCached = eventArgCache.ContainsKey(propertyName);
if (!isCached)
{
Debug.WriteLine("Adding new property changed event args.");
eventArgCache.Add(
propertyName,
new PropertyChangedEventArgs(propertyName));
}
else
{
Debug.WriteLine("Property changed event args retrieved from cache.");
}
args = eventArgCache[propertyName];
}
return args;
}
In every property changed event the value of that property is included in the event itself PropertyChangedEventArgs is represent this property values.
Basic function of this method is to return a PropertyChangedEventArgs object, it will return cache one if it is already in the cache
Maybe you are wondering why the property changed event need to be cache, usually is to improve performance of the application itself, especially user interaction.
protected void ValueTo<E>(ref E valueToSet, E newValue, string propertyName)
{
this.VerifyProperty(propertyName);
if (valueToSet == null)
{
if (newValue == null)
{
Debug.WriteLine("First time assignment, newValue was null NO assignment been made to {0}. Method will return immediately.", propertyName);
return;
}
Debug.WriteLine("First time assignment, assignment been made to {0}.", propertyName);
valueToSet = newValue;
this.HasChanges = true;
this.RaisePropertyChanged(propertyName);
}
else
{
if (valueToSet.Equals(newValue))
{
Debug.WriteLine("Assignment, valueToSet has same value as newValue no assignment been made.");
this.HasChanges = false;
}
else
{
Debug.WriteLine("Assignment, assignment been made. {0} value changed from {1} to {2}", propertyName, valueToSet, newValue);
valueToSet = newValue;
this.HasChanges = true;
this.RaisePropertyChanged(propertyName);
}
}
}
The above method will force the type of valueToSet and newValue to be the same, protected void ValueTo indicate generic type usage.
This is the main method that will be used by any class that extends the CommonDTO class this method contain three important parts:
- Property veriication
- Comparing new and old value of the property
- Raise an event if a property is changed
If you noticed that this method will forced to declare a type when using it.
Property verification
This line this.VerifyProperty(propertyName); do a verification on the model`s property name. If the property cannot be found it will print an error message that state which property is not existed.
[Conditional("DEBUG")]
private void VerifyProperty(string propertyName)
{
Type type = this.GetType();
// Look for a public property with the specified name.
PropertyInfo propInfo = type.GetProperty(propertyName);
if (propInfo == null)
{
// The property could not be found,
// so alert the developer of the problem.
string msg = string.Format(
ERROR_MSG,
propertyName,
type.FullName);
Debug.Fail(msg);
}
}
[Conditional("DEBUG")] is indicate the method will be executed only on debug mode, I am not sure whether this annotation is tightly related to the VisualStudio IDE or not.
Comparing new and old value of the property
if (valueToSet == null)
{
if (newValue == null)
{
Debug.WriteLine("First time assignment, newValue was null NO assignment been made to {0}. Method will return immediately.", propertyName);
return;
}
Debug.WriteLine("First time assignment, assignment been made to {0}.", propertyName);
valueToSet = newValue;
this.HasChanges = true;
this.RaisePropertyChanged(propertyName);
}
else
{
if (valueToSet.Equals(newValue))
{
Debug.WriteLine("Assignment, valueToSet has same value as newValue no assignment been made.");
this.HasChanges = false;
}
else
{
Debug.WriteLine("Assignment, assignment been made. {0} value changed from {1} to {2}", propertyName, valueToSet, newValue);
valueToSet = newValue;
this.HasChanges = true;
this.RaisePropertyChanged(propertyName);
}
}
This code basicaly will raise a change event only when newValue is successfully assigned to the valueToSet variable. I think this code is very clear and straight forward
Raise an event if a property is changed
In this last part we will see how to raise an change event when a property is changed.
protected void RaisePropertyChanged(string propertyName)
{
this.VerifyProperty(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
// Get the cached event args.
PropertyChangedEventArgs args =
GetPropertyChangedEventArgs(propertyName);
// Raise the PropertyChanged event.
handler(this, args);
}
this.AfterPropertyChanged(propertyName);
}
As you can see it used the this.PropertyChanged to raise the actual event. this.AfterPropertyChanged is optional, this method will be called after the property changed event occured.
But in this example I put empty implementation of this method. handler(this, args); look this line of code, remind me a lot of how javascript call a function call.
I hope the explanation about how the self aware model is clear enough, you can always play around with the code after downloading it at the end of this post.
Now is the time when we use it on an actual class.
Here come Commodity class
The actual name of the class file is Commodity.cs. The following code is the first thing how to use the CommonDTO:
public class Commodity : ValidatableDTO<CommodityValidator>
Later inside the project you will find that the ValidatableDTO is extending the CommonDTO. The ValidatableDTO only combined the model validation and the model self awareness of properties changes.
CommodityValidator is a validator class specifically to validate the Commodity model. But this will discussed in another post, we can ignore all validation related code for now.
private string name;
public string Name
{
get { return this.name; }
set {
ValueTo<string>(ref this.name, value, "Name");
}
}
- The
ValueTomethod is belong to theCommonDTOclass ref this.nameis the actual instance variable of the sub-class(theCommodityclass)valuenew value that will be assigned to the instance variablethis.nameNameis a property in theCommodityclass
Don’t be confused between Name and name, these are different things, first Name is property name contain getter and setter method (similar to Java Bean concept)
in other hand the name is a private variable which its type is string. So every time there is a changes on any properties on an instance of Commodity class, just check the HasChanges property
it will return true if has changes, it will be false otherwise. You can always look through out the code maybe you have more clearer view about this topic, your suggestion and critics are much appreciated and welcomed.
Download the code. See you next time.
Generated using Markdown 1.0.1

[...] leave a comment » This article explain about how to make self aware model in WPF application. Please see the original post [...]