I have a collection of objects "SourceItemCollection" used to populate the ListBox with checkboxes. Each item of the collection consists of two fields, Item and IsChecked (I've created a small class for this combined items). I would like to track all changes when user selects or deselects something from the collection (not when the button is pressed or something else, but "on-sight"). For this I would like to use another collection "SelectedItems" which will consist only of Items, without IsChecked property (I create and would like to use this collection outside the abovementioned small class of the source collection's items).
The tricky thing is that "SourceItemCollection" doesn't change itself, it always stays the same, changes only the IsChecked property of each item. I do get a notification each time I tick or untick something, but I get it inside the small class of my combined items and I can't access my SelectedItems collection from there.
Related
I have a set of collections based on a class called "Foo", and the class includes a property "Bar", along with a fairly long list of other values to be displayed and edited.
I am using two semi-independent UI elements that use the "Foo" collection in an "explorer" like display with a TreeView on one side and a detail ListView on the other. The Treeview has collection of Foo collections (like a folder or registry key with subitems) that has subitems that are the individual Foos. Which collection item it belongs under is dictated by the Bar property. You can think of this like a Foo that is a file and a property of the file is the file path.
Each Foo is displayed in a custom UserControl. If you click on a "container of Foos" on the left TreeView, the SelectionChanged method displays the Foos that are in that collection in the right ListView, and if you click on a specific Foo item on the left it displays just that Foo in the right ListView.
This is all working well and we can change the Bar setting in the ListView and have it update the underlying data and display within ListView (using INotifyPropertyChanged).
What I'd like is to have the changed Bar value, changed in the ListView, affect the ListView display on the left automatically.
Any ideas on how to accomplish this (or reorganize to get the same effect)?
I am experimenting with WPF and MVVM in our system. However iam having a problem with keeping things selected in lists using only MVVM ( without doing extra CollectionViews ).
What i currently have is the list
ObservableCollection<ReservationCustomerList> Customers;
And then a property storing the selected Customer
ReservationCustomerList SelectedCustomer;
In my opinion now, when the list reloads (actually from another thread async), the selection should be able to be kept, however this does not happen.
Does someone have a nice clean way of achieving this ?
The way we did it was that we did not replace the collection. We added/removed the entries and updated existing entries if required. This maintains the selection.
You can use LINQ methods like Except to identify items that are new or removed.
In case the reloaded list still contains the last selected item and you want that item to be selected, then you can raise the PropertyChange event for the property SelectedCustomer after your collection gets reloaded.
Please make your sure your viewmodel class implements INotifyPropertyChanged interface.
you can use the ICollectionView to select the entity you want.
ICollectionview view = (ICollectionView)CollectionViewSource.GetDefaultView(this.Customers);
view.MoveCurrentTo(SelectedCustomer);
in your Xaml the itemsControl must have IsSynchronizedWithCurrentItem=true
or if the ItemsControl has a SelectedItem property you can simply bind it to your SelectedCustomer Property.
When you "reload" your collection you basically replace all values in it with new values. Even those that look and feel identical are in fact new items. So how do you want to reference the same item in the list when it is gone? You could certainly use a hack where you determine the item that was selected by its properties and reselect it (i.e. do a LINQ search through the list and return the ID of the matching item, then reselect it). But that would certainly not be using best practices.
You should really only update your collection, that is remove invalid entried and add new entries. If you have a view connected to your collection all the sorting and selecting and whatnot will be done automagically behind the scenes again.
Edit:
var tmp = this.listBox1.SelectedValue;
this._customers.Clear();
this._customers.Add(item1); this._customers.Add(item2);
this._customers.Add(item3); this._customers.Add(item4);
this.listBox1.SelectedValue = tmp;
in the method that does the reset/clear works for me. I.e. that is the code I put into the event handling method called when pressing the refresh button in my sample app. That way you dont even need to keep references to the customer objects as long as you make sure that whatever your ID is is consistent. Other things I have tried, like overwriting the collections ´ClearItems()´ method and overwriting ´Equals()´ and ´GetHashCode()´ didn't work - as I expected.
I'm working with ListCollectionView objects to display lists of items. Currently, I'm building a screen that has two of these lists - one, completeList, holds all available items, the other one, sortedList, holds a subset of them with the item order being relevant. Possible actions here are
add or remove any of completeList's items to/from sortedList
move items up or down in sortedList
save the content of sortedList.
Now, my question is this: is there any possibility to insert items into sortedList at a defined position?
Right now, they will always be added at the end of the list, regardless of the currently marked item, and I didn't find a way around it - apart from the obvious dirty hack, which would have me store all items after the desired position, remove them from the list, add the new item, then re-add all stored items in the correct order.
Does ListCollectionView offer any such functionality, or is there another CollectionView class that would do the trick?
You're actually asking for something that's a logical contradiction. Suppose I have a ListCollectionViewsorted alphabetically:
American
Continental
Festival
Imperial
Tower
Worldwide
Should I be able to insert Luxor between American and Continental? Not if the view is sorted. There's only one place that item can go. And where it appears in the view is independent of where it might appear in the underlying list.
Without knowing more about your application, it's hard to know exactly what to suggest. But if a collection view is sorted, the way to make an item appear at a specific place in the view is to assign its sort key(s) a value that will, once the view is refreshed, cause it to appear in the desired location.
A fairly trivial (and generic) way of doing this is to add a DateTime property to the data item class, set it to DateTime.Now in the item's constructor, and make it the last sort key that the view uses. Then, when adding a new item, set its other sort key properties to the value of the currently selected item. If you do this, new items will always appear in the appropriate place, so long as you don't change the values of any of the sort key properties.
Having said that, from the other features you want to support, I believe that you shouldn't be using a ListCollectionView at all for what you're calling sortedList. This list isn't sorted. It's ordered, which is not at all the same thing. When the user moves an item up in the list, you actually want to change its position.
What you probably want to do is implement the list as an ObservableCollection, and wrap it in a view model class that exposes Items, SelectedItem, AddNewCommand, MoveUpCommand, MoveDownCommand, and SaveCommand properties. Then you can bind the ItemsSource and SelectedItem properties of a ListBox or ListView to Items and SelectedItem properties in the class, and bind buttons or hyperlinks or whatever in the UI to the commands. The commands will manipulate the Items property, using Remove and Insert, and since the Items is an ObservableCollection, the UI will stay in sync.
I have a render-heavy item template in an ItemsControl and want to minimize the recreation of child item templates when ItemsSource signals a change. I am wondering if, because ObservableCollection can tell WPF precisely what has changed (as opposed to just the whole list), if it is more efficient in rendering changes to the collection, or if WPF is smart enough to reuse previous item views if it detects the same item is still in the changed list.
Your suspicion is correct. WPF will not reuse previous views. If you replace the ItemsSource of an ItemsControl with a new List, it will create completely new views for each item in the list, even if the same items were in the old list.
You can test this yourself by putting a custom control in the ItemTemplate and adding a breakpoint or debug logging to its constructor. If you replace the ItemsSource with an identical list, you will see your control constructed once for each item in the list. On the other hand, when an item is added to an ObservableCollection you will only see it called once.
Note that the ItemsControl can reuse the container (such as ListBoxItem) if you are using a virtualizing panel and have container recycling enabled. See Link. It still can't reuse the contents of the container, however.
ObservableCollection only informs of addition and removal of objects - so perhaps not as precise as what you were expecting (if an object within the list changes, ObservableCollection will not fire off any notifications).
I've got an ObservableCollection assigned to ItemsSource of a listbox. Listbox is using a DataTemplate which has a usercontrol in it which has items bound to each listboxitem's properties.
I have an up and down button on the usercontrol which moves an item up or down the list. The list is sorted by the property that I'm changing. Click up or down, the DisplayOrder property is changed, I'm using INotifyProperty to tell the ObservableCollection it needs to re-sort.
What is the best way for the usercontrol to get the item count so that I can disable the down button when an item reaches the bottom of the list. (The top is easy, I compare to 0)
I see two ways of handling this.
The first is to pass a handle of your collection to each of your items (when they get added to the collection) so that they can calculate if they are the first or last item themselves.
The other is to expose writable properties on your items, such as CanGoUp and CanGoDown, and your parent control becomes responsible for setting these properties properly. I prefer this solution because it decouples the behavior of your parent list, from the child items. Even though the up/down buttons are placed on your child items, it's really a functionality of the parent list.
listBox1.Items.Count ?
this.Parent.Controls.Count?