I have a ICollectionView which serves as an input source for a WPF ListView. The number of items (text messages) in the CollectionView could be upto 10 thousands. I want to add a sorting creiteria to the collection view based on the TimeStamp. The latest added message should be on top.
MyCollectionView.SortDescriptions.Add(new SortDescription("TimeStamp", ListSortDirection.Descending));
Question: If I use the above sorting criterion, does the sorting takes place every time I add a new message? Or does the CollectionView maintains a sorted list internally and in my scenerio (i.e. having TimeStamp as Sorting), it will only need to compare the new incoming message's TimeStamp with the last added message's TimeStamp?
You'd do better NOT relying on collectionview sorting and NOT presenting 10,000 items to a listview.
The answer:
By default, when you’re using a CollectionView(Source) to do sorting, grouping and filtering in an itemscontrol, the sorting/grouping/filtering behavior will update when you explicitly refresh CollectionView or
when you add or remove an item to the collection.
You should therefore not sort the collection. I think your best bet is likely to instead insert at position zero of an un sorted observablecollection.
If you're inserting lots of items quickly then that's still going to burn through cycles. These are on your UI thread so you best not plan on anyone trying to interact with your UI. If these messages come in fast enough you will just have a blur anyhow.
I think you should probably instead only show the user the latest few messages in a "live" view. Don't let them sort.
If they need to see 10,000 then put that in another view that shows them a static snapshot. See what your performance is like and think about iterating when you have something concrete to play round with.
Related
With a list view containing items I can reorder which gives a nice UI effect.
I have my item source for the list view hooked up to an observable collection. Is there anyway with the framework I could programatically simulate a reorder and give the same effect you would have if you actually reordering?
The only way I've been able to slightly achieve this is to literally clear all the items from my data source then repopulate after shuffling the items, however it doesn't look nice.
Well, you could sort the items in code-behind in a temporary helper array and then according to the order they are in in the sorted one start periodically moving items one-by-one in a small time interval (with DispatcherTimer) withing the collection - remove at it's index and insert somewhere it belongs. I think there is no built-in way to do it in a simpler manner.
I have a setup where potentially thousands of items (think 3000-5000) will be added to an ObservableCollection that is binded to some visual interface. Currently, the process of adding them is quite slow (approx. 4 seconds/1000 items), and of course the GUI is unresponsive during that time. What is a good method to handle moving that many items at once into a collection without worrying about the system locking up? I've looked at DispatcherTimer but I'm not sure if it will provide everything I need it to.
Another question - Is there something I can do to speed up the creation of these objects so that it doesn't take so long to add them to the collection? Currently I use them like so: Collection.Add(new Item(<params>)) Would generating the items beforehand, in a background thread probably, decrease the time it takes to add them by a noticeable amount?
Edit: Virtualization is not possible. The requirements specify a WrapPanel look, so the display is actually a ListBox which has a templated ItemsPanel
Edit2: According to the stopwatch, the bottleneck is actually putting items into my ObservableCollection. I will try changing that collection type and doing my own notification to see if that speeds it up substantially.
Edit3: So the answer is in one place - I solved this issue (with help from below) by creating a class which inherits from ObservableCollection. This class did two things - expose a method to add collections at one time, and added the ability to suppress the CollectionChanged Event. With these changes the time it takes to add 3000 items is roughly .4 seconds (97% improvement). This link details the implementation of these changes.
You've said 1000, so I'll stick to that number just for instance.
IIRC, the observable collection has a small drawback - if you add the items one by one, it raises notifies once per each item. That means that you have 1000 notifications for 1000 of items and the UI thread will run at deadly speed just to keep up with redrawing the screen.
Do you need to redraw ASAP? Maybe you can batch the additions? Split the 1000 of items into a few packed of 100 items, or a little more packets of 50 or 20 items. Then, instead of putting all items one by one, put them in packets. But beware: you have to use some methods like AddRange implemented by the collection it self, not by LINQ, or else you will again have one-by-one insertion. If you find such method, it should cut the number of events significantly, because the collection should raise the Changed event only once per AddRange call.
If observable collection does not have AddRange, either use different collection, or write your own, just a wrapper will probably be sufficient. The goal is to NOT raise Changed event at every single Add(), but after a reasonable count of them, or - maybe just skip raising Changed when items are added and raise Changed at some regular time intervals? This would be beneficial especially, if your data "flows in" indefinitely at a constant rate.
Of course, at that number of items coming onto the screen, you may just as well be held at the rendering it self. If your ItemTemplates are complicated, a 1000 of objects times 1000 of instances of visual layers/properties may simply kill the user experience. Have you simplified the ItemTemplates to the bare minimum?
Last thing: consider using virtualizing StackPanels as the ItemPanels in your ItemsControl/ListBoxes. It can greatly reduce the memory footprint and the number of items drawn at a single point of time. This will not necessarily help in the number or events raised, but it may help greatly when you have complex item templates!
Edit: you are using ObservableCollection, so I've assumed WPF/Silverlight.. update the question if this is not correct
WPF Binding supports concurrency for this reason. Try setting Binding.IsAsync to true. In addition.
Don't use ObservableCollection<T>, it is slow for this because each time an item is added it raises events. Use something faster like List<T> and raise your property change notification after all your items are added.
Pre-create your items in a background thread, then push them into your collection.
Check other parts of code involved to see if there is bloat, and trim.
By request, here is how I solved this issue. I started by creating a class which inherits from ObservableCollection. This class did two things - expose a method to add entire collections at once, and added the ability to suppress the CollectionChanged Event. With these changes the time it takes to add 3000 items is roughly .4 seconds (97% improvement). This link details the implementation of these changes.
Another thing you can try: subclass ObservableCollection and make it support bulk loading (AddRange). Here is an article:
AddRange and ObservableCollection
for second question
if in your GUI you are using WPF technologie, you can increase performance using VirualizingStackPanel allowing you to create only visible items
I'm having an application, that periodically polls a web service (about every 10 seconds). In my application logic I'm having a List<Message> holding the messages. All messages have an id, and might be received out of order. Therefore the class implements the Comparable Interface.
What WinForm control would fit to be regurarly updated (with the items in order). I plan to hold the last 500 messages. Should I sort the list and then update the whole form? Or is data binding approriate (concerning performance)?
If you are working with WinForms, I shall recommend a ListView-control with View-property set to Details along with a BackgroundWorker-control.
If the list is going to be changing each time, and your order is not coming in consistently, I'd just sort your list and reupdate the entire UI.
You should be able to do the list fetching + sorting in a background thread, so the main "UI" blocking will just be redrawing the UI. With 500 elements, this won't be fast, but it should be tolerable.
i'd use databinding with the BindingList in System.ComponentModel wrapping your List.
BindingList in this case, would allow you to update your List object with new data and will automatically re-bind your data to the control that you are using for display.
which control you use would depend on how you want it to look. any control that supports databinding to a collection would work, though.
C#: What is the best way to implement a 'filter' mechanism for ListView Items?
I want to filter out some listview items from view in 'details' mode where it contains rows and columns. What would be the best option to create such a mechanism where I could rapidly remove the items in question from view, leaving the others intact, and putting them back into the listview when there is no more need to filter out listview items? Should I remove/copy them to a List and just and add them back when done or would there be a better method of doing this more effeciently? The listview will be handeling about 100-500 items.
If you are working with a databound control you will have this facility within the binding framework.
If not, I would probably store all the items for the list separately and populate the control in full each time, based on any contextual requirements such as filtering. The code to iterate through the list and move items not required at present is probably unnecessarily complicated. A full repopulate each time will be easier and won't differ much in terms of computational expense.
This behavior is built in to BindingSources using DataSets in .Net 2.0.
For .Net 3.0+, you can use LINQ.
So I have a ListView with an upper limit of about 1000 items. I need to be able to filter these items using a textbox's TextChanged event. I have some code that works well for a smaller number of items (~400), but when I need to re-display a full list of all 1000 items, it takes about 4 seconds.
I am not creating new ListViewItems every time. Instead, I keep a list of the full item collection and then add from that. It seems that the .Add method is taking a long time regardless. Here is a little sample:
this.BeginUpdate();
foreach (ListViewItem item in m_cachedItems)
{
MyListView.Add(item);
}
this.EndUpdate;
I have tried only adding the missing items (i.e., the difference between the items currently being displayed and the total list of items), but this doesn't work either. There can be a situation in which there is only one item currently displayed, the user clears the textbox, and I need to display the entire list.
I am not very experienced in eeking performance out of .NET controls with a large sample like this, so I don't really know a better way to do it. Is there any way around using the .Add() method, or if not, just e better general solution?
There is a better way, you can use the VirtualMode of the list view.
That documentation should get you started. The idea is to provide information to the ListView only as it's needed. Such information is retrieved using events. All you have to do is implement those events and tell the list view how many items it contains.
AddRange is much faster than add
MyListView.AddRange(items)
There are two things to address this:
Turn off sorting while manipulating the list contents.
Hide the list so it doesn't try to paint.
The 1st point is the biggest performance gain in list manipulation out of these two. To achieve this, just set the ListViewItemSorter to null for the duration of the modification and set it back at the end.
For the 2nd option, I often draw the list to a bitmap and then show that bitmap in a PictureBox so the user doesn't see the list disappear, then just reshow the list when I'm done.
Also note that you can hide items and so make them invisible without removing them. So add all your items the first time around and then later on you just hide the ones no longer needed and show the ones that are.