Performance when loading a user control into region

Topics: Prism v2 - WPF 3.5
Jul 31, 2009 at 2:56 PM

I'm working on a simple demo application using the compoiste Application Library for WPF. I have an issue in that when I inject a user control into a region in the shell there is a considerable lag in the control rendering and being visible. When I include the same control in the shell (not in a referenced IModule) it appears instantly. I understand that I must take a performance hit at the point when I load controls into my shell from other modules but the delay is quite extreme. The control itself is a dataGrid (WPFToolkit) with around 2000 rows - there is no database work being done to generate the data for the grid.

 

The code Im using in the initialisation of my module is as below:

 this.regionManager.RegisterViewWithRegion(RegionNames.MainRegion, typeof(Test2));

Is there any reason Im getting such poor performance? The lag in the control rendering is around 5 seconds - a complete show stopper for using prism if it cannot do something so simple.

 

Thanks

Jul 31, 2009 at 4:34 PM

What is the performance if you don't load the DataGrid with data?  

Jul 31, 2009 at 4:59 PM

Its faster - but still has a lag of about a second even just to render the grid with columns headers and no rows in it.

Jul 31, 2009 at 5:28 PM

How many columns are we talking about?   The reason I ask is because I have not encountered such delays (that I agree are impractical);  I suspect something else is going on...    For example: http://www.global-webnet.net/webcast/RIAPrism.htm is a webcast I did for this BLOG where I show RIA, WPF, Silverlight and Winform Grids being populated (multi-targeting) with data and the view loads in an expected responsive manner.

I would review the output window and see if there are any complaints from WPF happening in the background.   If you remark out the datagrid do you still get the delay?  

 

Jul 31, 2009 at 5:40 PM

Thanks for getting back to me. Ive only got 3 columns on the grid.

I've created a sample at home which illustrates the issue I'm having. I shall zip it up and share it with this thread.

Jul 31, 2009 at 6:47 PM

Hi

I do not know the exact problem you are having, but you should take into account that ViewDiscoveryyou do not have explicit control over when the regions' corresponding views are loaded and displayed.” (from the Prism-v2 documentation), as opposed to ViewInjection. You can read more about these differences in this article from the Prism documentation.

Another possibility could be that the DataGrid is not being rendered using UI Virtualization (you can read about a similar situation in this post). If this is the cause of the issue, you can search the web for different ways to enable Virtualization in the WPF DataGrid.

Please let me know if this helps.

Damian Schenkelman
http://blogs.southworks.net/dschenkelman

Jul 31, 2009 at 7:16 PM

Ive tried using both view discovery and view injection and the problem persists. Ive also set the endable row and column virtulization methods on my grid.

Below is a zipped up copy of a small solution demonstrating the issue

http://files.getdropbox.com/u/416443/CALDemo.zip

Im grateful for your help,

Dav

Aug 1, 2009 at 12:46 AM
Edited Aug 1, 2009 at 1:43 PM

Hi Dav,

I took your demo and wrapped some infrastructure around it so that I could level the playing field.   The infrastructure is a combination of the Model-View-Presenter and Model-View-ViewModel (MVVM) patterns in addition to patterns I picked up from the Smart Client Software Factory days as well as the QuickStart example TopDownComposition in PRISM V2 drop 7.   The infrastructure cranked out is a scaled down version of what I will be releasing in August.

What you will find in the demo provided is that not only do both the Shell and Modules load in the same amount of time, but with a wee bit of P&P the performance (actual and perceived) is very fast. 

In the following capture clip I show before and after refactoring referenced PRISM project:
http://www.global-webnet.net/webcast/performance.htm   Blogged about HERE

All of the source code (your demo with infrastructure plugged in) available on the following link:
http://www.global-webnet.net/Webcast/CALDemo.zip

Bill

Architectural note:  This demo uses a combination of the Model-View-Presenter (MVP) pattern and the Model-View-ViewModel (MVVM) pattern, aka Presentation Model and Application Model.    By having multiple views share the same model (see Martin Fowlers Presentation Model) you can effectively share the same data without having to have a lot of complex logic to maintain state.   Each view can update the model and the other views will be notified via the observer pattern (INotifyPropertyChanged).

Trying to use MVVM alone has introduced the limitations that Martin Fowler discussed in THIS ARTICLE (paragraph above Figure 11).   As he suggest, it was the limitations that introduced the need for MVP.   Combining them gives us the best of both worlds.  

 

Aug 3, 2009 at 10:55 AM

Additionally, I suggest you use View Injection rather than View Discovery, although the latter sytax is easy, but because RegisterViewWithRegion use weak reference, so we are not sure when the GC occurs, the performance will be down.

Please use "RegionManager.Region["RegionName"].Add(new View())", and manully remove the view from region, which can improve the performance significantly.

Aug 3, 2009 at 12:58 PM

Actually the weak references are for the listeners.   I trust the problem they are trying to solve by doing this is to ensure that the registered listeners (ContentRegistered event) do not have a strong reference to the objects that contain the handlers.   Otherwise when the object is removed it can't be GC'd (memory leak) because the listener has a strong reference to it.   By using the WeakDelegatesManager to manage the registered listeners if objects get removed, they can be GC'd.   

Aug 3, 2009 at 1:41 PM

Hi Bill,

Thanks so much for taking the time to look at and modify my code. Am I correct in thinking that apart from adding the goodness of MVVM to my demo app, the perceived performance of my app has been increased by simply using the below code to let the xaml respond to the changes in the observable collection?

 

 if (i % 15 == 0)
System.Windows.Forms.Application.DoEvents();

 

 

Aug 3, 2009 at 3:45 PM

Yes, DoEvents() helps with the percieved performance as well as loading your data on a separate thread, e.g.,

Excerpt from Bootstrapper.cs follows:

            // Run ModuleInitialized() on separate thread
            Dispatcher.CurrentDispatcher.BeginInvoke(
                System.Windows.Threading.DispatcherPriority.SystemIdle,
                new ModulesInitializedDelegate(ModulesInitialized));

Which also helped with the actual performance.   If you take out the DoEvents() it will still be fast but if you remove the ModulesInitialized() event, running on a separate thread your original problem will raise it's ugly head.

 

Aug 3, 2009 at 5:07 PM

Thanks Bill,

I've read elsewhere that using DoEvents() to keep the UI responsive is not considered a best practice. Is there a way using WPF's dispatcher model to push changes to the UI to achieve similar perceived performance (that is seeing some rows appear in the grid earlier)?

 

Thanks

Aug 3, 2009 at 6:18 PM
Edited Aug 3, 2009 at 6:31 PM

You'll find the following WPF alternative to Application.DoEvents() in a number of places: http://www.cnblogs.com/sheva/archive/2006/08/24/485790.html, he wrote this one back in 2006.  

Bill

P.S. (Edited) the "bad things" refered to can result in a very quicky behavior of your application.  I can't remember the specifics but years ago (back when WinForms was the way to go) I chased a reentrancy problem caused/permitted by a misplaced DoEvents().   DoEvents() had its place and usage but if littered to generously it could cause serious problems.    I trust this falls true for WPF...

Aug 3, 2009 at 6:24 PM

Hi, dav_evans,

I remember DoEvent is the function of Winform, not WPF, which is another topic, rather than Prism. To approve my viewpoint, maybe I pzuuled, so I create a WPF app, but find no this function.

DoEvent can actually improve performance of WInform when load too many controls, another case is receive so many event but have no enough time to handled them, finally some events will be lost, so we use doevent to prevent from it.

But in WPF, we don not need to use this mechnism, nor the async mechnism either.