In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-07 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Today, I would like to share with you how to solve the problem of automatic expansion of WPF tree table width. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article.
The original question is as follows:
Figure 1 description of the problem
Background
Tree controls have been widely used in GIX4 systems. This control was searched and reintroduced by other colleagues on the Internet a year ago.
In the beginning, the most straightforward solution to this problem is to find the Expander control (plus sign:) in the * * column and listen for its "Expanded" event; in the event handler, calculate the required width, and then set it to the width of the control.
When I actually wrote the code according to this scheme, I found that it was not as simple as I thought, and I found a lot of problems. For example, Expander is not an Expander control, but a ToggleButton, and it is written in a template, and the type of Expander in TreeGridRowPresenter is only UIElement, that is, you cannot convert Expander from UIElement to ToggleButton, so the program will be written to death. For example, how to calculate the required width of the * column.
These are the issues that need to be addressed for the BUG mentioned above:
Four problems to be solved
1. When is the most appropriate trigger? Where does the code to adjust the width be triggered?
two。 How to find all the GridViewRowPresenter of a tree control.
3. In GridViewRowPresenter, how to find the control of the * column.
4. What is the structure of the column control, how to find out the size it needs, and whether you can use Measure and DesiredSize directly.
Solve the problem step by step
* question, when will this feature be triggered? In fact, I want to click, when the child nodes are loaded, and then calculate the appropriate size, and then set to the column object. I first tried to write code in TreeListView's OnExpanded event handler to get each TreeListView, but found that when this event occurred, all the child nodes were not generated, so the window could not be obtained through the ItemContainerGenerator.GetContainerForItem method. This scenario failed. Next, I looked at the interface declaration of ItemsControl and found that the ItemContainerGenerator property had the event StatusChanged. So I listen to this event instead and decide that if its Status becomes ContainersGenerated, it means that all the child nodes have been generated. The code is as follows:
This.ItemContainerGenerator.StatusChanged + = (o, e) = > {if (this.ItemContainerGenerator.Status = = GeneratorStatus.ContainersGenerated) {this.AdjustFirstColumnWidth ()}}
But also found a new problem, at this time, although the window object TreeListView has been generated, but all the Visual Child below it has not been generated, so it is also impossible to get the GridRowPresenter used to display each line in it. So it had to be changed like this:
Public TreeListViewItem () {this.PrepareToAdjustFirstColumnWidth ();} private void PrepareToAdjustFirstColumnWidth () {this.ItemContainerGenerator.StatusChanged + = (o, e) = > {if (this.ItemContainerGenerator.Status = = GeneratorStatus.ContainersGenerated) {if (this.Items.Count > 0) {var item = this.Items [this.Items.Count-1]; var treeItem = this.ItemContainerGenerator.ContainerFromItem (item) as TreeListViewItem TreeItem.Loaded + = (oo, ee) > {this.AdjustFirstColumnWidth ();}
In this way, the code for adjusting the width will not be triggered until all the visual content of a child is loaded.
The second problem is relatively simple. After looking at the source code of TreeListView, I found that it used the GridViewRowPresenter class in the template of the TreeListViewItem class, and then defined the name for it: "PART_Header".
Private TreeGridViewRowPresenter FindGridRow () {var rowPresenter = this.Template.FindName ("PART_Header", this) as TreeGridViewRowPresenter; return rowPresenter;}
To solve the third problem, we need to know how to generate a row in GridViewRowPresenter and the control structure generated by *. Let's first take a look at the control structure generated by GridViewRowPresenter***, where I use Snoop:
Figure 2 viewing the visual structure of TreeGridViewRowPresenter with Snoop
We found that GridViewRowPresenter simply contains a few visual elements that happen to be displayed in each column. Then look at the source code of GridViewRowPresenter and find that it has the following attributes: public GridViewColumnCollection Columns {get;set;}, internal UIElementCollection InternalCollection {get;set;}. After further analysis, I guessed that GridViewRowPresenter.InternalCollection simply contains the display elements of all columns, and it maintains these visual elements based on the rows in the Columns attribute to make them appear like tables.
So far, the third problem has been solved:
Var firstColumn = VisualTreeHelper.GetChild (rowPresenter, 0) as UIElement
* A problem is the most troublesome problem in the process. We see that the * elements under the row in figure 2 are the display elements of the * * column, showing "2.1". But the Expander control on the left of the text is a visual child of TreeGridViewRowPresenter. And indentation is not a control. So what's going on? After reading the source code of TreeGridViewRowPresenter, I found that it took the initiative to put Expander in *:
Public class TreeGridViewRowPresenter: GridViewRowPresenter {protected override System.Windows.Media.Visual GetVisualChild (int index) {/ / Last element is always the expander / / called by render engine if (index < base.VisualChildrenCount) return base.GetVisualChild (index); if (index = = base.VisualChildrenCount) return this.lbRowNo; return this.Expander } protected override int VisualChildrenCount {get {/ / Last element is always the expander if (this.Expander! = null) return base.VisualChildrenCount + 2; else return base.VisualChildrenCount + 1;}
The reason why the text is indented first and then Expander is that the TreeGridViewRowPresenter class overrides the FrameworkElement.ArrangeOverride method. In this method, it shortens the length of the display of the elements of the * column before displaying an indented white space and an Expander control:
Protected override Size ArrangeOverride (Size arrangeSize) {Size s = base.ArrangeOverride (arrangeSize); if (this.Columns = = null | | this.Columns.Count = = 0) return s; UIElement expander = this.Expander; double current = 0; double max = arrangeSize.Width; for (int x = 0; x < this.Columns.Count; x +) {GridViewColumn column = this.Columns [x] / / Actual index needed for column reorder UIElement uiColumn = (UIElement) base.GetVisualChild ((int) ActualIndexProperty.GetValue (column, null)); / / Compute column width double w = Math.Min (max, (Double.IsNaN (column.Width))? (double) DesiredWidthProperty.GetValue (column, null): column.Width); / / First column indent if (x = 0 & & expander! = null) {double indent = FirstColumnIndent + expander.DesiredSize.Width; uiColumn.Arrange (new Rect (current + indent, 0, w-indent, arrangeSize.Height));} else {uiColumn.Arrange (new Rect (current, 0, w, arrangeSize.Height)) } max-= w; current + = w;} / / Show expander if (expander! = null) {expander.Arrange (new Rect (this.FirstColumnIndent, 0, expander.DesiredSize.Width, expander.DesiredSize.Height));} return s;}
At this point in the analysis, you know how to calculate the final width of the * column:
Private double GetFirstColumnDesiredWidth () {var rowPresenter = this.FindGridRow (); if (VisualTreeHelper.GetChildrenCount (rowPresenter))
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.