Adding items to ILIst as sourcecollection of a ListCollectionView - wpf

According to the documentation, you have to implement INotifyCollectionChanged on the source collection of a ListCollectionView to propagate adding/removing of collections items.
So I don't understand how his is working:
var parent = new Parent();
parent.Childs = new List<Child>();
parent.Childs.Add(new Child());
parent.Childs.Add(new Child());
parent.Childs.Add(new Child());
var view = new ListCollectionView(parent.Childs);
Assert.AreEqual(3, parent.Childs.Count);
Assert.AreEqual(3, view.Count);
parent.Childs.Add(new Child());
Assert.AreEqual(4, parent.Childs.Count);
Assert.AreEqual(4, view.Count);
Please, can anybody explain how this is working?

Why wouldn't this work? You are asserting after you have added the Child items. The Count property will always return the corrent number of items.
The reason why you need to implement the INotifyCollectionChanged interface is for a view to be able to know when it should refresh the UI.
For example, if you add an item to a data-bound collection that you are displaying in a ListView, the source collection needs to raise the CollectionChanged event for the new item to automatically show up in the view.

Related

Update the List view observable collection using MVVM

I have a usercontrol, with one list box and one list view control in it. For Listview i have bound the observablecollection of type TrafficManager class as shown below:
private static ObservableCollection<TrafficManager> _trafficCollection;
public ObservableCollection<TrafficManager> TrafficCollection
{
get { return _trafficCollection; }
set
{
_trafficCollection = value;
OnPropertyChanged("TrafficCollection");
}
}
I have bound this to itemsource of list view.
Now my requirement is on selection of the listbox item, i need to filter some items of the listview. For that i used a linq to get the desired rows from list view and added that to the list view collection. Before adding i did a listview Collection TrafficCollection.Clear() and then added to that collection.But now the issue is on selection of another item in list box i need the original listview contents again to carry out the filtering using the linq again. Here once the TrafficCollection.Clear() executes the original observable collection data vanishes. How do i maintain a backup of original observable collection data "TrafficCollection" of listview. Remember i have only one view. Is there anyway to do this? Please let me know.
you can use CollectionViewSource filtering, refer here
SO Link: Trigger Filter on CollectionViewSource
this will not clear original collection.

How do I get the UIElement when Collection changes?

I have a wpf Treeview which has a dynamic itemssource. The User can add and remove items at runtime.
I'm missing an event which gives me the currently added UIElement that was added to the treeviews itemsSource. So I guess I need to switch to OnCollectionChanged.
This is what I have:
// MyItemViewModel is a viewmodel for a TreeViewItem
// MyCollection is bound to hte Treeview's ItemsSource
public class MyCollection : ObservableCollection<MyItemViewModel>
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
// i like to have the UIelement which was added to the collection
// (e.NewItems contains the FrameworkElement's DataContext)
break;
}
}
}
Im following MVVM, as good as I can, and don't want to hold any view elements in the viewmodel.
I like to have an event that is fired when an item is added, which provides the new added UIElement in its sender or EventArgs.
I already tried ItemContainerGenerator class, but it's not useful inside a viewmodel since it requires already a UIElement Control.
You seem to be looking at this problem from the wrong direction... in MVVM, you can pretty much forget about the UI for the most part. So, instead of thinking how to get hold of the item that the user added into the collection control in the UI, think about accessing the data object that you added to the data collection in the view model that is data bound to the UI collection control in response to an ICommand that was initiated by the user.
So to me, it sounds like you need to implement an ICommand that is connected to a Button in the UI, where you add the new item into the data bound collection rather than any event. In this way, you'll always know the state of all of your data items.

Observable Collection is not updating the datagrid

