I have the following components in a WPF application:
(1) Window
(2) ContentPresenter in the Window that is bound to a property in the underlying ViewModel. This Property references another ViewModel.
(3) A DataTemplate for the ViewModel that will be bound to the ContentPresenter referenced above. This data template instantiates a third-party grid that displays some data.
Whenever the ContentPresenter renders the data from the DataTemplate, it takes approximately three to four seconds for the UI to render. This causes the UI to hang for the duration of the time that it takes to render the content. Since I have little to no control over how the third-party control renders itself - my question involves whether or not it is possible to render content in a way that the UI will not hang.
Please advise.
Thanks.
Chris
How many rows is the grid displaying? And how many of those rows are visible on screen?
I'm asking because it's possible that you've got a UI layout that defeats virtualization. Usually, controls that show a scrollable list of data will perform virtualization. (The built-in ListBox does this, and any 3rd party grid of tolerable quality should do the same.) This is critical for performance, because it means your UI only needs to instantiate those items that are actually visible, rather than everything in your list.
But it's relatively easy to defeat this virtualization by accident. One way is to wrap the list or grid control in a ScrollViewer. You need virtualizing controls to be able to manage their own scrolling for virtualization to work, so the scrolling needs to happen on the inside. Wrapping a control in a ScrollViewer prevents it from doing its own scrolling. Another way it can go wrong is if you plug in a different ItemsPanel. A third possibility is that your list/grid control actually needs to be told to use virtualization.
But if you're using a control that simply takes a long time to render just the stuff you need to show on screen, then there's not much you can do - you'd need to contact the control vendor, or consider using a different vendor...
Related
I am making a search app in wp7. Every record's data is bound to a user control. I have introduced an infinite loading instead giving page numbers. So when the number of instances of the UserControl is increased in the screen the transition from one page to another page (like the preview or settings pages) or coming back from that page to the current page is getting slower. I cannot change the design (infinite loading concept).
What are the ways to handle this scenario? How about changing the visibility of the controls? And reference or suggestion will be highly appreciated.
Note I tagged WPF and Silverlight because the binding happens the same way in them, expected those to have dealt with scenarios like these.
EDIT Check this question, which is asked by me. Because of having UserControl's in the listbox the vertical offset is not being maintained. So I had no option other than using ItemsControl with scrollViewer around it. ItemsControl contains a list of 5 - 6 usercontrols which intern have itemsControls inside them, I thought virtualization may not happen in such cases. Am I right?
In WPF, this is done by Virtualization
Using Virtualization, only one copy (or a few copies) of the UserControl actually gets created, and switching to another user control actually just swaps out the DataContext that the control is bound to. It doesn't actually create a new UserControl.
For example, if you have an VirtualizingStackPanel with 100,000 items, and only 10 are visible at a time, it will only render about 14 items (extra items for a scroll buffer). When you scroll, the DataContext behind those 14 controls gets changed, but the actual controls themselves will never get replaced. In contrast, a regular StackPanel would actually render 100,000 items when it gets loaded, which would dramatically decrease the performance of your application.
This question about Virtualizing an ItemsControl can probably get you going in the right direction.
Take a look at this post, I believe the solution provided by Rico is what you are looking for. :)
I am creating a resource-intensive dashboard application that will have many areas of data visualization. I am thinking that it would be best to use a frame and load the pages needed one at a time using WPF pages. These pages will also have different data contexts, security restrictions, etc. But, another developer says I can accomplish the same thing using a TabControl.
Does a TabControl load all the items in all the tabs at once, on application startup? Or, can I load them lazily as needed like with WPF pages (page only loads content when navigated to)? Also, can you have different data contexts per each item in a TabControl?
In WPF you can use UI Virtualization which means that only the visible controls are initialized and rendered. As far as I know, the TabControl does not support UI Virtualization by default but maybe you can add it manually or use another control. Maybe you want to have a look at the following article which presents some performance tips. There is also mentioned that there is a difference between UI and Data Virtualization. Not showing the controls does not mean that the underlying data are not in memory. All your binding targets will be loaded, but the controls will not be rendered.
To your second question: Yes, every TabItem can have its own DataContext. If you use a TabControls ItemsSource to bind a list of items, the DataContext for every TabItem will be one item of the list. If you manually add TabItems, you can set the DataContext like that:
<TabControl>
<TabItem DataContext="{Binding Context1}" />
<TabItem DataContext="{Binding Context2}" />
</TabControl>
It is more complex than you would guess. If you bind to Tab Collection (think MVVM) then the tab only get created when it is selected. And with a Collection if you leave a tab and come back it gets built AGAIN. If you create the tabs in XAML then the tabs are all built when the windows loads. Yes you can have different DataContext for each tab. What I do for lazy loads is bind to the TabItem property IsSelected and if it is false all the Properties in the class just return a (fast) static type compliant value. If IsSelected is changed to true then I load the real values and call NotifyPropertyChanged (and I save the real values).
I use the heck out of this were I load a big objects and one tab is a summary. Tabs do not virtualize but if you have big lists then for sure use virtualization in the tab. You can use BackgroundWorker to create properites but once it returns and you bind that returned value the UI locked until the UI control is rendered. For me reuse of a single frame versus tabs is a UI thing. Just to break up code I typically load a tab with a frame and a page (and I typically pass data to the page in the ctor to load dynamic content).
Is there a way to get Silverlight databound controls to load in the background to shorten load times during another part of application use? Specifically, I have a tab control containing a datagrid that is slow to load when there are large number of columns and rows. The performance hit occurs the first time I click the tab. Is there a way to force this load on a background thread when app first opens or something similar?
Not sure this is exactly relevant but I just resolved an issue I had where I was firing up a new grid (which was already loaded but not visible). In the process of making it visible I also assign the ItemSource of a datagrid inside which - via a converter - generates controls. What I found was that although the datagrid in silverlight typically only loads rows it needs to (based on visibility) in my case the code sequence to show the grid and bind was happening too quickly and because the grid wasn't yet shown it (silverlight) decided it needed to load all the rows.
Calling UpdateLayout() prior to generating the controls and binding resolved the issue.
I am binding my ContentPresenter to a ViewModel that has a type-referential DataTemplate which contains an instance of a third-party control (DevExpress' GridControl). When this control is bound to a modestly sized collection (i.e. 1000 items), the control takes a noticable four or five seconds to load. So, to my question - for controls that take a while to render, can this somehow be done using a BackgroundWorker such that the UI doesn't hang? Keep in mind that I my controls reside in a DataTemplate, so any code-behind is not a desirable option.
Thanks!
Unfortunately creating the actual UI (in your case, creating, positioning, and rendering controls) must be done on the UI thread due to compatibility constraints - all UI components must be created by the UI thread, and they can only be altered by the UI thread as well.
One thing I would recommend looking at is virtualization - if you're not displaying the datatemplate of 1000 items, why create all of the controls? You can find examples around like Virtualized WPF Canvas, or using the built-in VirtualizingStackPanel. Using these techniques will be more work than simply binding a viewmodel to an item with a datatemplate, but will give much, much better performance.
If the actual issue is just that the DevExpress GridControl is super slow with 1000 items, then you'll want to see if you can set it to a virtual mode, or switch to a different 3rd party control.
Your ItemsControl should contain a VirtualizingStackPanel which ListView and ListBox do, but make sure that virtualisation is switched on and you use container recylcling
<ItemsControl
VirtualizingStackPanel.IsVirtualizing="true"
VirtualizingStackPanel.VirtualizationMode="Recycling">
I have a WPF User control that binds to a DataTable and generates CheckBox and a masked EditBox for each row in a DataTable. I have several instances of this control on my form. The total number of CheckBoxes to be generated is over 200. I am seeing some rendering performance issues. The form loads with all of the static controls ( Text Boxes, Drop Downs) instantly, then several seconds later the CheckBoxes appear.
Any thoughts?
Thanks
Unless all the 200 items are visible on the screen, you should be using some kind of virtual layout that creates the visual tree only for the visible items. This will greatly improve your performance.
What is "generating" the checkboxes? You should be using an ItemsControl (or subclass) and binding the data that represents the checkboxes to it. Assuming you're doing that, then what you want to do is get that ItemsControl to use "virtualizing" by applying the VirtualizingStackPanel.IsVirtualizing property to the ItemsControl like so:
<ItemsControl VirtualizingStackPanel.IsVirtualizing="true" ... >
You might also want to turn on "container recycling" which will also help performance. This is also done with an attached property:
<ItemsControl VirtualizingStackPanel.VirtualizationMode="Recycling" ... >
Too many checkboxes surely cost a lot, if you look at templates of basic controls, they are also filled with lot of uielements.
I would suggest if you can divide your UI into Tabs or Accordins that will cause less visible items on one screen as well as it will help user navigate to items easily and faster as well.
VirtualizingStackPanel will help but if your binding isnt correct it may lead to unpredicted results.
Custom Control Template:
You can also create your own custom checkbox template with least UIElements, like simple rectangle filled with different color on IsChecked property trigger. This will eliminate few animations etc that can surely imporve your rendering performance. I believe CheckBox is least important when it comes to animating UI.
When you are sure that you will be using "Text" as content, then simply create template with rectangle to show filled/empty value and put TextBlock with template binding to Content.
Try to give fixed width/height to your checkbox, whenever you fix the height/width of your controls/containers, it becomes eaiser for layout manager to render them, rather then keep on calculating and adjusting items.