Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Rendering and Binding Performance Comparison

0.00/5 (No votes)
25 May 2014 1  
WPF performance comparison in 3 ways of refreshing data

Introduction

In my workplace (a financial institution), responsiveness of Windows application is critical and there are many factors which will affect the performance. These factors include network, dependent external services and software design.

In this tip, I would like to investigate and compare the performance on different ways to refresh data in a typical WPF application.

Background

In this example, there is a window full of WPF controls (I have added multiple instances of the same user control for simplicity). The user control contains a typical set of WPF controls, including Label, TextBox, Slider, ComboBox, CheckBox, DataGrid. This is a typical MVVM design.

  • View - DogDetails.xaml user control
  • ViewModel - DogVM.cs
  • Model - Dog.cs

There are four buttons at the top of the application. The functionality of these four buttons are the same, it refreshes the whole window with another set of data (a list of Dog). However, the implementation of the three buttons are different. The aim is to test and compare the performance of each of them.

1. Re-Render and Re-Bind

  • Re-generate the data (list of Dog object)
  • Re-constructs all the ViewModels, one per DogDetails user control
  • Re-constructs all UserControls and rebind to ViewModels

2. Re-Construct VM and Re-Bind

  • Re-generate the data (list of Dog object)
  • Re-constructs all the ViewModels, one per DogDetails user control
  • Re-use UserControls and rebind to ViewModels

3. Re-use VM and Re-Bind

  • Re-generate the data (list of Dog object)
  • Re-use ViewModels and set the Model referenced by each ViewModel
  • Re-use UserControls and rebind to ViewModels

4. Re-Notify Only

  • Re-generate the data (list of Dog object)
  • Re-use all the ViewModels and UserControls by just switching the Dog object referenced by DogVM and call NotifyPropertyChanged for all fields

To measure the performance of rendering, I followed the advice from here.

Using the Code

Here are the various implementations of refreshing. They are all in MainWindow.cs:

1. Re-render control and Re-bind

 public void RegenAndBind()
        {
            allVMs.Clear();
            allDetailsControls.Clear();

            start = DateTime.Now;
            int i = 0;
            for (int row = 1; row < _mainGrid.RowDefinitions.Count; row++)
            {
                for (int col = 0; col < _mainGrid.ColumnDefinitions.Count; col++)
                {
                    //Reconstuct VM
                    DogVM thisvm = new DogVM();
                    thisvm.SetDog(allitems[i]);

                    //Reconstuct UserControl and Set the Grid position
                    var dogDetails = new DogDetails();
                    //Rebind
                    dogDetails.DataContext = thisvm;
                    //Add the user control to window
                    _mainGrid.Children.Add(dogDetails);
                    Grid.SetColumn(dogDetails, col);
                    Grid.SetRow(dogDetails, row);

                    //Keep References
                    allVMs.Add(thisvm);
                    allDetailsControls.Add(dogDetails);
                    i++;
                }
            }            
        } 

2. Re-construct VM and Re-bind

 public void ReconstuctVMAndbindOnly()
        {
            allVMs.Clear();
            start = DateTime.Now;
            int i = 0;
            for (int row = 1; row < _mainGrid.RowDefinitions.Count; row++)
            {
                for (int col = 0; col < _mainGrid.ColumnDefinitions.Count; col++)
                {
                    //Reconstuct VM
                    DogVM thisvm = new DogVM();
                    thisvm.SetDog(allitems[i]);
                    //Bind VM to each UserControl
                    allDetailsControls[i].DataContext = thisvm;
                    //Keep Reference
                    allVMs.Add(thisvm);
                    i++;
                }
            }
        } 

3. Re-use VM and Re-bind

        public void RebindOnly()
        {           
            start = DateTime.Now;
            int i = 0;
            for (int row = 1; row < _mainGrid.RowDefinitions.Count; row++)
            {
                for (int col = 0; col < _mainGrid.ColumnDefinitions.Count; col++)
                {
                    allVMs[i].SetDog(allitems[i]);
                    allDetailsControls[i].DataContext = allVMs[i];         
                    i++;
                }
            }
        } 

4. Re-notify only

        public void NotifyOnly()
        {
            start = DateTime.Now;
            int i = 0;
            for (int row = 1; row < _mainGrid.RowDefinitions.Count; row++)
            {
                for (int col = 0; col < _mainGrid.ColumnDefinitions.Count; col++)
                {
                    //Using the kept reference, just set the Dog object referenced by VM
                    //NotifyPropertyChange is handled by the VM
                    allVMs[i].SetDog(allitems[i]);
                    i++;
                }
            }
        } 

Points of Interest

Here's the performance figures I obtained from my moderate spec PC when the application is opened in full screen (Intel i5-2500K 3.3Ghz, 16GB ram, SSD on windows 7, VS2013)

I also note that having a DataGrid in DogDetails.xaml has quite a big performance impact.

Here are the average of 10 refreshes for each implementation. (With DataGrid in UserControl)

  1. Re-render control and Re-bind: 1126.2ms
  2. Re-construct VM and Re-bind: 403.6ms
  3. Re-use VM and Re-bind: 373.8ms
  4. Re-notify only: 343.6ms

Here are the average of 10 refreshes for each implementation. (Without DataGrid in UserControl - comment the DataGrid in DogDetails.xml):

  1. Re-render control and Re-bind: 680.1ms
  2. Re-construct VM and Re-bind: 144.4ms
  3. Re-use VM and Re-bind: 129.8ms
  4. Re-notify only: 96.6ms

Here's the summary of the findings:

  • DataGrid rendering performance is quite poor, even when the dataset is really small. I might investigate this further, maybe using a 3rd party grid.
  • Most of the performance gain is obtained by avoiding the reconstruction and building of the UserControl.
  • In this example, there is only a very small gain (around 10 to 30ms) after avoiding reconstruction of the ViewModel. This is because the ViewModel is really simple in this example. The benefit is highly depending on the complexity and performance of the ViewModel constructor.
  • Size of the window has a big effect on performance.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here