Programmatically multiselection update is slow in listbox - wpf

I try to programmatically update the selected items in a listbox, with extended selection mode. Here is how I do it:
foreach (var selectedItem in ItemsForSelection)
{
_myList.SelectedItems.Add(selectedItem);
}
My problem is, that when the number of the selected items is big, the update is very slow.
The root of the problem is that listbox doesn't derrive from MultiSelector, which can be tweaked to perform a fast bulk update, by using the methods BeginUpdateSelectedItems and EndUpdateSelectedItems.
Is there a way to get a similar result in a listbox?

Is there a BeginUpdate and EndUpdate method available in the ListBox...
_myList.BeginUpdate();
foreach (var selectedItem in ItemsForSelection)
{
_myList.SelectedItems.Add(selectedItem);
}
_myList.EndUpdate();
That is assuming that _myList is a ListBox...The pair for Begin/End Update methods freezes the WM_PAINT message and unfreezes respectively thereby making it flicker free and fast.

After adding a chunk of items, try pumping the dispatcher by pushing a dispatcher frame into the dispatcher.
http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherframe.aspx

There is a SetSelectedItems(IEnumerable) available on ListBox you could use. This function wraps selection changes in a SelectionChange.Begin/End (unfortunately only available internally of course) which ought to result in only a single selection change event going out.
Note that SetSelectedItems is protected, so you'll have to use your own ListBox derivative to call it. Odd choice, that.

Related

Winforms Listview checkedItems missing

Basically, I have a listview inside my form. In order to make the process of selecting the different items in the listview quicker, i have to add a "select all items" checkbox.
For Each lvItem As ListViewItem In Me.lvwDatos.Items
lvItem .Checked = True
Next
That's about it, very simple. Once i click on the select all checkbox, i can see clearly how all the elements go into checked state. However, on the next step, when i want to loop through the selected items in my code and do whatever tasks should be applied to them, i'm finding that ALL elements are unchecked. What's making them loose their state?
Ok, nevermind, i found the problem...that's how it is supposed to be, there's no problem in the listview, it's just the chain of events that were taking place that broke it all...legazy code, as usual...
This is why I have designed Better ListView component which have this behavior fixed (and many other quirks of .NET ListView).
There is also a free Better ListView Express, if you are interested.
The checked item collection is maintained separately and you always get its actual state.

Implementing WPF Progressbar for long running methods

We have a 3- tier architecture(UI,BL,DAL) WPF application. I need to handle loading of WPF and DevExpress datagrid with large number of rows. The BL method will return an observable collection of objects which is to be binded to the WPF datagrid. If the number of records are vergy large then the UI become un-responsive. So we need to implement a solution such that show a progress bar with the percentage of the work completed as the BL method executes the query and process the data. Here I need to get the total number of records immediately when the query is executed and after processing the each row I need to show the current index of the item processing in the lable like "processing 1/2000 documents".
What is the best way to achieve the above feature. We are using MVVM pattern. Whether I need to change the way we do the fetching and processing the records in BL (currently the fectch and processing (Map value from datareader to custom object) inside a BL method). Alternatively I am looking for loading the rows in the datagrid in a paged manner as the user scrolls the datagrid.
Any links for samples is appreciated.
Edit:
#Big Daddy your solution
1)Add new properties to view model to get the TotalCount and PercentComplete.
2)Pass the viewmodel to the Search method.
3)Use the BGW to update the properties.
The above seems to a workable solution. But I am eager to know whether any other way of solving this without dependednt of the viewmodel. Any design patterns avaialble for this kind of operation?
You can use a BackgroundWorker to handle this. It will not block the UI while getting your data and will keep the UI responsive for the user. The BackgroundWorker has a ProgressChanged event that works very well with ProgressBars.
In the projects I've worked on, I've implemented BWs in a client-service/repository. Your view-model can make the calls into this class(es). The methods here will instantiate the BWs, do the work, report progress, and return the data. You'll need to report the progess on the UI, so set-up a property in your view-model and bind your ProgressBar's value to it, like this:
View-Model
private int _percentCompleted;
[DefaultValue(0)]
public int PercentCompleted
{
get { return _percentCompleted; }
set
{
_percentCompleted = value;
RaisePropertyChanged(() => this.PercentCompleted);
}
}
View
<ProgressBar x:Name="SourceBatchUploadProgressBar"
Style="{StaticResource GreenProgressBar}" Grid.Column="1" Grid.Row="1"
Value="{Binding PercentCompleted, UpdateSourceTrigger=PropertyChanged}"
Height="25" Width="200" Margin="5,0,10,5"/>
You'll need to have the BW's ReportProgress event update the PercentCompleted property for this to work. Something like this:
BackgroundWorker.RunWorkerCompleted += (o, e) =>
{
...Update progress
};
If you'd like more details, let me know.
So you have all the rows. What processing are you referring to? Rendering? The displayed status of rendering would always be 100% as it does not render until it is done rendering.
It takes the UI a long time to render 2000 rows. There is a lot of formatting and sizing going on.
Break up the UI to display like 40 rows per pages with next and previous page buttons.
If DevExpress datagrid does not support virtualization then look for a grid that does. For speed I like ListView GridView.
Wow a check. You are listening. I give you more.
So get the whole list of IDs at once if that is fast (and you can get a total count). Then just create the 40 objects on demand. If you want to get fancy create the next 40 on a BackGroundWorker. Disable the Next button when you start the BackGroundWorker and enable it in the Complete.

