This blog mainly describes how to use UI Virtualization (uiv) to improve the performance of the treegrid control in the OEA framework. It also provides some resources to learn uiv.
Problem
Recently, the treegrid control of OEA has been greatly modified, and all the DataGrid controls in the system have been replaced with the new controls. The new treegrid control implements many new functions.ArticleNote), but there is a problem left over: Because it replaces the original DataGrid, And the DataGrid supports UI virtualization by default, when the data volume on some interfaces is large, the treegrid control that does not support uiv seems to be insufficient. To solve this problem, I read many articles and learned about uiv in WPF over the past two days. Finally, I have solved the problem. I will write this article to record it later.
Before uiv is implemented:
518 data records, and 18130 referals are generated.
In fact, after the solution, the problem mainly lies in the treegrid template, which is directly pasted to show you:
< Scrollviewer Style = "{ Staticresource Gridtreeviewscroll }" Background = "{ Templatebinding Background }" Focusable = "False" Cancontentscroll = "False" Horizontalscrollbarvisibility = "{ Templatebinding Scrollviewer . Horizontalscrollbarvisibility }" Verticalscrollbarvisibility = "{ Templatebinding Scrollviewer . Verticalscrollbarvisibility }" Padding = "{ Templatebinding Padding }" Snapstodevicepixels = "{ Templatebinding Snapstodevicepixels } "> < Grid > < Itemspresenter Snapstodevicepixels = "{ Templatebinding Uielement . Snapstodevicepixels} "/> < Textblock Opacity = "0.5" Textwrapping = "Wrap" Fontsize = "36" Text = "No data" Textalignment = "Center" Verticalalignment = "Center" Horizontalalignment = "Center" Fontfamily = "Stcaiyun" Rendertransformorigin = "0.5, 0.5" Foreground = "#80000000"> < Textblock. Visibility > < Multibinding > < Multibinding. Converter > < Oeamodulewpf : Itemscontrolnodataconverter /> </ Multibinding. Converter > < Binding Path = "Data" Relativesource = "{ Relativesource Findancestor , Ancestortype = { X : Type OEA : Gridtreeview } "/> < Binding Path = "Items. Count" Relativesource = "{ Relativesource Findancestor , Ancestortype = { X : Type OEA : Gridtreeview } "/> </ Multibinding > </ Textblock. Visibility > < Textblock. rendertransform > < Transformgroup > < Scaletransform Scalex = "1.5"/> < Skewtransform Anglex = "-30"/> < Rotatetransform Angle = "-30"/> </ Transformgroup > </ Textblock. rendertransform > </ Textblock > </ Grid > </ Scrollviewer >
To display the word "no data" when the list has no data, a grid contains an itemspresenter and a textblock. This sectionCodeIt seems that there is no problem, so I haven't debugged uiv for a long time. In the end, I had to patiently learn about uiv on the Internet.
Solution
In fact,
Related uiv knowledge points There are several:
- Virtualizingstackpanel in WPF only supports uiv of a layer of data. (Does this seem to be improved after wpf3.5 SP1 ?)
- Treeview before wpf3.5 SP1 does not support uiv. The subsequent Treeview is disabled by default and needs to be opened manually.
- To implement uiv, a corresponding scollviewer is required.
- Uiv can be implemented only when the cancontentscroll attribute in scollviewer is true.
When this attribute is set to true, scollviewer transmits the current viewport size to the content element during the measure operation. Otherwise, it will pass infinite to content.
At the same time, iscollinfo needs to be implemented by sub-elements (that is, virtualizingstackpanel) and scroll information should be returned, while scollviewer is just a simple window. In this way, sub-elements can implement uiv internally, it also informs the corresponding scrollowner (scrollviewer)-related drag information.
Therefore, the above XAML has two major errors:
- Scrollviewer. cancontentscroll should be set to true.
- You should use virtualizingstackpanel as the content element of scrollviewer ).
Modify it to the following XAML:
< Grid > < Scrollviewer Style = "{ Staticresource Gridtreeviewscroll }" Background = "{ Templatebinding Background }" Focusable = "False" Cancontentscroll = "{ Templatebinding Scrollviewer . Cancontentscroll }" Horizontalscrollbarvisibility = "{ Templatebinding Scrollviewer . Horizontalscrollbarvisibility }" Verticalscrollbarvisibility = "{ Templatebinding Scrollviewer . Verticalscrollbarvisibility }" Padding = "{ Templatebinding Padding }" Snapstodevicepixels = "{ Templatebinding Snapstodevicepixels } "> < Virtualizingstackpanel Isitemshost = "True" Snapstodevicepixels = "{ Templatebinding Uielement . Snapstodevicepixels} "/> </ Scrollviewer > < Textblock Opacity = "0.5" Textwrapping = "Wrap" Fontsize = "36" Text = "No data"> ...... </ Textblock > </ Grid >
At the same time, note that the uiv that opens the Treeview supports:
Public classGridtreeview:Treeview{StaticGridtreeview (){Virtualizingstackpanel. Isvirtualizingproperty. overridemetadata (Typeof(Gridtreeview),NewFrameworkpropertymetadata(True));}
Let's take a look at the optimized results:
The number of reducers is reduced from 1w8 to 3000. When there are more rows, about 3000 are generated at the beginning. It is also obvious that the drag is much smoother.
Success!
Related Resources
An easy-to-understand uiv concept article: Ui virtualization, which describes the uiv in WPF and Silverlight. (It also has a follow-up article: "Data virtualization alization", which is also very good ).
The DataGrid Control used in the system has poor performance once data is grouped. The reason is also related to uiv:
Currently, controls in WPF do not support UI virtualization alization after group, because when scrollviewer. cancontentscroll is set to true, the mode changes from scroll by pixel to scroll by item. Groupitem in the group control is actually an item. If you continue to use the scroll by item mode, the user experience will be very poor, therefore, the MS determines that the uiv After grouping is not supported. The default template of The ListBox control has a trigger that sets concontentscroll to false when isgrouping is true. For more information, see UI virtualization. Other uiv articles related to grouping are as follows:
WPF DataGrid transformation alization with grouping, msdn sample code: grouping and transformation alization, and problem: listview transformation alization
Virtualizing treeviewitem: The best answer is a few things: virtualizingstackpanel needs to interact with scrollviewer. At the same time, it only supports one layer of virtualization. You can consider using ListBox/listview as a work und to implement a false Treeview, so that the entire list can be virtualized.
WPF-receivalizing an itemscontrol: by default, itemscontrol does not support UI configuralization because its template does not contain a scrollviewer.
Are there any tricks that will help me improve Treeview's performance: There are three articles in this series: Part I, Part II, and Part III. the last article explains how to use ListBox to simulate a Treeview. In this way, because ListBox itself supports uialization, the final "Treeview" also supports UI alization. Some similar controls have already been passed to codeproject: "rolling alizing Tree View (vtreeview)", where I also talked about the above series of articles. Coincidentally, it also talked about the resources selected by our system to implement the treegrid control on codeproject: a versatile Treeview for WPF.
For more advanced custom UI virtualization, refer to the following articles, which are good: virtualizing wrappanel and implementing a virtualized panel in WPF (aveon), implementing a virtualizingpanel Part 2: iitemcontainergenerator, implementing a virtualizingpanel Part 3: measurecore, and implementing a virtualizingpanel Part 4: the goods!" Iscrollinfo in avlon Part I, iscrollinfo in avlon Part II, iscrollinfo in avlon Part III, iscrollinfo in avlon Part IV, and responding to comments
.
MS own related resources:
Msdn control performance, how to: Find a treeviewitem in a Treeview,