I wanted to share a quick syntax trick I’m using to send property change notifications in a Windows Phone 7.1 application. As you already know, the Mango release of Windows Phone introduce local database storage using SQL Compact Edition and Linq-To-SQL.
In the MSDN documentation Local Database Best Practices for Windows Phone, you can find the following recommendation:
“Minimizing Memory Usage
LINQ to SQL change tracking works by maintaining two copies of each object (…)
By default, LINQ to SQL will create the two copies of the object when the objects are materialized. Frequently, however, only a handful of objects in the materialized collection will actually get modified within a specific transaction. In this case, there is no reason to keep a second copy of the object.
The INotifyPropertyChanging interface allows the application to notify the DataContext when it is modifying a property that will ultimately be submitted as an update to the database. The DataContext can use that notification as a trigger to create the copy. This way, only the items that are actually changing need to be duplicated.”
It means that to optimize memory usage, your model class should implement both the INotifyPropertyChanged and INotifyPropertyChanging interface. Memory usage is an important aspect, especially on mobile device ! On the Windows Phone platform the certification requires your app to use less than 90MB of memory.
So you’ll probably end up creating a base class for all your model, maybe something like this EntityBase:
public class EntityBase : INotifyPropertyChanged, INotifyPropertyChanging
{
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
protected void RaisePropertyChanged(string propertyName)
{
if (propertyName == null)
throw new ArgumentNullException("propertyName");
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected void RaisePropertyChanging(string propertyName)
{
if (propertyName == null)
throw new ArgumentNullException("propertyName");
if (this.PropertyChanging != null)
this.PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
And you’ll define a property like the following
public string Title
{
get
{
return this.title;
}
set
{
if(this.title != value)
{
this.RaisePropertyChanging("Title");
this.title = value;
this.RaisePropertyChanged("Title");
}
}
}
Because I’m not a big fan of this syntax (property name is duplicated, and it’s easy to use either the first call or the second one…), I tried to find another solution. Here is my proposal
public string Title
{
get
{
return this.title;
}
set
{
if(this.title != value)
{
using (this.NotifyChange("Title"))
{
this.title = value;
}
}
}
}
This syntax is based on the using operator and the IDisposable interface. The IDisposable interface used to be implemented by objects which must explicitly release resources when they are no longer needed. But you can use it for any other reason and benefit the using operator !
Here is the additional code in my EntityBase class:
protected IDisposable NotifyChange(params string[] propertyNames)
{
return new PropertyChange(this, propertyNames);
}
private class PropertyChange : IDisposable
{
private ModelEntityBase entity;
private readonly string[] propertyNames;
public PropertyChange(ModelEntityBase entity, string[] propertyNames)
{
this.entity = entity;
this.propertyNames = propertyNames;
foreach (var propertyName in propertyNames)
{
this.entity.RaisePropertyChanging(propertyName);
}
}
public void Dispose()
{
foreach (var propertyName in propertyNames)
{
this.entity.RaisePropertyChanged(propertyName);
}
this.entity = null;
}
}
Not that if setting your property might invalidate other properties as well, you can give more than one parameter to the NotifyChange method.
Hope this helps !
Nice trick, I like the idea of the disposable PropertyChanged object! The only problem is that you still need to manually check if the value has changed. Here’s another approach:
public string Title
{
get
{
return this.title;
}
set
{
SetProperty(ref title, value, "Title");
}
}
protected void SetProperty(ref T backingField, T newValue, string propertyName)
{
if (!Equals(backingField, newValue))
{
backingField = newValue;
OnPropertyChanged(propertyName);
}
}
Thomas,
Thanks for the feedback ! I think I’m going to combine our approach 🙂
We could also use Expression tree to remove the hard-coded string but it’s already enough for me !
And of course you also need to raise the PropertyChanging event, I forgot it when I copied/pasted the method 😉