Question

Thanks to Marc Gravell's awesome answer I was able to implement property change tracking within my class. However, when the object is first initialized and the properties set for the first time all the properties are being marked as dirty. What would be the best way to handle the initial setting of the properties so that they are not marked dirty when first loading the object?

So when ExtendedFieldDto properties are first set dirtyProperties always has a count equal to the properties of the inheriting class, in this case ExtendedFieldDto.

public abstract class NotifyPropertyChanged {
    public IDictionary<string, object> dirtyProperties { get; private set; }

    protected NotifyPropertyChanged() {
        dirtyProperties = new Dictionary<string, object>();
    }

    protected void setProperty<T>(ref T property, T value, string propertyName) {
        if (!EqualityComparer<T>.Default.Equals(property, value)) {
            property = value;
            if (dirtyProperties.Keys.Contains(propertyName))
                dirtyProperties[propertyName] = property;
            else
                dirtyProperties.Add(propertyName, property);
        }
    }
}

public class ExtendedFieldDto : NotifyPropertyChanged {
    private string _id;
    public string id {
        get { return _id; }
        set { setProperty(ref _id, value, "id"); }
    }

    private int _idLocation;
    public int idLocation {
        get { return _idLocation; }
        set { setProperty(ref _idLocation, value, "idLocation"); }
    }

    private string _columnName;
    public string columnName {
        get { return _columnName; }
        set { setProperty(ref _columnName, value, "columnName"); }
    }

    private string _description;
    public string description {
        get { return _description; }
        set { setProperty(ref _description, value, "description"); }
    }

    private string _help;
    public string help {
        get { return _help; }
        set { setProperty(ref _help, value, "help"); }
    }
}

The dto is currently being used as a proprety on an aspx page where I'm storing the object in ViewState (a requirement from the legacy code). So I'm not sure how I would use the constructor for ExtendedFieldDto to set the private properties with this type of implementation.

private ExtendedFieldDto extendedField {
    get {
        if (ViewState[EXTENDED_FIELD_VIEWSTATE_KEY] == null)
            ViewState[EXTENDED_FIELD_VIEWSTATE_KEY] = new ExtendedFieldDto();
        return (ExtendedFieldDto)ViewState[EXTENDED_FIELD_VIEWSTATE_KEY];
    }
    set { ViewState[EXTENDED_FIELD_VIEWSTATE_KEY] = value; }
}
Was it helpful?

Solution

This is one of a number of common problems for which the ISupportInitialize interface was created.

public abstract class NotifyPropertyChanged : ISupportInitialize {
   ...
   public void BeginInit() { }
   public void EndInit() { PropertyChangedObserver(); }
}

and you use it like this:

ExtendedFieldDto foo = new ExtendedFieldDto();
foo.BeginInit();
foo.id = "abc123";
foo.idLocation = 0;
...
foo.EndInit();

EDIT: You might also think about implementing INotifyPropertyChanged while you're at it, since you're already most of the way there.

OTHER TIPS

I had a very similar problem once. The idea of using a ctor did not work for me, because the object was created and initialized by XML deserialization.

The rather ugly solution I used was a pseudo-global initializing bool variable (thread-static variable, http://msdn.microsoft.com/library/system.threadstaticattribute%28v=vs.110%29.aspx). Before deserializing the data I set that bool to true and after deserialization completed I reset it to false (using a try-finally construct to be safe). In my PropertyChanged handlers I checked that bool. If it was true, I just did not fire my events.

That is a very ugly solution. I even don't like calling it a solution at all, because of the check of that bool variable every time the PropertyChanged handler is called. It is not a clean or save approach, as you must be sure to only set that bool during initialization and you must be sure to reset it afterwards. But it worked for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top