I am using a Dim All_PriceLists As System.Collections.ObjectModel.ObservableCollection(Of BSPLib.PriceLists.PriceListPrime) where PriceListPrime implements Inotify for all properties in it.
I bound the All_PriceList to a datagrid as DataGrid1.ItemsSource = All_PriceLists but when I do All_PriceLists=Getall() where Getall reads and gets the data from the DB, the datagrid is not updating.
It updates only when I hack it this way:
DataGrid1.ItemsSource = Nothing
DataGrid1.ItemsSource = All_PriceLists
Could you please tell me where I have gone wrong or what I should implement. Thank you.
You have several solutions to your problem
Update the ItemsSource directly (instead of replacing the local member variable)
DataGrid1.ItemsSource = new ObservableCollection(Of PriceListPrime)(GetAll())
Update the ObservableCollection (as mentioned in another answer)
All_PriceList.Clear();
For Each item in Getall()
All_PriceList.Add(item)
Next
Set your DataContext to a view model and bind to a property of the view model
Dim vm as new MyViewModel()
DataContext = vm
vm.Items = new ObservableCollection(Of PriceListPrime)(GetAll())
The view model will implement INotifyPropertyChanged and raised the PropertyChanged event when the Items property is changed. In the Xaml your DataGrid's ItemsSource will bind to the Items property.
The problem is that you are not updating the collection, you are replacing it, which is different.
The datagrid remains bound to the old list and the updated data is stored in a new unbound collection. So, you are not hacking a solution, your are binding the datagrid to the new collection, which is correct.
If you want a more automatic solution, you should bind your datagrid to a dataset/datatable, which is totally different code.
You should update ObservableCollection instead of creating new one if you want the app to react on your changes.
So, clear All_PriceList collection and add new items into it. Example:
All_PriceList.Clear();
For Each item in Getall()
All_PriceList.Add(item)
Next
ObservableCollection doesn't support AddRange, so you have to add items one by one or implement INotifyCollectionChanged in your own collection.

Adding an Item to ItemsSource from a control

A control has an ItemsSource Property of type IEnumerable. If I try to add items to Items collection when ItemsSource is set I get an error "Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead."
A method for Removing Items is present here:
WPF - Best way to remove an item from the ItemsSource
However I cannot find a method to (based on the same interface) to add a new Item. The AddNew method does not take any arguments. From the sample at : http://msdn.microsoft.com/en-us/library/system.componentmodel.ieditablecollectionview.canaddnew.aspx I felt this to be the correct code:
IEditableCollectionView items = paneToDropInto.Items;
if (items.CanAddNew)
{
object newitem = items.AddNew();
newitem = contentToTransfer;
items.CommitNew();
}
However it does not work. It does add the new item. But it is a blank Item. Note contentToTransfer.
Figured it out. As pointed out by Tom and Djerry +1 both (thanks). I am just re referencing the new item which will not cause the original new item generated by AddNew to be saved (very stupid of me).
However there is another interface I can use (and did use):
IEditableCollectionViewAddNewItem items = paneToDropInto.Items;
if (items.CanAddNewItem)
{
object newitem = items.AddNewItem(contentToTransfer);
}

WPF binding not notifying of changes

I have a WPF sorting/binding issue. (Disclaimer: I am very new to WPF and databinding so apologise if I am asking a really dumb question :-))
Firstly, I have a linqToSql entity class Contact with an EntitySet<Booking> property Bookings on it.
If I directly bind this Bookings property to a ListView, the application seems to correctly notify of changes to the selected item in the ListView, such that a textbox with {Binding Path=Bookings/Comments} updates correctly.
// This code works, but Bookings is unsorted
var binding = new Binding();
binding.Source = contact.Bookings;
bookings.SetBinding(ItemsControl.ItemsSourceProperty, binding);
However, as I can't seem to be able to find a way to sort an EntitySet (see this post), I am trying to bind instead to an Observable collection, e.g:
// This code doesn't notify of selected item changes in the ListView
var binding = new Binding();
binding.Source = new ObservableCollection<Booking>(contact.Bookings.OrderByDescending(b => b.TravelDate).ToList());
bookings.SetBinding(ItemsControl.ItemsSourceProperty, binding);
But this doesn't seem to notify the comments textbox correctly such that it updates.
If anyone has a solution for either sorting the data before or after its bound, or another solution that will work that would be much appreciated.
You should bind to a CollectionView rather than the collection itself. That will allow you to specify whatever sorting criteria you require. Example:
var collectionView = new ListCollectionView(contact.Bookings);
collectionView.SortDescriptions.Add(new SortDescription("TravelDate", ListSortDirection.Ascending));
var binding = new Binding();
binding.Source = collectionView;
bookings.SetBinding(ItemsControl.ItemsSourceProperty, binding);
Hainesy,
Does the Booking object implement INotifyPropertyChanged to notify change in Comments property?
If not, you cannot expect TextBox which is bound to Comments property to be updated automatically when Comments change
Using ObservableCollection in this case will only get you the benefit of updating the view with changes when Booking objects are added or deleted from the collection
-Rajesh

Resources