Why ObservableCollection is not updated on items change? - wpf

I noticed that ObservableCollection in WPF reflects changes in GUI only by adding or removing an item in the list, but not by editing it.
That means that I have to write my custom class MyObservableCollection instead.
What is the reason for this behaviour?
Thanks

The ObservableCollection has no way of knowing if you make changes to the objects it contains - if you want to be notified when those objects change then you have to make those objects observable as well (for example by having those objects implement INotifyPropertyChanged)

another way of achieving this would be that you implement a new XXXViewModel class that derives from DependencyObject and you put this one in the ObservableCollection.
for this look at this very good MVVM introduction: http://blog.lab49.com/archives/2650
an example for such a class would be:
public class EntryViewModel : DependencyObject
{
private Entry _entry;
public EntryViewModel(Entry e)
{
_entry = e;
SetProperties(e);
}
private void SetProperties(Entry value)
{
this.Id = value.Id;
this.Title = value.Title;
this.CreationTimestamp = value.CreationTimestamp;
this.LastUpdateTimestamp = value.LastUpdateTimestamp;
this.Flag = value.Flag;
this.Body = value.Body;
}
public Entry Entry
{
get {
SyncBackProperties();
return this._entry;
}
}
public Int64 Id
{
get { return (Int64)GetValue(IdProperty); }
set { SetValue(IdProperty, value); }
}
// Using a DependencyProperty as the backing store for Id. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IdProperty =
DependencyProperty.Register("Id", typeof(Int64), typeof(EntryViewModel), new UIPropertyMetadata(new Int64()));
}}
important things here:
- it derives from DependencyObject
- it operates with DependencyProperties to support WPFs databinding
br
sargola

You can register a method in the view model class aginst the PropertyChanged event of data class objects and listen to them in View model when any change in the property of the data objects happen. This is very easy and straight way to have the control in View model when the items of an observable collection changes. Hope this helps...

Probably because items have no way to alert the collection when they are edited - i.e. they might not be observable. Other classes would have similar behavior - no way to alert you to a every change in the graph of referenced classes.

As a work-around, you could extract the object from the collection and then reinsert it after you are done processing. Depending on your requirements and concurrency model, this could just make the program ugly, though. This is a quick hack, and not suitable for anything that requires quality.
Instead, you could implement the collection with an update method that specifically triggers the ContentChanged (not sure about the name) event. It's not pretty, but it is at least quite easy to deal with.
Ideally, as kragen2uk says, it would be best to make the objects observable and keep your client code clean and simple.
see also this question.

Related

What would be the best way to raise a MVVM property from a different ViewModel?

