I have a few properties in a bindingList for a XtratreeList(DevExress) where a child node needs to show a parentnode'e property. I have the following code.
public abstract class ClassBase : INotifyPropertyChanged
{
protected static int initialId = 0;
private int id;
private int parentID;
private string productName;
private string productType;
private string colorProductType;
private void RaisePropertyChanged(string propertyName)
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public int ID
{
get { return id; }
set
{
if ( id == value )
return;
id = value;
RaisePropertyChanged("ID");
}
}
public int ParentID
{
get { return parentID; }
set
{
if ( parentID == value )
return;
parentID = value;
RaisePropertyChanged("ParentID");
}
}
public string ProductName
{
get { return productName; }
set
{
if ( productName == value )
return;
productName = value;
RaisePropertyChanged("ProductName");
}
}
public string ProductType
{
get { return productType; }
set
{
if ( productType == value )
return;
productType = value;
RaisePropertyChanged("ProductType");
RaisePropertyChanged("ColorProductType");
}
}
public string ColorProductType
{
get { return colorProductType ; }
set
{
if (colorProductType == value)
return;
colorProductType = value;
RaisePropertyChanged("ColorProductType");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}`
My requirement is to have the ColorProductType property changed when the ProductType property changes, basically ProductType is a parent node property and ColorProductType - child's. So on changing the parent's property the child's need to be changed. I have both these properties bound to 2 text boxes. So changing the parent prop should change both textboxes, but the vice versa is not true. RaisePropertyChanged("ColorProductType"); within the parent is not working, colorproducttype is null, what is the issue here?
RaisePropertyChanged does not actually update the property. It simply signals the PropertyChanged event. Something somewhere must subscribe to it and update the other property accordingly. Something like this:
public abstract class ClassBase : INotifyPropertyChanged
{
private string productType;
private string colorProductType;
public ClassBase()
{
this.PropertyChanged += HandlePropertyChanged;
}
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "ProductType")
{
// update ColorProductType here
}
}
private void RaisePropertyChanged(string propertyName)
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public string ProductType
{
get { return productType; }
set
{
if ( productType == value )
return;
productType = value;
RaisePropertyChanged("ProductType");
}
}
public string ColorProductType
{
get { return colorProductType ; }
set
{
if (colorProductType == value)
return;
colorProductType = value;
RaisePropertyChanged("ColorProductType");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
Naturally, this is complete overkill. You can update ColorProductType when ProductType is updated and let the PropertyChanged event and databinding handle the textbox update:
public string ProductType
{
get { return productType; }
set
{
if ( productType == value )
return;
productType = value;
// update ColorProductType here
RaisePropertyChanged("ProductType");
}
}
Related
i'm having difficulties deserialising a json file. The json object has the following structure which has been simplified
{"date":"2015-11-11",
"retailer_id":"CLD001",
"orders":[{
"products":
[{
"product_id":"53743443003",
"quantity":4,"
unit_price":42.71}],
"value":170.84,
"customer":{"id":58}}]}
This structure indicated to me that the top class is
[Table]
public class RetailOrders : INotifyPropertyChanged, INotifyPropertyChanging
{
private List<OrderItems> oi;
private string retailer_id;
private DateTime date;
public List<OrderItems> OrderItems
{
get { return oi; }
set { oi = value; }
}
public string Retailer_id
{
get { return retailer_id; }
set { retailer_id = value; }
}
public DateTime Date
{
get { return date; }
set { date = value; }
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
}
As you can see orders take a list of products being ordered with the variable id, quantity and total price
[Table]
public class ProductsOrdered: INotifyPropertyChanged, INotifyPropertyChanging
{
private string productID;
private int quantity;
private double unit_price;
public string ProductID
{
get { return productID; }
set { productID = value; }
}
public int Quantity
{
get { return quantity; }
set { quantity = value; }
}
public double UnitPrice
{
get { return unit_price; }
set { unit_price = value; }
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
finally the orderItems contain a list of the orders followed by a total price and associated customer
[Table]
public class OrderItems : INotifyPropertyChanged, INotifyPropertyChanging
{
private List<ProductsOrdered> po = new List<ProductsOrdered>();
private double TotalPrice;
private int customer_id;
public List<ProductsOrdered> Productsordered
{
get { return po; }
set { po = value; }
}
public double totalprice
{
get { return TotalPrice; }
set { TotalPrice = value; }
}
public int customerid
{
get { return customer_id; }
set { customer_id = value; }
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
}
I'm expecting the list to fill out however currently they are null values and can't seem to think of why this is happening
Your property names don't match the JSON you've supplied. Specifically in your JSON there is an array orders but in your C# class the property is OrderItems.
You could annotate the property like this:
[JsonProperty(PropertyName = "orders")]
public List<OrderItems> OrderItems { get; set; }
I haven't worked all the way through your hierarchy, but any other null fields will likely be caused by a similar mismatch.
One other thing to be careful of is private properties and private setters, which I don't thing will be an issue for you here, but is the other top reason for null values when you deserialize JSON.
I have an object with five properties and each of these properties has two states ("before" and "after").
How do I get the information about which properties changed their state?
The only way that I am familiar with is to get a list of all the properties (using Reflection?), then use a loop to compare each property between two objects and store information about those which were changed.
Is there a simple way to do it, perhaps using LINQ?
The interface INotifyProprtyChanged requires you to implement an event PropertyChanged. You can subscribe to this interface in the class itself and track properties for which they get called.
For example:
internal class SampleClass : INotifyPropertyChanged{
public event PropertyChangedEventHandler PropertyChanged;
private string _SampleProperty;
internal List<string> _ChangedProperties;
public SampleClass() {
this.PropertyChanged += SampleClass_PropertyChanged;
_ChangedProperties = new List<string>();
}
protected virtual void OnPropertyChanged( string propertyName ) {
PropertyChangedEventHandler handler = PropertyChanged;
if ( handler != null )
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
void SampleClass_PropertyChanged( object sender, PropertyChangedEventArgs e ) {
if ( _ChangedProperties.Contains( e.PropertyName ) ) return;
_ChangedProperties.Add( e.PropertyName );
}
public string SampleProperty {
get { return _SampleProperty; }
set {
if (_SampleProperty == value )
return;
_SampleProperty = value;
OnPropertyChanged( "SampleProperty" );
}
}
}
Now you have a list of changed properties. You can work further by remembering values, etc.
I have not considered thread safety, I would not consider this sample production ready.
You can do something like this:
public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
public class PropertyChangedEventArgs : EventArgs
{
public PropertyChangedEventArgs(string propertyName, dynamic oldValue, dynamic newValue)
{
this.PropertyName = propertyName;
this.OldValue = oldValue;
this.NewValue = newValue;
}
public virtual string PropertyName { get; private set; }
public virtual dynamic OldValue { get; private set; }
public virtual dynamic NewValue { get; private set; }
}
public class PropertyClass
{
public event PropertyChangedEventHandler PropertyChanged;
private void Set<T>(string propertyName, ref T field, T value)
{
if (field.Equals(value))
return;
T oldValue = value;
field = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName, oldValue, value));
}
// Properties
private string _name;
private string _message;
private bool _isMember;
public string Name
{
get { return _name; }
set { Set("Name", ref _name, value); }
}
public string Message
{
get { return _message; }
set { Set("Message", ref _message, value); }
}
public bool IsMember
{
get { return _isMember; }
set { Set("IsMember", ref _isMember, value); }
}
}
This approach seems to work half the time for me.
I can see these lines get executed in the debugger:
agencyListBox.DataBindings.Add(new Binding("DataSource", this.Data.Agencies, "AvailableAgencies"));
agencyListBox.DataBindings.Add(new Binding("SelectedItem", this.Data.Agencies, "SelectedAgency", false, DataSourceUpdateMode.OnPropertyChanged));
The agencies class looks like this:
public AgencyType SelectedAgency
{
get
{
return _selected;
}
set
{
_selected = value;
OnPropertyChanged("SelectedAgency");
}
}
public List<AgencyType> AvailableAgencies
{
get
{
return _availableList;
}
set
{
_availableList = value;
OnPropertyChanged("AvailableAgencies");
}
}
So the fields I reference in the binding do exist.
The DisplayMember is set to "Label" which is defined in the AgencyType class:
public event PropertyChangedEventHandler PropertyChanged;
private string _label { get; set; }
public string Label
{
get { return _label; }
set
{
_label = value;
OnPropertyChanged("Label");
}
}
private string _identifier { get; set; }
public string Identifier
{
get { return _identifier; }
set
{
_identifier = value;
OnPropertyChanged("Identifier");
}
}
public AgencyType()
{
Label = string.Empty;
Identifier = string.Empty;
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The values are displayed as desired.
But then when I change the selection, data.Agencies.SelectedAgency is null!
Does anyone have any tips?
I have a Customer class, I would like to get notified when the user has changed the value of the Customer.CityInfo property.
public class City
{
public long Id {get;set;}
public string Code {get;set;}
}
public class Customer
{
private City cityInfo;
private string name;
public long Id { get; set; }
public bool IsCityModified { get; set;}
public bool IsCustomerNameModified { get; set; }
public string Name
{
get{ return name;}
set
{
if(name!=value)
{
IsCustomerNameModified=true; }name=value;
}
}
}
public City CityInfo
{
get
{
if(cityInfo==null)
{
cityInfo=new City();
}
return cityInfo;
}
set{
if(this.cityInfo!=value)
{
IsCityModified =true;
}
this.cityInfo=value;
}
}
}
public ActionResult Save()
{
Customer customer=this.currentCustomerSession;
if(TryUpdateModel<Customer>(customer)){
UpdateModel<Customer>(customer)
}
if(customer.IsCustomerNameModified ){
//I am able to detect whether the customerName value has been changed in the frontend.
}
if(customer.IsCityModified){
//I am not able to detect whether the city value has been changed in the frontend.
}
}
I could set the flag(IsCustomerNameModified) to true if the Customer Name changed since its a value type. But Not able to detect the changes done in Reference Types.
Could anyone help?
This kind of issue is usually handled via a change notification system. See this article: How to: Implement Property Change Notification
Snippet:
public string PersonName
{
get { return name; }
set
{
name = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("PersonName");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
Using this pattern will help you avoid the need to set flags or other such machinations.
Paul is correct you need to implement INotifyProperty change. Here is a quick example. It's very simple.
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _number;
public BaseViewModel()
{
PropertyChanged += (o, p) =>
{
//this is the place you would do what you wanted to do
//when the property has changed.
};
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public int Number
{
get { return _number; }
set
{
_number = value;
OnPropertyChanged("Number");
}
}
}
I agree with Paul's answer but you may even need to override the Equals() and GetHashCode() functions in the City class. The overridden function can check to see if the Code and ID have changed.
public override bool Equals( object obj )
{
City other = obj as City;
if ( ( other != null ) && ( other.Id == this.Id ) && ( other.Code == this.Code ) )
{
return ( true );
}
return ( false );
}
public override int GetHashCode( )
{
return ( this.Id ^ this.Code.GetHashCode() ) ;
}
You could use INotifyPropertyChanged , but I guess you are not binding the object to some UI element.
In that case if it is required only to know if the CityInfo property is changed, the simplest
solution is to raise a custom event.
public class Customer
{
private City cityInfo;
private string name;
public long Id { get; set; }
public bool IsCityModified { get; set;}
public event Action<City> OnCityInfoChanged;
public bool IsCustomerNameModified { get; set; }
public string Name
{
get{ return name;}
set
{
if(name!=value)
{
IsCustomerNameModified=true; }name=value;
}
}
}
public City CityInfo
{
get
{
if(cityInfo==null)
{
cityInfo=new City();
}
return cityInfo;
}
set{
if(this.cityInfo ==value)
return;
IsCityModified =true;
this.cityInfo=value;
if(OnCityInfoChanged != null)
OnCityInfoChanged(value);
}
}
}
And
public ActionResult Save()
{
Customer customer=this.currentCustomerSession;
customer.OnCityInfoChanged += new Action<CityInfo>( (cityInfo) => {//Do Something with New CityInfo});
if(TryUpdateModel<Customer>(customer)){
UpdateModel<Customer>(customer)
}
if(customer.IsCustomerNameModified ){
//I am able to detect whether the customerName value has been changed in the frontend.
}
if(customer.IsCityModified){
//I am not able to detect whether the city value has been changed in the frontend.
}
}
Now that I correctly understood the problem, I would suggest to do the following:
Add a public bool Changed { get; private set; } property in your City object.
Then in each property of your object, check if the value has changed, and if it has, then put the Changed flag to true:
public int Id
{
{ get { return this.id } }
{
set
{
if (this.id != value) Changed = true;
this.id = value;
}
}
}
it is similar to implementing the IPropertyChanged interface, but this way you are sure you only get to check if the object was modified once.
It seems that the reference of your object doesn't change, so you only have to check it's Changed property (if the object's reference really changed, my precedent answer would have worked)
In project i user SQL CE, i have Table:
[Table]
public class Article : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define _cid: private field, public property, and database column.
private int _aid;
[Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
public int aid
{
get { return _aid; }
set
{
NotifyPropertyChanging("aid");
_aid = value;
NotifyPropertyChanged("aid");
}
}
// Define nameColor name: private field, public property, and database column.
private int _rid;
[Column]
public int rid
{
get { return _rid; }
set
{
NotifyPropertyChanging("rid");
_rid = value;
NotifyPropertyChanged("rid");
}
}
private string _title;
[Column]
public string title
{
get { return _title; }
set
{
NotifyPropertyChanging("title");
_title = value;
NotifyPropertyChanged("title");
}
}
private string _thumnail;
[Column]
public string thumnail
{
get { return _thumnail; }
set
{
NotifyPropertyChanging("thumnail");
_thumnail = value;
NotifyPropertyChanged("thumnail");
}
}
private string _DesScription;
[Column(DbType = "NTEXT")]
public string DesScription
{
get { return _DesScription; }
set
{
NotifyPropertyChanging("DesScription");
_DesScription = value;
NotifyPropertyChanged("DesScription");
}
}
private int _orderID;
[Column]
public int orderID
{
get { return _orderID; }
set
{
NotifyPropertyChanging("orderID");
_orderID = value;
NotifyPropertyChanged("orderID");
}
}
private string _pubDate;
[Column]
public string pubDate
{
get { return _pubDate; }
set
{
NotifyPropertyChanging("pubDate");
_pubDate = value;
NotifyPropertyChanged("pubDate");
}
}
private string _linkURL;
[Column]
public string linkURL
{
get { return _linkURL; }
set
{
NotifyPropertyChanging("linkURL");
_linkURL = value;
NotifyPropertyChanged("linkURL");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify that a property changed
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
// Used to notify that a property is about to change
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
when i Update Colum Thumnail , i have erros :
SQL Server does not handle comparison of NText, Text, Xml, or Image data types
because of special characters into database insert sequence trogn should I use BbType = "NTEXT"
Please Help me !
You could remove this column for concurrency checking by adding [Column(UpdateCheck = UpdateCheck.Never)] to this column.
See this blogpost about Linq to sql concurrency checking: http://blogs.msdn.com/b/matt/archive/2008/05/22/into-to-linq-to-sql-optimistic-concurrency.aspx