Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BeginUpdate equivalent in WPF?

Tags:

c#

wpf

My problem is that I need to add a lot of items to a ListBox in WPF. In WinForms you'd just use the BeginUpdate(); method, add everything, and finally use the EndUpdate(); method.

So, how would I stop the drawing in a WPF listbox until every item is added and then draw everything in one go?

like image 575
Lith Avatar asked May 04 '10 22:05

Lith


2 Answers

Use the Dispatcher properly.

You have to add things to your ListBox (or its data source) from the Dispatcher thread, else the UI will explode. When you do this, you're either in a method on that thread already or (hopefully more likely) you're in a background thread and using Dispatcher.BeginInvoke to add the item.

When you kick the update across to the Dispatcher, use Dispatcherpriority.Normal as the priority. The Dispatcher has a queue of work items and your Normal items will push in (perhaps surprisingly) high in that queue.

The bit of code that WPF runs to update a data binding when the underlying data has changed runs at DispatcherPriority.DataBind, which is lower than Normal. That means the data binding won't typically be updated until all of your items are added (or alternatively, if your items take a long time to add, it might happen when the Dispatcher is idle between adding items).

The bit of code that actually renders your control (say, when its binding signals an update) runs at DispatcherPriority.Render and is even lower priority than the binding. That means that your control will only render when the Dispatcher has run out of bindings to update, which in turn will only happen when the Dispatcher has run out of item-adds to process.

If this sounds strange, remember that each layer (update - binding - render) causes a metaphorical flag to be set on the layer below - you don't get ten bindings and then ten renders happening. If your item adds are fast, you'll get all your adds followed by one bind and one render - which is perfect.

Basically: if you use the Dispatcher as its intended you'll have nothing to worry about. It seems "wrong" to have render as a relatively low priority on the Dispatcher but, actually, it's very clever :-)

like image 167
Dan Puzey Avatar answered Oct 18 '22 14:10

Dan Puzey


It sounds like you might be programatically adding the items to your list box one-by-one. A better approach would be to store the items you want to display in a model, and bind the model to the list box's data context. This will allow WPF take care of the rendering updates.

If you add snippets of your XAML and code to the question (to show us what you're currently doing), we might be able to provide a better answer.

EDIT: Added a very simple example.

Here's an example that binds a view model to the main window (the view) and then the XAML declares that the ListBox's data is bound to the view model's Numbers property.

MainViewModel.cs

public class MainViewModel
{
    public IEnumerable<int> Numbers
    {
        get { return Enumerable.Range(1, 1000); }
    }
}

MainWindow.xaml

<Window
  x:Class="WpfApplication1.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Height="350"
  Width="525"
  >
  <ListBox ItemsSource="{Binding Numbers}"/>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}

If you're just getting started with WPF, I can highly recommend Windows Presentation Foundation Unleashed by Adam Nathan. It's a great book and it's in colour to boot. Reading other books after this is like going back to Notepad after using Visual Studio.

For more on this Model-View-ViewModel stuff, check out Josh Smith's Advanced MVVM book.

like image 29
Damian Powell Avatar answered Oct 18 '22 14:10

Damian Powell