On my MainViewModel, I have a property that looks like this:
private bool _IsSkinNight = true;
public bool IsSkinNight
{
get { return _IsSkinNight; }
set
{
_IsSkinNight = value;
RaisePropertyChanged("IsSkinNight");
RaisePropertyChanged("WindowBackColor");
RaisePropertyChanged("StyleImage");
}
}
As you can see, I use this one property to raise other properties. It makes changing the UI much easier. Especially as I am going to add more items to it.
However, I have a property on a WPF page that I need to update as well. But since it's on a different page, its ViewModel is separate as well. So this property can't call RaisePropertyChanged on it and the property in the page can't check the state of IsSkinNight.
So what would be the best way to cross between the different ViewModels? I'll be adding more pages. So is there a way to make like a universal property that all ViewModels can access?
Thanks
Even if I don't like using it, you probably need to look up for EventAgregators.
Basically you will be able to fire an event in your MainViewModel, and in your other view models you will be able to register to one or more event of this agregator.
However, I strongly recommend that you use it very lightly, because it can become extremely difficult to Debug, since there is no call stack when you fire an event like that.
Thanks for the help everyone. I did a bit more research, based on the suggestions here, and came across MVVM Messages.
Using this blog post, I was able to use MVVM messages to achieve my goal. Thanks again.
In such a case, I sometimes create a kind of Context class, to keep track of "global" properties. This class has to be registered as a Singleton.
public class SkinContext : ISkinContext {
private bool _IsSkinNight = true;
public bool IsSkinNight
{
get { return _IsSkinNight; }
set
{
_IsSkinNight = value;
RaisePropertyChanged("IsSkinNight");
RaisePropertyChanged("WindowBackColor");
RaisePropertyChanged("StyleImage");
}
}
then I inject this class in each ViewModel that needs to be aware of the context and subscribe to the NotifyPropertyChanged event (Or a custom event that you created):
public class SomeViewModel {
public SomeViewModel(ISkinContext context){
context.OnPropertyChanged += (s,e) => { /*Raise other notification and whatnot*/ }
}
}

WPF: DependencyProperty of custom control fails when using several instances of the control

I've built a custom control in WPF that inherits from ListBox. In this I have implementet my own property that is a BindingList. To make this property bindable I've implemeneted it as a DependencyProperty:
public BindingList<CheckableListItem> CheckedItems
{
get
{
return (BindingList<CheckableListItem>)GetValue(MultiComboBox.CheckedItemsProperty);
}
set
{
SetValue(MultiComboBox.CheckedItemsProperty, value);
}
}
public static readonly DependencyProperty CheckedItemsProperty;
I register this DependencyProperty in a static constructor inside my custom control:
CheckedItemsProperty = DependencyProperty.Register("CheckedItems",
typeof(BindingList<CheckableListItem>),
typeof(MultiComboBox),
new FrameworkPropertyMetadata(new BindingList<CheckableListItem>()));
(MultiComboBox is the name of my custom control. CheckableListItem is a simple class I've written just for this purpose).
This BindingList is then updated inside the custom control (never outside) as the user interacts with it.
When I use my custom control in XAML I bind to the CheckItems property with the mode "OneWayToSource". I'm using the MVVM pattern and the property in the ViewModel that I'm binding to is also a BindingList. The ViewModel never affects this list, it just reacts at the changes that the custom control make to the list. The property in the ViewModel looks like this:
private BindingList<CheckableListItem> _selectedItems;
public BindingList<CheckableListItem> SelectedItems
{
get
{
return _selectedItems;
}
set
{
if (value != _selectedItems)
{
if (_selectedItems != null)
{
_selectedItems.ListChanged -= SelectedItemsChanged;
}
_selectedItems = value;
if (_selectedItems != null)
{
_selectedItems.ListChanged += SelectedItemsChanged;
}
OnPropertyChanged("SelectedItems");
}
}
}
As you can see I'm listening to changes made to the list (these changes always occur inside my custom control), and in the "SelectedItemsChanged"-method I update my Model accordingly.
Now...this works great when I have one of these controls in my View. However, if I put two (or more) of them in the same View strange things start to happen. This will of course mean that I'll have two lists with selected items in my ViewModel. But if do something in the View that changes one of the lists, both lists are affected! That is, the event handlers for the event ListChanged is triggered for both list if changes are made to any one of them!
Does anyone recognize this problem and/or have a solution to it? What is wrong with my implementation?
My first though is that the DependencyProperty is static. Normally that means shared between all instances. But I guess DependencyProperties work in some other "magical" way so that might not be the problem.
Any tips or hints is appreciated!
I had a similar problem with a collection-type dependency property. My solution was taken from the MSDN article on Collection-Type Dependency Properties. It was adding the following line
SetValue(OperatorsPropertyKey, new List<ListBoxItem>()); //replace key and type
in the constructor of my control because it seems that a collection-type dependency property constructor is being called only once no matter how many instances your control containing this collection has (static eh).
This sounds like you bound both/all the Views to the same ViewModel. That would explain that changes to one cause changes in the other.

Building ViewModels based on nested Model Entities in WPF and MVVM Pattern

I have a problem understanding how to build view models based on the following models
(I simplified the models to be clearer)
public class Hit
{
public bool On { get; set;}
public Track Track { get; set; }
}
public class Track
{
public ObservableCollection<Hit> Hits { get; set; }
public LinearGradientBrush Color { get; set; }
public Pattern Pattern { get; set; }
}
public class Pattern
{
public string Name { get; set; }
public ObservableCollection<Tracks> Tracks { get; set; }
}
Now, my problem is, how to build the ViewModels..
I need to keep the original relationships through the models, beacaus i have a Serialize() method on the Pattern that serializes it to an XML file.. (with the related Tracks and Hits)
To be able to bind the pattern to the user controls and it's nested templates I should also have a PatternViewModel with an ObservableCollection<TrackViewModel> in it, same thing for the TrackViewModel and the HitViewModel.. and i neet to have custom presentation properties on the view models that aren't part of the business object (colors and more..)
It just seem not a good thing to me to duplicate all of the relationships of the models on the view models...
and keeping track of all this relations while coding the viewmodels is also much more error prone..
anyone has a better approach/solution?
One thing I've done, with some success, is to move the ObservableCollection out of the model. Here's my general pattern:
In the model objects, expose a property of type IEnumerable<TModel> that gives read-only access to the collection. Use a plain old List<TModel>, not an ObservableCollection, as the backing collection.
For code that needs to mutate the models' collections (add, delete, etc.), add methods to the model object. Don't have outside code directly manipulating the collection; encapsulate that inside methods on the model.
Add events to the model for each type of change you allow. For example, if your model only supports adding items to the end of the collection, and deleting items, then you would need an ItemAdded event and an ItemDeleted event. Create an EventArgs descendant that gives information about the item that was added. Fire these events from the mutation methods.
In your ViewModel, have an ObservableCollection<TNestedViewModel>.
Have the ViewModel hook the events on the model. Whenever the model says an item was added, instantiate a ViewModel and add it to the ViewModel's ObservableCollection. Whenever the model says an item was deleted, iterate the ObservableCollection, find the corresponding ViewModel, and remove it.
Apart from the event handlers, make sure all of the collection-mutation code is done via the model -- treat the ViewModel's ObservableCollection as strictly something for the view's consumption, not something you use in code.
This makes for a lot of duplicate code for each different ViewModel, but it's the best I've been able to come up with. It does at least scale based on the complexity you need -- if you have a collection that's add-only, you don't have to write much code; if you have a collection that supports arbitrary reordering, inserts, sorting, etc., it's much more work.
I ended up using part of the solution that Joe White suggested, in a slighty differ manner
The solution was to just leave the models as they were at the beginning, and attaching to the collections an eventhandler for CollectionChanged of the inner collections, for example, the PatternViewModel would be:
public class PatternViewModel : ISerializable
{
public Pattern Pattern { get; set; }
public ObservableCollection<TrackViewModel> Tracks { get; set; }
public PatternViewModel(string name)
{
Pattern = new Pattern(name);
Tracks = new ObservableCollection<TrackViewModel>();
Pattern.Tracks.CollectionChanged += new NotifyCollectionChangedEventHandler(Tracks_CollectionChanged);
}
void Tracks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Track track in e.NewItems)
{
var position = Pattern.Tracks.IndexOf((Track) e.NewItems[0]);
Tracks.Insert(position,new TrackViewModel(track, this));
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (Track track in e.OldItems)
Tracks.Remove(Tracks.First(t => t.Track == track));
break;
case NotifyCollectionChangedAction.Move:
for (int k = 0; k < e.NewItems.Count; k++)
{
var oldPosition = Tracks.IndexOf(Tracks.First(t => t.Track == e.OldItems[k]));
var newPosition = Pattern.Tracks.IndexOf((Track) e.NewItems[k]);
Tracks.Move(oldPosition, newPosition);
}
break;
}
}
}
So i can attach the new Color/Style/Command on the view models to keep my base models clean
And whenever I add/remove/move items in the base models collection, the view models collections remain in sync with each other
Luckily I don't have to manage lots of object in my application, so duplicated data and performance won't be a problem
I don't like it too much, but it works well, and it's not a huge amount of work, just an event handler for the view model that contains others view model collections (in my case, one for PatternViewModel to sync TrackViewModels and another on TrackViewModel to manage HitViewModels)
Still interested in your thoughs or better ideas =)
I think I had the same problem and if you do it like "PatternViewModel with an ObservableCollection<TrackViewModel>" you also get a massive impact on your performance because you start duplicating data.
My approach was to build - for your expample - a PatternViewModel with a ObservableCollection<Track>. It's no contradiction to MVVM because the view is bound to the collection.
This way you may avoid the duplication of the relationships.
One solution I've been considering, although I'm not sure if it would work perfectly in practice, is to use converters to create a viewmodel around your model.
So in your case, you could bind Tracks directly to (as an example) a listbox, with a converter that creates a new TrackViewModel from the Track. All your control would ever see would be a TrackViewModel object, and all your models will ever see is other models.
I'm not sure about the dynamic updating of this idea though, I've not tried it out yet.

