How to refresh UI from ViewModel with ObservableCollection? - c#

I have a listbox with items bound to an ObservableCollection.
Now, from within the viewModel, I need to cause an update to the UI.
I dont have a refernce to the listbox from my view model.
If I remove or add an item from my ObservableCollection, the ui gets updated.
Based on some other logic I need to update the UI...but the ObservableCollection is the same.
How can I update the UI WITHOUT either adding or removing items from my ObservableCollection?
Thanks

If you need to change your UI because you've edited the items in your collection, then you should arrange for those items to implement the INotifyPropertyChanged interface. If the objects within your collection have a PropertyChanged event, the UI will be listening for that event from individual items. (If possible, you could also change the items in your collection to be DependencyObjects with DependencyProperties, which accomplishes the same goal.)
If you really need to trigger a UI update when nothing at all about your collection has changed, the way to do it is to manually raise the CollectionChanged event. This can't be done with the ObservableCollection<> as is, but you could derive a new collection from that class, and call the protected OnCollectionChanged method from within some new, public method.

I've had a similar issue where I wanted to change the background on an item, but obviously neither the item nor the collection changed.
It was achieved by calling:
CollectionViewSource.GetDefaultView(your_collection_name).Refresh();
This refreshed the view from the view model without altering the collections

This is a good case for an extension method. It hides away the implementation in case it changes in future versions, can be modified in one place, and the calling code looks simpler and less confusing.
public static void Refresh<T>(this ObservableCollection<T> value)
{
CollectionViewSource.GetDefaultView(value).Refresh();
}
Usage:
myCollection.Refresh();

Related

