Brief introduction
This article will be a complete description of my use of visualtreehelper implementation of the whole process of the function, want to see directly the function of the realization of friends can jump to the function implementation part.
or download the source code directly on GitHub.
We often encounter this situation in WPF: When we try to find the child or parent control of a control on a form or page, we can only find its first level of logical child or parent object. When we want to go deeper, there is no way out.
Even in our custom DataTemplate controls, we have no way to access them. For example, in a ListView custom control, we have no way to get control of the specified position. Examples can be found in my blog post: Controls in Custom DataTemplate in WPF, and the mechanism of loading in window_loaded events.
This article explores the solution.
VisualTreeHelper
In the VisualTreeHelper class, Microsoft provides utility methods for performing common tasks involving nodes in a visual tree, and some methods in the VisualTreeHelper class can accept DependencyObject that represent any type of visual object Value.
Here we are going to use two methods: Visualtreehelper.getchild () and Visualtreehelper.getparent ().
Using VisualTreeHelper to simulate a scene build
Create a new WPF project, named Visualtreehelperdemo.
Suppose we have a main form as shown below, the content container of a form is a grid control name= "Topgrid", which contains up to two child grids, each of which contains a button in each child grid.
The MainWindow.xaml code is as follows:
<window x:class="Visualtreehelper.mainwindow"xmlns="http// Schemas.microsoft.com/winfx/2006/xaml/presentation "xmlns:x=" http://schemas.microsoft.com/ Winfx/2006/xaml "Title=" MainWindow " Height=" = " Width= "525"> <Grid Name="Topgrid"> <grid.rowdefinitions> <rowdefinition></rowdefinition> <rowdefinition></rowdefinition> </grid.rowdefinitions> <Grid > <button Content="Button1" Name="Btn_one" VerticalAlignment="center" horizontalalignment="center"> </Button> </Grid> <Gridgrid.row="1"> <button Content="Button2" Name="Btn_two" VerticalAlignment="center" horizontalalignment="center"> </Button> </Grid> </Grid></Window>
Traverse looking for child objects
Now let's look for Topgrid All button child objects and output their names.
Open the MainWindow.xaml.cs file and add the following code to find the child objects:
// <summary> /// use VisualTreeHelper to find child objects of an object// </summary> /// <typeparam name= "T" ></typeparam> // <param name= "obj" ></param> /// <returns></returns> List<t> findvisualchild<t> (DependencyObject obj)wheret:dependencyobject{Try{List<t> TList =Newlist<t> {}; for(inti =0; I < Visualtreehelper.getchildrencount (obj); i++) {DependencyObject child = Visualtreehelper.getchild (obj, i);if(Child! =NULL&& Child isT) {Tlist.add ((T) child); }Else{list<t> Childofchildren = findvisualchild<t> (child);if(Childofchildren! =NULL) {Tlist.addrange (Childofchildren); } } }returnTList; }Catch(Exception ee) {MessageBox.Show (EE. Message);return NULL; }}
In the Btn_one_click event, write the following code:
// <summary> /// Form Load Events// </summary> /// <param name= "sender" ></param> /// <param name= "E" ></param> Private void Btn_one_click(Objectsender, RoutedEventArgs e) {stringBtnname =""; list<button> btnlist = findvisualchild<button> (Topgrid);foreach(Button IteminchBtnlist) {Btnname + =string. IsNullOrEmpty (btnname)? Item. Name.tostring ():","+ Item. Name.tostring (); } Show (string. Format (TopGrid.Name.ToString () +"Total {0} buttons with name {1}", Btnlist.count, Btnname));}
Run the program, click Button1, and the results are as follows:
The result shows that the traversal was successful.
Traverse looking for parent object
Now let's traverse Button2 's parent object, get information about all of its parent objects, and show it.
Open the MainWindow.xaml.cs file and add the code that looks for the parent object as follows:
// <summary> /// use VisualTreeHelper to find the parent object of the specified dependent object// </summary> /// <typeparam name= "T" ></typeparam> // <param name= "obj" ></param> /// <returns></returns> Public StaticList<t> findvisualparent<t> (DependencyObject obj)wheret:dependencyobject{Try{List<t> TList =Newlist<t> {}; DependencyObject parent = visualtreehelper.getparent (obj);if(Parent! =NULL&& Parent isT) {Tlist.add ((T) parent); list<t> parentofparent = findvisualparent<t> (parent);if(Parentofparent! =NULL) {Tlist.addrange (parentofparent); } }Else{ }returnTList; }Catch(Exception ee) {MessageBox.Show (EE. Message);return NULL; }}
Add the following code in the Btn_two_click:
// <summary> /// Traverse Button2 Parent Object Information// </summary> /// <param name= "sender" ></param> /// <param name= "E" ></param> Private void Btn_two_click(Objectsender, RoutedEventArgs e) {stringParentName =""; list<grid> gridlist = findvisualparent<grid> (btn_two);foreach(Grid IteminchGridlist) {ParentName + =string. IsNullOrEmpty (parentname)? Item. Name.tostring ():","+ Item. Name.tostring (); } MessageBox.Show (string. Format (btn_Two.Name.ToString () +"A total of {0} logical parents with names of {1}", Gridlist.count, ParentName));}
Run the program, click Button2, the effect is as follows:
The result shows that the traversal was successful.
Summarize
In this way we can get the control object we want and manipulate it, including the controls in the custom DataTemplate.
WPF uses VisualTreeHelper to traverse a child object or parent object that looks for an object