Click here to Skip to main content
15,881,803 members
Articles / Desktop Programming / WPF
Tip/Trick

WPF Rendering and Binding Performance Comparison

Rate me:
Please Sign up or sign in to vote.
4.89/5 (4 votes)
25 May 2014CPOL3 min read 20.9K   209   11   5
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

C#
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

C#
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

C#
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

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
Hong Kong Hong Kong
Front-office Technologist in Finance Industry, who also has an interest in mobile and IOT technologies

Comments and Discussions

 
QuestionNice Pin
Yang Kok Wah25-May-14 23:25
Yang Kok Wah25-May-14 23:25 
AnswerRe: Nice Pin
Andrew Lai27-May-14 5:23
Andrew Lai27-May-14 5:23 
GeneralRe: Nice Pin
Yang Kok Wah27-May-14 8:19
Yang Kok Wah27-May-14 8:19 
GeneralRe: Nice Pin
Andrew Lai27-May-14 16:51
Andrew Lai27-May-14 16:51 
AnswerRe: Nice Pin
Andrew Lai27-May-14 5:26
Andrew Lai27-May-14 5:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.