Silverlight: how to bind List<T> to data grid

MVVM pattern is implemented in my Silverlight4 application.
Originally, I worked with ObservableCollection of objects in my ViewModel:
public class SquadViewModel : ViewModelBase<ISquadModel>
{
public SquadViewModel(...) : base(...)
{
SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
...
_model.DataReceivedEvent += _model_DataReceivedEvent;
_model.RequestData(...);
}
private void _model_DataReceivedEvent(ObservableCollection<TeamPlayerData> allReadyPlayers, ...)
{
foreach (TeamPlayerData tpd in allReadyPlayers)
{
SquadPlayerViewModel sp = new SquadPlayerViewModel(...);
SquadPlayers.Add(sp);
}
}
...
}
Here is a peacie of XAML code for grid displaying:
xmlns:DataControls="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
...
<DataControls:DataGrid ItemsSource="{Binding SquadPlayers}">
...</DataControls:DataGrid>
and my ViewModel is bound to DataContext property of the view.
This collection (SquadPlayers) is not changed after its creation so I would like to change its type to
List<SquadPlayerViewModel>
. When I did that, I also added
RaisePropertyChanged("SquadPlayers")
in the end of '_model_DataReceivedEvent' method (to notify the grid that list data are changed.
The problem is that on initial displaying grid doesn't show any record... Only when I click on any column header it will do 'sorting' and display all items from the list...
Question1: Why datagrid doesn't contain items initially?
Q2: How to make them displayed automatically?
Thanks.
P.S. Here is a declaration of the new List object in my view-model:
public List<SquadPlayerViewModel> SquadPlayers { get; set; }
You can't use List as a binding source, because List not implement INotifyCollectionChanged it is require for WPF/Silverlight to have knowledge for whether the content of collection is change or not. WPF/Sivlerlight than can take further action.
I don't know why you need List<> on your view model, but If for abstraction reason you can use IList<> instead. but make sure you put instance of ObservableCollection<> on it, not the List<>. No matter what Type you used in your ViewModel Binding Only care about runtime type.
so your code should like this:
//Your declaration
public IList<SquadPlayerViewModel> SquadPlayers { get; set; }
//in your implementation for WPF/Silverlight you should do
SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
//but for other reason (for non WPF binding) you can do
SquadPlayers = new List<SquadPlayerViewModel>();
I usually used this approach to abstract my "Proxied" Domain Model that returned by NHibernate.
You'll need to have your SquadPlayers List defined something like this:
private ObservableCollection<SquadPlayerViewModel> _SquadPlayers;
public ObservableCollection<SquadPlayerViewModel> SquadPlayers
{
get
{
return _SquadPlayers;
}
set
{
if (_SquadPlayers== value)
{
return;
}
_SquadPlayers= value;
// Update bindings, no broadcast
RaisePropertyChanged("SquadPlayers");
}
}
The problem is that whilst the PropertyChanged event informs the binding of a "change" the value hasn't actually changed, the collection object is still the same object. Some controls save themselves some percieved unnecessary work if they believe the value hasn't really changed.
Try creating a new instance of the ObservableCollection and assigning to the property. In that case the currently assigned object will differ from the new one you create when data is available.

When to use a WPF Dependency Property versus INotifyPropertyChanged

Do folks have any guidance on when a simple .NET property that fires INotifyPropertyChanged.PropertyChanged is sufficient in a view model? Then when do you want to move up to a full blown dependency property? Or are the DPs intended primarily for views?
There are a few approaches:
1. The dependency property
While you using the dependency property it makes the most sense in elements-classes that have a visual appearance (UIElements).
Pros:
WPF do the logic stuff for you
Some mechanism like animation use only dependency property
'Fits' ViewModel style
Cons:
You need to derive form DependencyObject
A bit awkward for simple stuff
Sample:
public static class StoryBoardHelper
{
public static DependencyObject GetTarget(Timeline timeline)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
return timeline.GetValue(TargetProperty) as DependencyObject;
}
public static void SetTarget(Timeline timeline, DependencyObject value)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
timeline.SetValue(TargetProperty, value);
}
public static readonly DependencyProperty TargetProperty =
DependencyProperty.RegisterAttached(
"Target",
typeof(DependencyObject),
typeof(Timeline),
new PropertyMetadata(null, OnTargetPropertyChanged));
private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Storyboard.SetTarget(d as Timeline, e.NewValue as DependencyObject);
}
}
2. The System.ComponentModel.INotifyPropertyChanged
Usually, when creating a data object, you’ll use this approach. It is simple and neat solution for Data-like stuff.
Pros and Cons - complementary to 1. You need to to implement only one event (PropertyChanged).
Sample:
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
private string name;
public string Name;
{
get { return name; }
set {
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
3.PropertyNameChanged
Rising an event for each property with specified name(f.e. NameChanged). Event must have this name and it is up to you to handle/rise them. Similar approach as 2.
4. Get the binding
Using the FrameworkElement.GetBindingExpression() you can get the BindingExpression object
and call BindingExpression.UpdateTarget() to refresh.
First and second are the most likely depending what is your goal.
All in all, it is Visual vs Data.
As far as I know, DependencyProperty is only required when you need
PropertyValue inheritence
you need to allow the property to be set in Style setters
Use animation for the property
etc.
These features will not be available with normal properties.
DependencyProperty is required if you want to allow a binding to be set on the property. Usually this is for custom UIElements you create. You want to allow people to be able to bind data to your UIElements.
<local:MyUIElement MyProperty={Binding Path=SomethingToBindTo} />
To do this requires that MyProperty is a dependancy property
The main problem I see with INotifyPropertyChanged is if you viewmodel is complex containing many nested types it appears that you have to bubble the PropertyChanged event up through the hierarchy.
As the other answers have already said enough about when to create dependency property. i.e.
PropertyValue inheritence
you need to use binding on a property
Use animation for the property
The one more perspective/question on this is "In a WPF application is makes sense to create dependency properties in a control cause they are likely to change during user interaction like Height,width, text,content, background etc but what about other classes like Behaviors Classes(Non UI classes). Do properties in those classes need to be a dependency property?"
I won't say for very absolute or emphasis on some set of rules here but you should create your properties as DP. As from design perspective if a property is DP it's always in default form of WPF to use/bind.i.e.
As a DP is much more fast/natural in reflecting changes compare to a normal CLR property.
A DP has validation mechanism to validate the value assigned and a default structure to revert the value.
A DP has Coerce value callback to control the limits of property.
A DP has meta data associated with it unlike CLR property.
In terms of practices I've seen people doing many mistakes in nested bindings and then raising changes these kind of faults doesn't happen with a DP cause of it's design and compatibility of raising change itself. So with a little extra syntax you put a flexibility/performance/ easeness to your application. So go for it wherever affordable.
Still can't say sure for ViewModel classes/other helper classes. will update the answer if found convincing reasons in future.
Just a post worth reading on this topic

Resources