Reputation: 65
I have an observable collection of Suppliers that I want to load into a gridview and then have users edit any relevant information on the supplier. My issue is I'm not sure how to implement an IsDirty field for each property on the supplier (Model) that can be changed. I have the IsDirty bits created as such
#region SupplierID
private int _SupplierID;
public int SupplierID
{
get
{
return _SupplierID;
}
set
{
if (_SupplierID != value)
{
_SupplierID = value;
OnPropertyChanged("SupplierID");
}
}
}
#endregion
#region Address
private string _Address;
public string Address
{
get
{
return _Address;
}
set
{
if (_Address != value)
{
_Address = value;
IsDirtyAddress = true;
OnPropertyChanged("Address");
}
}
}
public bool IsDirtyAddress{ get; set; }
#endregion
#region City
private string _City;
public string City
{
get
{
return _City;
}
set
{
if (_City != value)
{
_City = value;
IsDirtyCity = true;
OnPropertyChanged("City");
}
}
}
public bool IsDirtyCity { get; set; }
#endregion
#region State
private string _State;
public string State
{
get
{
return _State;
}
set
{
if (_State != value)
{
_State = value;
IsDirtyState = true;
OnPropertyChanged("State");
}
}
}
public bool IsDirtyState { get; set; }
#endregion
#region Zip
private string _Zip;
public string Zip
{
get
{
return _Zip;
}
set
{
if (_Zip != value)
{
_Zip = value;
IsDirtyZip = true;
OnPropertyChanged("Zip");
}
}
}
public bool IsDirtyZip { get; set; }
#endregion
The problem is that when I build the list of suppliers (ViewModel), I actually end up setting the IsDirty bits to true. What is the best way to set my Address, City, State, Zip when creating the supplier without setting the IsDirty bits to true. Do I need an initialization function in my Model?
for (int i = 0; i < dtSupplier.Rows.Count; i++)
{
Supplier s = new Supplier()
{
SupplierID = Convert.ToInt32(dtSupplier.Rows[i]["SupplierID"].ToString()),
Address = dtSupplier.Rows[i]["Address"].ToString(),
City = dtSupplier.Rows[i]["City"].ToString(),
State = dtSupplier.Rows[i]["State"].ToString(),
Zip = dtSupplier.Rows[i]["Zip"].ToString()
};
Suppliers.Add(s);
}
Maybe I'm going about the whole IsDirty approach the wrong way. I just want to know which values actually changed so my SQL update statement will only include the changed values when a user saves. Thanks!
Upvotes: 1
Views: 1516
Reputation: 27019
You need to do a few things:
Loading
. When you are loading the ViewModel, set the Loading
property to true. When finished loading, set it to false. Loading
and do not set IsDirty
flags. Also, even if not in loading state, compare the values to the value in your model and see if they are the same. nameof
(see my example below).IsDirty
flag so make the setter private.Here is a hypothetical example:
public class Model
{
public string Name { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
private readonly Model model;
public ViewModel(Model model)
{
this.model = model;
}
public bool Loading { get; set; }
public bool IsDirtyName { get; private set; }
private string name;
public string Name
{
get
{
return this.name;
}
set
{
if (this.Loading)
{
this.name = value;
return;
}
if (this.model.Name != value)
{
IsDirtyName = true;
OnPropertyChanged(nameof(Name));
}
}
}
private void OnPropertyChanged(string propertyName)
{
// ...
}
public event PropertyChangedEventHandler PropertyChanged;
}
If you pay attention the above design, you do not even need all those IsDirty
flags and IsLoading
etc. You can actually just have one method in your ViewModel that you call during saving and ask it to check and return all the properties that have changed. The ViewModel will compare its own properties against the Model properties and return a dictionary. There are many ways do achieve what you want.
Upvotes: 1
Reputation: 6522
One option is to handle the IsDirty
logic on a different class which will store the original values of the Supplier
object instance. You can then use that class to GetChangedPropertyNames
or check if your object HasChanges
.
class Supplier
{
private string _Address;
public string Address
{
get
{
return _Address;
}
set
{
if (_Address != value)
{
_Address = value;
OnPropertyChanged("Address");
}
}
}
}
class SupplierIsDirtyTracker
{
private Dictionary<string, object> _originalPropertyValues = new Dictionary<string, object>();
private Supplier _supplier;
public void Track(Supplier supplier)
{
_supplier = supplier;
_originalPropertyValues.Add(nameof(Supplier.Address), supplier.Address);
}
public bool HasChanges()
{
return !Equals(_originalPropertyValues[nameof(Supplier.Address)], _supplier.Address);
}
public IEnumerable<string> GetChangedPropertyNames()
{
if(!Equals(_originalPropertyValues[nameof(Supplier.Address)], _supplier.Address))
{
yield return nameof(Supplier.Address);
}
}
}
You can also use Reflection
on your IsDirtyTracker
class to eliminate hardcoding the property names.
Upvotes: 0