Caching of UserControl objects - wpf

I have a WPF application where I show and hide lots of UserControl objects. The XAML code looks something like this:
<ItemsControl ItemsSource="{Binding Path=MyListOfStuff}" >
<Controls:MyControl Stuff="{Binding}"/>
</ItemsControl>
Creating those objects takes a lot of time. Profiling shows that 'InitializeComponent' takes a significant amount of time for the MyControl objects. I want to pre create these objects to reduce that time. How can I do that? I still need the xaml code and don't want to replace all of it with just code.
It's not possible to use virtualization because the items in the list are sometimes bigger than the view, so CanContentScroll must be False.

There are two aspects to solve your problem. even you can use both of them..
UI Virtualization
Data Virtualization
You should have a look at
http://blogs.microsoft.co.il/blogs/tomershamam/archive/2009/10/01/ui-virtualization-vs-data-virtualization-part-2.aspx
also if you are using .net 4.0 you can use Lazy class to support Data Virtualization easily otherwise you will have to create some classes to support that.
Regards.

It is possible to do UI caching in WPF, but I'm quite sure it is not what you are looking for.
Bitmap caching is useful when one visual is painted more than once, so it is rendered only once and for subsequent renderings only copied from the cache.
You will have to have a look at virtualization (see Shoaib's answer).
Article about bitmap caching.

Related

Several WPF- / XAML-Files performing better than a big one?

I was talking recently to another GUI developer that was looking at one of my WPF applications. He suggested to break down my very large WPF views (files) into several smaller views. According to him this should promote loading performance as elements that are loaded from UserControls in separate files are rendered only when they actually come into view.
In my main view I currently have over 10k lines of XAML. As the main part of this view is a big TabControl with several large TabItems it would be easy to transfer the content of each TabItem into a separate file. It is true that most of the Tabs will not be used by every user or at least not directly after startup.
However, I was not able to verfy his claim by searching the web. Whenever I search the internet for WPF performance optimization I find all kinds of suggestions, but splitting up large XAML files into smaller ones was never mentioned in any way there.
For me, personally, having one big XAML per view is more comfortable and reusability is really not a problem in my case. So now I am wondering:
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
From a maintainability and reusability point of view, yes. But whether you define content of each TabItem inline or in a separate UserControl won't matter from a performance point of view.
So you won't gain any performance benefits of doing this:
<TabItem>
<local:UserControl1 />
</TabItem>
...versus doing this:
<TabItem>
<Grid>
...
</Grid>
</TabItem>
You should consider adopting the MVVM design pattern and bind the ItemsSource property of the TabControl to an IEnumerable property of a view model and use DataTemplates to define the appearance of each item rather than defining everything inline though. Doing this, only the contents of the selected TabItem will be loaded into the visual tree.

Drag and drop from datasource to WPF window not working

I have been tasked to design a contact management program for my company. We have VS 2012 and since I have never used WPF before I thought I would use it to develop this application.
I am having huge problem getting started on the binding when utilizing the entity framework for the database which btw is database first.
I have followed the instructions within this link to the letter.
http://msdn.microsoft.com/en-us/data/jj574514.aspx
The objects show up in the data sources window just fine. But when I drag and drop to my window, nothing happens. No idea what I am doing wrong and cannot find anyone else with this problem.
Can anyone help me out here? I have looked everywhere. Any help is appreciated
Ok. I actually went thru that article, just to show good faith and let you know that I actually want to help you.
I came to the following conclusions:
That article show a very basic scenario of getting data from an Entity Framework context and showing it in a WPF DataGrid.
It doesn't have any kind of validation nor business rules.
It doesn't have any UI behavior such as conditionally enabling/disabling or showing/hiding any UI elements.
That kind of scenario is where the Designer is useful, when you don't actually need anything except getting / saving data from / to a DB.
Unfortunately (or fortunately for all of us developers who make a living of it), most applications will require some level of validation and business rules and some level of UI logic.
The designer is really useless when it comes to developing complex logic.
You can use the designer for such situations where you don't require complex logic, however I must warn you the following cons:
The Visual Studio WPF designer produces fixed-size, fixed-position UIs. these type of UIs don't work well when executed in computers with different screen resolutions and DPI settings. Just like winforms.
It also produces XAML that has many unnecessary things (such as x:Name="categoryIdColumn" and things like Margin="13,13,43,191" which are really bad from a maintainabilty / scalability point of view)
From what I've seen, the designer-generated XAML also contains a CollectionViewSource, this is both a good thing and a bad thing. It's a good thing because it enables Design-Time Data in the DataGrid, but it is also bad because it bloats your XAML with lots of unneeded things and introduces unnecessary <Window.Resources> that complicate things up.
Now, this is the very minimal XAML needed for that DataGrid, without Design-time data support:
<Window x:Class="MiscSamples.DesignTimeDataGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DesignTimeDataGrid">
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGridTextColumn Header="Category Id" Binding="{Binding CategoryId}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid>
</Window>
You see? It's actually faster to type that (much more so with the help of Intellisense) than what it takes for you to browse the property window and set these properties manually.
My suggestion is that you get familiar with XAML instead of insisting in the hard way to do things
Another very important aspect to keep in mind is that generally speaking, you don't put anything in code-behind in WPF because it's not needed, therefore that tutorial is actually going against the WPF Way of doing things, but that's Ok because it's actually an Entity Framework tutorial, not a WPF tutorial.
ease of development
You really need to reconsider what you call "ease of development". When it comes to UI development, I call "ease of development" to actually being able to do what I want with the UI without having to resort to shitty procedural code practices involving P/Invoke (whatever that means) and "owner draw" type of things for evertyhing.
WPF provides REAL ease of development as opposed to the fake ease of development exhibited by winforms
winforms lets you do everything with a designer (and this is just because the code the designer generates is actually so shitty that nobody would have ever used winforms if they didn't have the designer) but then when it comes to adding complex DataBinding or UI logic you're stuck with winforms' incapabilities forever.
WPF encourages manual XAML writing, not only because XAML is declarative (as opposed to the procedural winforms approach), but also because the levels of customizability and reusability are so high that a designer-centric approach does not make sense.
drag and drop is the easy way out
No it's not. It's actually the hard way. The easy way is to learn XAML and be able to do Things you can't even imagine to do with winforms.
If a designer-centric approach still makes sense to you, you may want to try Expression Blend
Automatically Create Data Grids from Your Models
Using a data source to drag and drop a template onto a WPF control is an excellent and fast way to get up and running!
Start by doing this: In your project create a folder named Models, then use either Entity Framework DB first or code by hand the models you want to show.
OR see discussion below on Object binding...
In that same folder create a dummy class that is a property for IEnumerable like this..
public IEnumerable<MyClassModel> MyCollection { get; set; }
From there go to the Main Visual Studio menu, to View/Other Windows/Data Source and click that link.
Click on Object and find the MyCollection property just created above.
Now open a user control or window in WPF but keep the datasources toolbox opened.
It should default to a DataGrid, but you can right click on the datasource and change it to detail, datagrid or select individual properties of the class it represents.
Simply drag that datasource onto the XAML's grid area. The right click on the new stuff you see and click reset to set the content to be the size of the entire window.
After having done this you will have code injected into the code behind of the view as follows in the window loaded event of that window, usercontrol etc.
// Do not load your data at design time.
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
//Load your data here and assign the result to the CollectionViewSource.
System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["Resource Key for CollectionViewSource"];
myCollectionViewSource.Source = your data
// }
Go back to the XAML and look for the CollectionViewSource KEY property that was also inserted when you dragged the property to the XAML. It looks like this:
Use the Key name in the code behind, and then "Bind" the CVS to your data source which is an enumerable of type MyClassModel it can live in the View Model or in the code behind of the view as you choose.
If you only use the CollectionViewSource to as the datacontext of the grid you do not need to implement INPC for any underlying collections! The CVS updates the view automatically everytime the source is updated! Once you get good at this you can create working View prototypes of data in 2 minutes! Forget hand-coding XAML that just takes too long.
Object Binding
Create a static class with a static method that returns something like this:
When using the datasource wizard choose the "Object" selection.
Click Ok and you should see something like this:
You have just mapped all of the properties into the data source definition.
For anyone finding this issue in VS 2022: as per this is written, VS 2022 has this known bug unable to drag and drop data source to XAML form.
More info: https://developercommunity.visualstudio.com/t/drag-a-a-table-from-datasource-and-drop-in-a-windo/1660788
UPDATE:
It says that the fix has been released on 15th June. You can try updating your VS 2022 to the latest.

Rendering Thread still slow after Virtualization

At a high level my application is applying about 5 different DataTemplates to a set of ListBoxItems based on their type. These items are laid out on a canvas at specific x, y points. I implemented virtualization on my ListBox and it did not seem to improve the time it takes to complete the rendering thread's processes. It still takes about 8-12 seconds for the UI to be completely loaded and usable by the user. I thought virtualization would help fix this problem but after looking around it looks like it only helps process scrolling large amounts of data. Am I correct in this assumption and does anyone else have any other tips for improving the rendering thread. This is the only problem I am having and then my project is complete. Thanks StackOverflow!
Virtualisation means that only the items you have visible are created, then dynamically destroyed/new items created as you scroll. The alternative is all UI controls are created for all items at once.
It sounds like you have bigger problems with the rest of the app. Do you perform all loading operations on a background thread? Is the UI control tree very complex indeed? Are you displaying 100s or 1,000s of items?
We also had a lot of trouble with performance in WPF. Best way is of course to profile your application. We use ANTS Performance profiler for that, but any .NET profiler will do. We got a huge performance hit, because of the lookup of our XAML Resources. Thats the advice i can give you:
Try to minimize all resources in XAML. But not only that, also try to minimize the amount of XAML files you have. One thing you can try is to defere the loading of complex parts of your DataTemplate. Similiar to what happens when you load a JPEG in a browser, first you will see a pixelated image which will be finer after it finished loading the JPEG. To accomplish that, use a simpler DataTemplate at first and then if this is visible only load the complex template on demand or after a while.
But without more information of your specific problem, we can only guess. This is an old question of mine about a similiar subject, maybe this will help aswell.
Yes, ListBox virtualization is for scrolling. When you have a large number of items in a ListBox, enabling virtualization will make only the visible items (+ a few extra items for scrolling) render, and scrolling the ListBox replaces the data in the rendered items instead of rendering new items.
If you were to post some code, perhaps we could assist you with some performance tweaks

Ways to improve WPF UI rendering speed

In case a screen of a WPF application contains lots of primitive controls, its rendering becomes sluggish. What are the recommended ways to improve the responsiveness of a WPF application in such a case, apart from adding fewer controls and using more powerful videocard?
Is there a way to somehow use offscreen buffering or something like that?
Our team was faced with problems of rendering performance. In our case we have about 400 transport units and we should render chart of every unit with a lot of details (text labels, special marks, different geometries etc.).
In first our implementations we splitted each chart into primitives and composed whole unit's chart via Binding. It was very sad expirience. UI reaction was extremely slow.
So we decided to create one UI element per each unit, and render chart with DrawingContext. Although this was much better in performance aspect, we spent about one month improving rendering.
Some advices:
Cache everything. Brushes, Colors, Geometries, Formatted Texts, Glyphs. (For example we have two classes: RenderTools and TextCache. Rendering process of each unit addresses to shared instance of both classes. So if two charts have the same text, its preparation is executed just once.)
Freeze Freezable, if you are planning to use it for a long time. Especially geometries. Complex unfreezed geometries execute HitTest extremely slow.
Choose the fastest ways of rendering of each primitive. For example, there is about 6 ways of text rendering, but the fastest is DrawingContext.DrawGlyphs.
Use profiler to discover hot spots. For example, in our project we had geometries cache and rendered appropriate of them on demand. It seemed to be, that no improvements are possible. But one day we thought what if we will render geometries one time and cache ready visuals? In our case such approach happened acceptable. Our unit's chart has just several states. When data of chart is changed, we rebuild DrawingVisual for each state and put them into cache.
Of course, this way needs some investments, it's dull and boring work, but result is awesome.
By the way: when we turned on WPF caching option (you could find link in answers), our app hung up.
I've had the same perf issue with a heavily customized datagrid since one year, and My conclusion is:
there is basically nothing you can do
on your side (without affecting your
app, i.e.: having fewer controls or
using only default styles)
The link mentioned by Jens is great but useless in your case.
The "Optimizing WPF Application Performance" link provided by NVM is almost equally useless in my experience: it just appeals to common sense and I am confident you won't learn anything extraordinary either reading. Except one thing maybe: I must say this link taught me to put as much as I can in my app's resources. Because WPF does not reinstanciate anything you put in resource, it simply reuses the same resource over and over. So put as much as you can in there (styles, brushes, templates, fonts...)
all in all, there is simply no way to make things go faster in WPF just by checking an option or turning off an other. You can just pray MS rework their rendering layer in the near future to optimize it and in the meantime, try to reduce your need for effects, customized controls and so on...
Have a look at the new (.NET 4.0) caching option. (See here.)
I have met a similar problem and want to share my thoughts and founds. The original problem is caused by a virtualized list box that displays about 25 complex controls (a grid with a text block and a few buttons inside displaying some paths )
To research the issue I used the VisualStudio Application Timeline that allows to how much time it takes to render each control and PerfView to find out what actually WPF is doing to render each control.
By default it took about 12ms to render each item. It is rather long if you need to update the list dynamically.
It is difficult to use PerfView to analyse what heppens inside since WPF renders item in the parent-child hierarchy, but I got the common understanding about internall processes.
WPF does following to render each item in the list:
Parse template using XAML reader. As far as I can see the XAML parsing is the biggest issue.
Apply styles
Apply bindings
It does not take a lot of time to apply styles and bindings.
I did following to improve performance:
Each button has its own template and it takes a lot of time to render it. I replaced Buttons with Borders. It takes about 4-5ms to render each item after that.
Move all element settings to styles. About 3ms.
Create a custom item control with a single grid in the template. I create all child elements in code and apply styles using TryFindResources method. About 2ms in the result.
After all these changes, performance looks fine but still most time is spent on loding the ListControl.Item template and the custom control template.
4. The last step: replace a ListControl with Canvas and Scrollbar controls. Now all items are created at runtime and position is calculated manually using the MeasureOverride and ArrangeOverride methods. Now it takes <1ms to render each item from which 0.5ms is spent on TextBlock rendering.
I still use styles and bindings since they do not affect performance a lot when data is changed. You can imagine that this is not a WPF solution. But I fave a few similar lists in the application and it is possible not to use templates at all.

Silverlight ItemsControl wih ColumnHeader

How can I add column headers to a Silerlight ItemsControl? I need a fast way to display a List of items that contains also some header info.
This may seem like a simplistic question but why not use the DataGrid in readonly mode?
The downside with data grid is it doesn't use a virtualised ItemsControl so performance may suffer if you are trying to list hundreds of items with many columns.
There's nothing built into the ItemsControl itself, but there's nothing to stop you from making a custom control that has that kind of functionality. It's a little work up front for the ability to reuse it later if it's a piece of UI you need frequently.
Adding too much functionality to it might be overkill though; if you need column sorting or automatic column/header generation, you may find that a DataGrid (as Anthony pointed out already) would be a faster way of getting a lot of functionality for free.

Resources