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. :)
Related
Background:
I use converters to acquire values for most of my binding statement because the bindings are so complicated that even multi-binding cannot satisfy. I have to calculate the value in the converters and return the value. Also I use OneWay or OneTime binding just to show the correct value. When user changes a value, I use Handlers to set the value. The Handlers are also complex program which cannot be simply replaced by TwoWay or OneWayToSource binding. Actually in this case the DataContext does not have any meaning. I use converters. Another reason of using converters is that all Controls are loaded dynamically using many DataTemplates and it's hard to create dynamic DataContext for each Controls in each DataTemplate.
With above background, my application works fine. I'm looking for solutions for our new problem below.
I have many group of Buttons each represent a warehouse containing different type of items.
When double-click a Button, a detail window pops up and user can modify the items. Those items can be represented by CheckBox, Combobox, TextBlocks, TextBox, etc.
For user's convenience, I duplicated some of the frequently-modified Controls from the popup window onto the Button itself (WPF allows Button to contain sub-controls), so that user can directly modify the items without double-click and popup the detail window.
Each Button could contain unknown number of sub-controls such as CheckBox, Combobox, TextBlocks, etc. Here "unknown" means that in the future developer can duplicate any controls onto the Button if the Controls for those items are deemed frequently-modified.
Everything works fine so far.
When user modifies an item in the popup window and closes the window, I used to reload the DataTemplate for the whole window so that everything is refreshed and the controls duplicated onto the Button can synch up with the value modified from inside the popup window.
Everything still works fine so far.
The problem happens when the application runs on machine with slow hardware, where performance is an issue. On a much slower machine, reloading the whole DataTemplate for the whole application that contains many Buttons is quite slow.
So I'm looking for ways to just refresh the Button that is double-clicked, not all Buttons. However, I searched a couple of days and could not find ideal solution of refreshing a WPF sub-tree.
I tried to travel the sub-tree of the Button to assign null to the DataContext property and then assign back the old DataContext, but the binding seems not triggered and the converters were not called.
I saw someone suggested to use something like below:
((ComboBox)sender).GetBindingExpression(ComboBox.ItemsSourceProperty)
.UpdateTarget();
That demands that I know the Control and its property that has bindings. I think I can do the same for all possible Controls and properties but it does not seem a future-proof solution.
Anybody knows an effective way of refreshing a WPF sub-tree without knowing what is in the sub-tree?
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 have a ListBox that contains a number of User items that are DataTemplated to appear as UserControls in the ListBox. Each UserControl can be expanded in size. To start with, the ListBox is big enough to display them all in their unexpanded state. The problem that I have is that when a number of these UserControls are expanded together, they extend out of the ListBox's visible area. The ListBox does not recognise this fact and no ScrollBars appear, even when they are set to Visible.
I am using DoubleAnimations to alter the UserControl heights when the user clicks on a button in each one. Is there something that I have to do, or some setting on the ListBox that must be set to get it to register the size changes of the UserControls that represent its items and display ScrollBars when needed?
Edit>>>
I have tracked down the problem to a custom WrapPanel that I am using in the ListBox.ItemsPanel. When I remove it, or replace it with a standard WrapPanel, ScrollBars appear when required. I got the code for the Panel from a good article about creating custom WPF panels. Can anyone see what's missing from the code given in the article and why it might stop the ScrollBars from displaying?
I wonder whether ListBoxes normally do what you are expecting? You might try calling InvalidateMeasure/Layout on the ListBox if you know when the item sizes change, just to see?
I decided to write the custom WrapPanel code again completely and this time it worked correctly! When comparing the new version with the previous version, I could see that a + was missing from a += in a measuring calculation and so the Panel thought that the items were much smaller than they really were... hence no ScrollBars.
So, if you have this problem, check your measuring code carefully.
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...
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.