WPF Validation inside UI Virtualized ListBox

I need to do some kind of data validation in a WPF application I am developing
As far as I know, when you add ValidatesOnDataErrors=True to the Binding, everytime the Binding is resolved (it can be every time teh value changes, it can be when focus is lost), Binding engine checks the binding source, through IDataErrorInfo, access the interface, finds out if there is some error or not.
It sounds good, with only one caveat. In order for data to be validated, it needs to be rendered. If you happen to have an ObservableCollection of that entity bound to a ListBox with VirtualizingStackPanel.IsVirtualizing=True, only rendered items are validated. Since most items are outside viewport, they are not rendered.
How can I force every item to be validated? Removing UI virtualization is not an option.
I have found one way to do so. It's ugly. But it works. Assuming the UI virtualized list is myList
for (Int32 i = 0; i < myList.Items.Count; i++)
{
myList.ScrollIntoView(myList.Items[i]);
}
UpdateLayout();
That way, I get a list of all items. I scroll the list to every item in that list. And I update layout, because ScrollIntoView is asynchronous, I think. After that, every item has been rendered, every binding has been executed and every validation has been evaluated.
Are there better ways out there?

How would I loop through a collection in a separate thread and reflect the current item on the bound ListBox?

I have a ListBox bound to an ObservableCollection. The items in the collection each signify a different step with a method to perform that step. What I would like to do is have a BackgroundWorker loop through the collection, run each item's action method, and have the current step be reflected by the ListBox.
My first iteration used no threading and was just to get the step running going. Now I have created a ListCollectionView, set it to represent the data in the ObservableCollection, and have bound the ListBox's ItemsSource to it instead of the ObservableCollection. I noticed running through the steps still blocks the UI thread's updates even though I'm explicitly incrementing the CurrentItem.
I want to use the ListCollectionView inside a BackgroundWorker but most examples I'm finding are written assuming you are modifying the contents or sorting of the list. I don't wish to do this; I simply want to increment the CurrentItem for each iteration. I'm guessing simply referencing it won't get me very far as it is tied to items on the UI thread and the compiler will complain. Any thoughts or pointers would be much appreciated.
You shouldn't be seeing any complaints from the compiler, but you will be getting exceptions at runtime if you try to update anything that fires an INotifyPropertyChanged PropertyChange from the background thread. There are a few ways around this. You can use Dispatcher.Current.Invoke to just do updates from inside your DoWork method. You can try to rig something through a ProgressChanged handler (runs on the calling thread) and calls to ReportProgress for each completed step. Or you could do the updates in the RunWorkerCompleted handler (also runs on calling thread) and maybe use a series of consecutive BackgroundWorker calls that are triggered from the previous one's completed handler (this can get messy if you don't manage the steps through a generic queue or something similar).
You need to check out WPF Cross-Thread Collection Binding – Part 4 – The Grand Solution and the source I think is on QuantumBitDesigns.Core
This allows you to update a list from another thread and have the changes automaticaly reflected on a bindable observable collection.
Figure: The demo app shows multiple updates to a single ObservableCollection
I have used this on multiple projects with fantastic results.

how to get the wpf toolkit datagrid to show new rows when bound to dataset

Is there a way to get the wpf toolkit DataGrid to show new rows when its bound to a DataSet? In other words, I have a DataGrid, I've set its ItemsSource to a DataTable, and everything seems to work fine, except I can't get the grid to show rows that I add to the DataTable programatically.
You can set the datagrid.ItemsSource to an ObservableCollection<T>.
ObservableCollection<YourItem> items = new ObservableCollection<YourItem>();
yourDataGrid.ItemsSource = items;
Then you should be able to just add to the collection to get the new rows to appear:
Edit: Based on updated info.
if (Dispatcher.CheckAcces())
{
// already on thread UI control was created on
items.Add(<your item>);
}
else
{
// update on same thread UI control was created on
// BeginInvoke would invoke a delegate which would call items.Add(<your item>)
Dispatcher.BeginInvoke(...);
}
See Dispatcher. All System.Windows.UserControl objects have a Dispatcher property.
I'm not sure how anyone would have figured this out, especially since I didn't mention it, but the problem was that I was updating the dataset from a thread other than the form's main thread, i.e. the thread that the grid was created on. You can do updates from another thread, but you can't do inserts, although I don't know why. If someone could shed some light on that, I'd appreciate it. My guess would be that the grid checks to see if the insert is coming in on another thread, and if so, it ignores it because that would cause an exception.

Resources