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!
You need to do a few things:
Add a flag to your ViewModel and name it Loading. When you are loading the ViewModel, set the Loading property to true. When finished loading, set it to false.
Pass your model to your ViewModel but do not expose it. Simply store it in your ViewModel.
When the property is set, check if the ViewModel is in state 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.
Do not use hardcoded strings because it is easy to make a mistake. Use nameof (see my example below).
Do not let other people from outside set the IsDirty flag so make the setter private.
I am pretty sure there are libraries that do this already but I do not know of any so perhaps someone else can chime in.
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.
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.
This is my model structure from which I want to use to create a treeview, with checkboxes on leaf nodes:
public class CategoryEntity : BaseEntity
{
public CategoryEntity()
: base()
{
}
private Guid _categoryId;
public Guid CategoryId
{
get { return _categoryId; }
set { _categoryId = value; InvokePropertyChanged("CategoryId"); IsDirty = true; }
}
private string _categoryname;
public string CategoryName
{
get { return _categoryname; }
set { _categoryname = value; InvokePropertyChanged("CategoryName"); IsDirty = true; }
}
private string _categorydescription;
public string CategoryDescription
{
get { return _categorydescription; }
set { _categorydescription = value; InvokePropertyChanged("CategoryDescription"); IsDirty = true; }
}
private string _categorytype;
public string CategoryType
{
get { return _categorytype; }
set { _categorytype = value; InvokePropertyChanged("CategoryType"); IsDirty = true; }
}
private Guid? _parentcategoryId;
public Guid? ParentCategoryId
{
get { return _parentcategoryId; }
set { _parentcategoryId = value; InvokePropertyChanged("ParentCategoryId"); IsDirty = true; }
}
}
The problem is that I am new to MVC and I don't know which controls to use to display this values in a tree structure. Can anyone suggest a way of doing this?
please tell me best way to implement many duplicate INotifyPropertyChanged.
I have a MainClass that has 10 children, every child has six field and every field must fired property change when own value changed.
this my code but not work:
public class BaseModel
{
public string S1 { get; set; }
public string S2 { get; set; }
public string S3 { get; set; }
public string S4 { get; set; }
public string S5 { get; set; }
public string S6 { get; set; }
}
and I use a class named ViewModelBase to implement INotifyPropertyChanged.
in second step use a class to implement duplicate INotifyPropertyChanged:
public class ImplementBaseModel : ViewModelBase
{
private readonly BaseModel _baseModel;
public ImplementBaseModel()
{
_baseModel = new BaseModel();
}
public string S1
{
get { return _baseModel.S1; }
set
{
if (_baseModel.S1 == value)
return;
_baseModel.S1 = value;
base.OnPropertyChanged("S1");
}
}
public string S2
{
get { return _baseModel.S2; }
set
{
if (_baseModel.S2 == value)
return;
_baseModel.S1 = value;
base.OnPropertyChanged("S2");
}
}
// other code...
}
then a model has 10 of this class:
public class MidClass
{
public ImplementBaseModel ImplementBaseModel1 { get; set; }
public ImplementBaseModel ImplementBaseModel2 { get; set; }
// other field
public ImplementBaseModel ImplementBaseModel10 { get; set; }
public MidClass()
{
ImplementBaseModel1 = new ImplementBaseModel();
ImplementBaseModel2 = new ImplementBaseModel();
// ....
ImplementBaseModel10 = new ImplementBaseModel();
}
}
OK finish code! now please tell me why some property not fired when value change? is a best way to implement this code?
In your setters, you never actually set the value. Use:
public string S1
{
get { return _baseModel.S1; }
set
{
if (_baseModel.S1 == value)
return;
baseModel.S1 = value;
OnPropertyChanged("S1");
}
}
Note that I removed the base from OnPropertyChanged. It isn't normal to invoke the PropertyChanged event in this way.
All NotifyPropertyChanged does is cause every binding to perform a "get" on their bound property. If the backing field is never updated, they will just get the same data.
as a shortcut, you could also create a local method like
bool UpdateAndRaiseIfNecessary( ref string baseValue, string newValue, [CallerMemberName] string propertyName = null)
{
if (baseValue != newValue)
{
baseValue = newValue;
OnPropertyChanged( propertyName );
return true;
}
return false;
}
and then all of the setters would be like this:
set
{
this.UpdateAndRaiseIfNecessary( ref _baseModel.S1, value );
}
I have some problem with Emit mapper when I try to save in database properties.
In first I mapped this class (it work good):
[Serializable]
public class ProfileProperty
{
public string PropertyValue { get; set; }
public bool IsVisible { get; set; }
public ProfileProperty(string value, bool isVisible = true)
{
this.PropertyValue = value;
this.IsVisible = isVisible;
}
public ProfileProperty()
{
this.IsVisible = true;
}
}
I mapped here:
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<PollmericaProfile, ProfileModel>();
ProfileModel prof = new ProfileModel();
if (x.User != null)
{
prof = mapper.Map(x);
}
But some of the requirements need not a string property. That's why I decided to write this:
[Serializable]
public class ProfileProperty
{
public object PropertyValue { get; set; }
public bool IsVisible { get; set; }
public ProfileProperty(object value, bool isVisible = true)
{
this.PropertyValue = value;
this.IsVisible = isVisible;
}
public ProfileProperty()
{
this.IsVisible = true;
}
public T GetValue<T>()
{
return (T)this.PropertyValue;
}
}
And all mapping is not worked =(
If you ccan, help me please. If you want I can provide the necessary information.
P.S. To be honest, I want to transfer to a string and back, so at least works
UPD: I tried without method public T GetValue<T>()... It works...
Sorry for this, but I find answer very quicly.
in mapping I must to write this:
var mapper = ObjectMapperManager
.DefaultInstance
.GetMapper<PollmericaProfile, ProfileModel>( new DefaultMapConfig()
.IgnoreMembers<PollmericaProfile, ProfileModel>(new string[] { "GetValue" }));
ProfileModel prof = new ProfileModel();
if (x.User != null)
{
prof = mapper.Map(x);
}
Let me explain my question by posing a hypothetical situation. Lets start with a class:
public class PaymentDetails
{
public int Id {get;set;}
public string Status {get;set;}
}
And then I have another class:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public PaymentDetails MyPaymentDetails{ get { return _paymentDetails; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
OK, so I have these two classes. PaymentHelper has made the property MyPaymentDetails read-only.
So I cannot instantiate PaymentHelper and modify MyPaymentDetails like this:
PaymentHelper ph = new PaymentHelper();
ph.MyPaymentDetails = new PaymentDetails(); // Not allowed!!!
But I can modify the public properties inside of ph.MyPaymentDetails like this:
ph.MyPaymentDetails.Status = "Some status"; // This is allowed
How do I prevent that from working? Or is there no good way of doing that?
A property may apply access modifiers to individual accessors, for instance:
public string Status { get; private set; }
The scope of access is left to your circumstance. Keeping it private, I'm sure you can tell, will mean only elements within the scope of the current class can use the setter, protected would allow inheritors to use it, etc.
Obviously your classes need to be engineered properly from the bottom up, so as to account for appropriate scoping and robust management when used further up the hierarchy.
The idea of protecting the properties of a complex type that is itself a property isn't available from a language construct at that level.
One option is to design the contained type in such a way as to make its properties read-only using the access modifiers (public set, protected set, private set, etc).
My preference is to expose it as an interface to public consumers:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public IPaymentDetails MyPaymentDetails{ get { return _paymentDetails; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
interface IPaymentDetails
{
int Status { get; }
}
Code inside the PaymentHelper class can then use the PaymentDetails class directly, and code outside the class won't be able to use PaymentDetails unless they cast directly to it, which you can stop if you don't release the PaymentDetails class and only provide the interface.
Of course, you can never really stop the determined person who may use reflection to set things. I tend to let these people break the code :-)
Another solution is not to expose the PaymentDetails object directly, but rather wrap the properties you wish to expose. For example:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public string PaymentDetailsStatus { get { return _paymentDetails.Status; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
Edit: You could always let the behavior of value types take care of this for you. Change PaymentDetails to a struct instead of a class:
public struct PaymentDetails
{
public int Id { get; set; }
public string Status { get; set; }
}
public class PaymentHelper
{
public PaymentDetails Details { get; set; }
}
If you then try to
ph.Details.Status = "Some status"; //
You'll get a compiler error telling you that you can't do this. Since value types are returned, well, by value, you can't modify the .Status property.
Or...
If PaymentDetails and PaymentHelper are declared in the same class library (separate from the code you want to prevent from writing to the .MyPaymentDetails property, you could use:
public class PaymentDetails
{
public int Id { get; internal set; }
public string Status { get; internal set; }
}
public class PaymentHelper
{
public PaymentDetails Details { get; private set; }
}
which will prevent anything declared outside of that class library from writing to .Id or .Status.
Or, force access to .Id and .Status to go through the helper class instead of allowing read access to a .Details property:
public class PaymentHelper
{
private PaymentDetails _details;
public string Id { get { return _details.Id; } private set { _details.Id=value; } }
public string Status { get { return _details.Status; } private set { _details.Status = value; } }
}
Of course, if you're going to do that, you could just
public calss PaymentDetails
{
public int Id { get; protected set; }
public string Status { get; protected set; }
}
public class PaymentHelper : PaymentDetails
{
}
... assuming that this sort of inheritance fits with the rest of your architecture.
Or, just to illustrate the interface suggestion proposed by #MrDisappointment
public interface IDetails
{
int Id { get; }
string Status { get; }
}
public class PaymentDetails : IDetails
{
public int Id { get; private set; }
public string Status { get; private set; }
}
public class PaymentHelper
{
private PaymentDetails _details;
public IDetails Details { get { return _details; } private set { _details = value; } }
}
So there are two ways that I can think of to deal with this. One is really simple:
public class PaymentDetails
{
private int _id;
private bool _idSet = false;
int Id
{
get
{
return _id;
}
set
{
if (_idSet == false)
{
_id = value;
_idSet == true;
}
else
{
throw new ArgumentException("Cannot change an already set value.");
}
}
}
private string _status;
private bool _statusSet = false;
string Status
{
get
{
return _status;
}
set
{
if (_statusSet == false)
{
_status = value;
_statusSet = true;
}
else
{
throw new ArgumentException("Cannot change an already set value.");
}
}
}
The simple solution only allows values to be set once. Changing anything requires creating a new instance of the class.
The other is rather complex but very versatile:
public interface IPaymentDetails : IEquatable<IPaymentDetails>
{
int Id { get; }
string Status { get; }
}
public class PaymentDetails : IPaymentDetails, IEquatable<IPaymentDetails>
{
public PaymentDetails()
{
}
public PaymentDetails(IPaymentDetails paymentDetails)
{
Id = paymentDetails.Id;
Status = paymentDetails.Status;
}
public static implicit operator PaymentDetails(PaymentDetailsRO paymentDetailsRO)
{
PaymentDetails paymentDetails = new PaymentDetails(paymentDetailsRO);
return paymentDetails;
}
public override int GetHashCode()
{
return Id.GetHashCode() ^ Status.GetHashCode();
}
public bool Equals(IPaymentDetails other)
{
if (other == null)
{
return false;
}
if (this.Id == other.Id && this.Status == other.Status)
{
return true;
}
else
{
return false;
}
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
IPaymentDetails iPaymentDetailsobj = obj as IPaymentDetails;
if (iPaymentDetailsobj == null)
{
return false;
}
else
{
return Equals(iPaymentDetailsobj);
}
}
public static bool operator == (PaymentDetails paymentDetails1, PaymentDetails paymentDetails2)
{
if ((object)paymentDetails1 == null || ((object)paymentDetails2) == null)
{
return Object.Equals(paymentDetails1, paymentDetails2);
}
return paymentDetails1.Equals(paymentDetails2);
}
public static bool operator != (PaymentDetails paymentDetails1, PaymentDetails paymentDetails2)
{
if (paymentDetails1 == null || paymentDetails2 == null)
{
return ! Object.Equals(paymentDetails1, paymentDetails2);
}
return ! (paymentDetails1.Equals(paymentDetails2));
}
public int Id { get; set; }
public string Status { get; set; }
}
public class PaymentDetailsRO : IPaymentDetails, IEquatable<IPaymentDetails>
{
public PaymentDetailsRO()
{
}
public PaymentDetailsRO(IPaymentDetails paymentDetails)
{
Id = paymentDetails.Id;
Status = paymentDetails.Status;
}
public static implicit operator PaymentDetailsRO(PaymentDetails paymentDetails)
{
PaymentDetailsRO paymentDetailsRO = new PaymentDetailsRO(paymentDetails);
return paymentDetailsRO;
}
public override int GetHashCode()
{
return Id.GetHashCode() ^ Status.GetHashCode();
}
public bool Equals(IPaymentDetails other)
{
if (other == null)
{
return false;
}
if (this.Id == other.Id && this.Status == other.Status)
{
return true;
}
else
{
return false;
}
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
IPaymentDetails iPaymentDetailsobj = obj as IPaymentDetails;
if (iPaymentDetailsobj == null)
{
return false;
}
else
{
return Equals(iPaymentDetailsobj);
}
}
public static bool operator == (PaymentDetailsRO paymentDetailsRO1, PaymentDetailsRO paymentDetailsRO2)
{
if ((object)paymentDetailsRO1 == null || ((object)paymentDetailsRO2) == null)
{
return Object.Equals(paymentDetailsRO1, paymentDetailsRO2);
}
return paymentDetailsRO1.Equals(paymentDetailsRO2);
}
public static bool operator != (PaymentDetailsRO paymentDetailsRO1, PaymentDetailsRO paymentDetailsRO2)
{
if (paymentDetailsRO1 == null || paymentDetailsRO2 == null)
{
return ! Object.Equals(paymentDetailsRO1, paymentDetailsRO2);
}
return ! (paymentDetailsRO1.Equals(paymentDetailsRO2));
}
public int Id { get; private set; }
public string Status { get; private set;}
}
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public PaymentDetailsRO MyPaymentDetails
{
get
{
return _paymentDetails;
}
}
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
The complex solution allows a changeable backing store, but presents a readonly version to the consumer that cannot be changed by outsiders to your helper class.
Note that both patterns only work if you implement them all the way down the object graph or stick to value types and strings.
You can't prevent that, the property returns a refrence to a PaymentDetails, and once somebody has that, it is out of your control.
However, you can just wrap the PaymentDetails. Instead of returning it verbatim, offer only getters for its public properties.
You can also assign access modifiers for the PaymentDetails class like so:
public string Status { get; private set; }
if you don't need the class elsewhere with a public setter.
Yet another solution: Make setters internal
This is the pragmatical way if the PaymentHelper is in the same assembly of PaymentDetails and the clients of PaymentHelper are in another assembly.
Yet another solution: Delegate from PaymentHelper to PaymentDetails.
This is to add the same properties to PaymentHelper as in PaymentDetails.
If you have many properties you can let generate the delegating properties into PaymentHelper by ReSharper. Place cursor on *_paymentDetails* of line
private PaymentDetails _paymentDetails;
Press Alt+Insert->Delegating Members. Then all PaymentHelper properties delegate to PaymentDetails properties.