What is the point of INotifyCollectionChanged in terms of databinding (C# WinRt)

Background:
I was trying to roll my own observable collection, by implementing IEnumerable, INotifyPropertyChanged and INotifyCollectionChanged. It works fine, but when I databind the CollectionChanged event is always null. The databound property does however updated, since I am sending a Items[] property changed event.
So this got me wondering what the point of INotifyCollectionChanged is in terms of databinding, since in my class it never gets triggered, but the databinding still works (it updates all the bindings to the collection).
I then decided to do some more digging, and decompiled ObservableCollection. When I databind to an ObservableCollection the CollectionChanged event isn't null like in my implementation.
So really I am wondering why ObservableCollection gets 'special' treatment, and what role INotifyCollectionChange plays in databinding (if any)
INotifyCollectionChanged can be implemented by collections so that when elements are added or removed from the collection, interested parties can be notified of those events. This is useful, for example, when you want a ListView or GridView or some other display control that displays the contents of collections to update its display when the contents of the collection have changed (through adding or removing elements). More generally, any object could data bind to the event to be notified when items are added/removed from the collection to do whatever the data bound component needs to do—it doesn't just have to be a GUI control. Any other operations on the collection, however, will result in no notifications being made to data bound controls/objects. In order for that to occur, you would also need to implement INotifyPropertyChanged on the collection, creating the other PropertyChanged events you also want to publish to notify data bound objects, and raise the event when the operation in question occurs.
Additionally, if you want each item within the collection to update its presentation in the UI when something about the item itself has changed, then the type representing the item should implement INotifyPropertyChanged.
It seems to me that you need to implement your own CollectionChanged event. The built-in System.Array and/or System.Collections.ArrayList classes do not have any events associated with them. So if you're using one of these classes as your backing store, then on each addition/removal of an item, you would need to be sure to raise the CollectionChanged event for your custom collection implementation.
However, I need to ask, why roll your own observable collection when Microsoft already provides the ObservableCollection<T> object, which you could possibly subclass and receive the functionality you're looking for for free?

How to assign PropertyChanged event handler to ObservableCollection owner

I need to handle the PropertyChanged event of an item in an ObservableCollection within the owner of the ObservableCollection. There has to be a more elegant way than:
ObservableCollection(MyViewModel) myViewModels = new ObservableCollection<MyViewModel>();
LoadMyViewModels(myViewModels); // populates the collection
foreach (MyViewModel myViewModel in myViewModels)
{
myViewModel.PropertyChanged += PropertyChangedEventHandler(MyViewModelPropertyChanged);
}
I'd like to pass the MyViewModelPropertyChanged event handler into LoadMyViewModels so I don't have to traverse the collection twice (once on load and once on event assignment).
MyViewModelPropertyChanged sets properties on the containing view that are reflected on the UI (the collection is bound to a TreeView and I need to enable/disable fields in the UI based on whether the item has been checked).
I've looked at most if not all the cited postings, but I'm a bit lost.
The above code does what I need it to do, but I know there's a better way. Please cite the appropriate reference or code sample.
Thanks.
A BindingList may give you what you need...
BindingList relays item change notifications when its items implement INotifyPropertyChanged.

When is CollectionView.Refresh() usually required?

I am not familiar at all with using WPF and the application that I am working on had a ListCollectionView.Refresh() every time one of the objects in the ListCollection View Model would change which made the application extremely inefficient (ListCollectionView is binded to List Collection View Model). After removing the Refresh() the application runs a lot smoother and still updates when changes occur in ListCollection View Model. After looking around it seems that any time there is a filter or re-sort on the CollectionView there is an implicit call to Refresh(). So when is it necessary to Refresh() and recreate the CollectionView?
If I understand you correctly, you have a ListCollectionView that is bound to a ListCollectionViewModel (your own class). As long as ListCollectionViewModel implements INotifyCollectionChanged properly (eg. it inherits from ObservableCollection<T>), and the items in the collection implement INotifyPropertyChange properly, then it is not necessary to call Refresh().
CollectionView doesn't handle CollectionChanged events where more than one item is changing (an exception occurs); Refresh() can be used instead, which is why you are seeing calls with filters and sorts.

Binding List and UI controls, not updating on edit

I am binding a BindingList two way to a listbox. The Binding list contains a number of images which apparently only update the listbox if items are added or removed from the binding list. How can I make it so that the bindinglist also raises the listchanged event when an item is modified?
EDIT: I find the problem I am having is that a property of an object is not being changed, rather the base object.
BindingList<ImageSource>();
This wont work however if I did this:
BindingList<Image>();
And then set the binding path to Image.Source, it would update correctly and this is because a property of the Image has changed but in the case of the first example, only a direct item in the list has changed. So how may I get the same behaviour as the second example?
FINAL EDIT : It seems that using ObservableCollection instead of BindingList fixes this issue. I was under the impression that they were identical in notifying of changes in the collection. Full answer below
The list does raise that event but only if the underlying items provides the proper notifications via INotifyPropertyChanged.
The BindingList differs from ObservableCollection in that BindingList does not notify that its direct items are changed (except when items are added or removed from the collection). ObservableCollection however implements INotifyCollectionChanged and INotifyPropertyChanged interfaces. This means that any change to direct items of an ObservableCollection are reported to the UI.
If you are using bindings to direct items and need to update items and not properties of those items, it seems that you have to use ObservableCollection. Another solution would be to derive from BindingList and implement INotifyCollectionChanged.
I am not an expert but this is what i have gathered during the last hour, if anyone has anything to add or correct please let me know.

Why does Combobox binding not work with List<T>

I am trying to bind a combobox in WPF like this,
<ComboBox Width="350" Margin="5" IsEditable="True" ItemsSource="{Binding ComboboxItems}" DisplayMemberPath="Name">
public List<ExpandoObject> ComboboxItems
{
get
{
return comboboxItems;
}
}
If I set the list like this in my view model,
comboboxItems.Clear();
foreach (ExpandoObject comboboxItem in repository.LoadComboboxItems())
{
comboboxItems.Add(comboboxItem);
}
NotifyPropertyChanged(this, x => x.ComboboxItems);
The NotifyPropertyChanged seems to work because a breakpoint on the ComboboxItems is hit, but then the combobox list does not update on the GUI. Snoop shows no binding errors or anything like that.
The first time the above list is updated it seems to work, so it can't be anything to do with using an ExpandoObject I don't think.
UPDATE:
Using an observable collection works, but I would like to know if I have a setter in a viewmodel like this which binds to a control on the GUI,
public string Database
{
get
{
return importData.Database;
}
set
{
importData.Database = value;
NotifyPropertyChanged(this, x => x.Database);
comboboxItems.Clear();
foreach (ExpandoObject comboboxItem in repository.LoadComboboxItems())
{
comboboxItems.Add(comboboxItem);
}
NotifyPropertyChanged(this, x => x.ComboboxItems);
}
}
Is that setter being run on a background thread? The reason I ask is will the setter block the GUI if it takes a while to load the items from the database?
This is where I went wrong the first time trying to use an ObservableCollection, by running the code in the setter on a background thread using BackgroundWorker. Updating the ObservableCollection caused an exception under those conditions.
I think it will work if you use an ObservableCollection<> instead of a List<>. Unless you use an ObservableCollection, xaml will not know that the contents of the list changed.
To answer the second part of your question, if you're trying to set the ObservableCollection using a BackgroundWorker directly, you will get an exception. One of the ways to get around the exception is to set the ObservableCollection using BeginInvoke
One thing to note: you don't need to call NotifyPropertyChanged(this, x => x.ComboboxItems); in your setter. This is because the property isn't changing; the property is a collection and the collection contents are changing. ObservableCollection will notify subscribers that the contents have changed.
Use ObservableCollection instead of the List.
Quoting MSDN:
You can enumerate over any collection that implements the IEnumerable
interface. However, to set up dynamic bindings so that insertions or
deletions in the collection update the UI automatically, the
collection must implement the INotifyCollectionChanged interface. This
interface exposes the CollectionChanged event, an event that should be
raised whenever the underlying collection changes.
WPF provides the ObservableCollection class, which is a built-in
implementation of a data collection that implements the
INotifyCollectionChanged interface.
Before implementing your own collection, consider using
ObservableCollection or one of the existing collection classes,
such as List, Collection, and BindingList, among many others.
If you have an advanced scenario and want to implement your own
collection, consider using IList, which provides a non-generic
collection of objects that can be individually accessed by index.
Implementing IList provides the best performance with the data binding
engine.

Categories

Resources