Answered by:
ObservableCollection<T> and binding problem.

Question
-
Hi to all!
I have a problem with ObservableCollection<T> and it's notification to a bounded control (ListView).
I have the following code snippet:public class PipesList : ObservableCollection<ChannelOwner> { public PipesList() : base() { Add(new ChannelOwner { EmptyName = "", One = "0", Two = "0", Three = "0", Four = "0", Five = "0", Six = "0", Seven = "0", Eight = "0", Nine = "0", Ten = "0" }); } }
The ChannelOwner class hold the public properties (with geters and seters).
So, i bind this collection to the ItemsSource of a ListView and set the column binding in XAML as this:<ListView DockPanel.Dock="Top" Name="lstOwnersAndChannels"> <ListView.View> <GridView> <GridViewColumn Header=" " DisplayMemberBinding="{Binding Emptyname}" /> <GridViewColumn Header="1" DisplayMemberBinding="{Binding One}" /> <GridViewColumn Header="2" DisplayMemberBinding="{Binding Two}" /> <GridViewColumn Header="3" DisplayMemberBinding="{Binding Three}" /> <GridViewColumn Header="4" DisplayMemberBinding="{Binding Four}" /> <GridViewColumn Header="5" DisplayMemberBinding="{Binding Five}" /> <GridViewColumn Header="6" DisplayMemberBinding="{Binding Six}" /> <GridViewColumn Header="7" DisplayMemberBinding="{Binding Seven}" /> <GridViewColumn Header="8" DisplayMemberBinding="{Binding Eight}" /> <GridViewColumn Header="9" DisplayMemberBinding="{Binding Nine}" /> <GridViewColumn Header="10" DisplayMemberBinding="{Binding Ten}" /> </GridView> </ListView.View> </ListView>
When i run the program, ListView nicely gets updated with the columns and their values (all zeroes at this time).
But when i modify the public properties and set a different than zero value in them, this change is not reflected at the ListView, which display the zeroes all time.
For example, by using a public method in the ChannelOwner class, i change the property "One" with a string value different than zero. I see from the debugger that the property is indeed changed but the ListView.itemsSource property does not get updated.
i am sure i am missing something here but after two hours of frustration i fail to see it...
Can anyone, please, help me with this ??
Thanks a lot for any help
anthony
Thursday, February 26, 2009 4:06 PM
Answers
-
Anthony,
I think the null will defeat the purpose in the PropertyChanged. I have a bit different with my code. I just started using it this way and it has stuck. The way I would code it:class Person : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } #endregion }
Then I would bind this way:Binding binding = new Binding(); binding.Source = NameListInstance; BindingOperations.SetBinding(myListView, ListView.ItemsSourceProperty, binding);
Again, my way might not be the best way, BUT I think you have to pass the Property name so that the object 'knows' which one is changed. Also I like to bind the ItemSourceProperty to the collection. If not you have to set it again and again in code some other way.
I hope it makes sense.
-noorbakhsh
- Proposed as answer by noorbakhsh Thursday, February 26, 2009 9:40 PM
- Marked as answer by Tao Liang Wednesday, March 4, 2009 2:40 AM
Thursday, February 26, 2009 9:33 PM
All replies
-
Anthony,
My question is if your class 'ChannelOwner' implements INotifyPropertyChanged and all setters have the correct 'RaisePropertyChanged' in them.
You have to realize that the ObservableCollection will let you monitor changes in the collection BUT for the item to signal that it has changed, you need your class to implement INotifyPropertyChanged interface.
I hope this helps.
-noorbakhsh
- Proposed as answer by noorbakhsh Thursday, February 26, 2009 5:13 PM
Thursday, February 26, 2009 5:12 PM -
Hi noorbakhsh!!
Thanks for your help, i think you leadme to the right direction...
So, i left the code at work and now i am at home and i build a simple example based on what you told me.
The code is this:class NamesList : ObservableCollection<Person> { public NamesList() : base() { Add(new Person { Name = "anthonyb" }); } } class Person : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; PropertyChanged(this, null); } } public event PropertyChangedEventHandler PropertyChanged; }
Is this sufficient for a ListView (or any other bounded control) to refresh itself ? i mean, i will create an instance of NameList and then i do something like:
myListView.ItemsSource = NameListInstance;
And when i try to edit an entry of the collection, it will siganl and the bounded control will update itself with the new data ??
Thanks again!
Thursday, February 26, 2009 8:46 PM -
Anthony,
I think the null will defeat the purpose in the PropertyChanged. I have a bit different with my code. I just started using it this way and it has stuck. The way I would code it:class Person : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } #endregion }
Then I would bind this way:Binding binding = new Binding(); binding.Source = NameListInstance; BindingOperations.SetBinding(myListView, ListView.ItemsSourceProperty, binding);
Again, my way might not be the best way, BUT I think you have to pass the Property name so that the object 'knows' which one is changed. Also I like to bind the ItemSourceProperty to the collection. If not you have to set it again and again in code some other way.
I hope it makes sense.
-noorbakhsh
- Proposed as answer by noorbakhsh Thursday, February 26, 2009 9:40 PM
- Marked as answer by Tao Liang Wednesday, March 4, 2009 2:40 AM
Thursday, February 26, 2009 9:33 PM -
Hey noorbakhsh
thanks again for your help!
I will try your code tomorrow at work and let you know. I think it should work as i look it right now but i was wondering this:
if we need to write so much code just for a single property (for a bounded control to be auto-updated), i do not want to imagine how much code we will have to write if we need, let's say, to fetch some data from a database table (with 15 or more columns) and do the same thing...
:(Thursday, February 26, 2009 9:49 PM -
I guess you are correct!
However, the data for more Properties added is same as any other property PLUS the OnPropertyChanged("PropertNameString"); line added, so just one extra line per Property.
Just the initial set-up seems bad!
Happy coding!
-noorbakhsh
Thursday, February 26, 2009 10:24 PM -
Hi!
i am back to work now and i implemented it like you told me and it now works!! When i change something in the collection,
the listview is updated correctly!
But i have a question: the line
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
is never executed because the event "PropertyChanged" is always null...How comes and the listview is the updated ??
And what is the correct way to implement this event, i mean for what purpose ?
Friday, February 27, 2009 10:09 AM -
Anthony,
I see what you mean. I had never put a break point there to see that. I am not sure! Maybe it is running on a parallel thread?? Maybe someone else can shed some light on this.
I have been using it this way from the beginning. I am not sure how I got in the habit of doing it this way, but it has been working, so I have been using it!!!
Well learn something new every day. Thanks for todays' !
-noorbakhsh
Friday, February 27, 2009 5:38 PM