Click here to Skip to main content
Click here to Skip to main content

WPF Rendering and Binding Performance Comparison

, 25 May 2014
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Andrew Lai
Team Leader
Hong Kong Hong Kong
Front-office GUI team lead working in a financial institution
Follow on   LinkedIn

Comments and Discussions

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

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140814.1 | Last Updated 25 May 2014
Article Copyright 2014 by Andrew Lai
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid