WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象

简介: 原文:WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象 简介   本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数实现部分。
原文: WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象

简介

  本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数实现部分。
  或者直接在GitHub上下载源码
  
  在WPF中我们经常会遇到这种情况:当我们尝试着去寻找窗体或者页面中某个控件的子控件或者父控件的时候,我们只能寻找到它的第一级的逻辑子级对象或者父级对象。当我们想更深入的时候,就没有办法了。
  甚至在我们自定义的DataTemplate中的控件,我们都没办法对其访问。比如在ListView中自定义的控件,我们就没办法获取指定位置的控件了。相关例子可以参见我的博文: WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
  本文将探讨解决方案。

VisualTreeHelper

  微软在VisualTreeHelper类中,提供了一些实用工具方法,用于执行涉及可视化树中的节点的常规任务,VisualTreeHelper 类中的一些方法可以接受表示任意一种可视对象类型的 DependencyObject 值。
  这里我们将要用到两个方法分别是:VisualTreeHelper.GetChild()VisualTreeHelper.GetParent()

使用VisualTreeHelper

模拟场景搭建

  新建一个WPF工程,命名为VisualTreeHelperDemo。
  假设我们有如下如所示的一个主窗体,窗体的内容容器为一个name=”TopGrid”的Grid控件,它包含了上下两个子级Grid,每个子级Grid中各自包含了一个Button。
  这里写图片描述
  MainWindow.xaml代码如下:  

<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="350" 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>
        <Grid  Grid.Row="1">
            <Button Content="Button2" Name="btn_Two" VerticalAlignment="Center" HorizontalAlignment="Center">
            </Button>
        </Grid>
    </Grid>
</Window>

遍历寻找子级对象

  现在我们来寻找TopGrid所有Button子级对象,并输出它们的名称。
  打开MainWindow.xaml.cs文件,添加寻找子级对象的代码如下:

/// <summary>
/// 利用visualtreehelper寻找对象的子级对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
List<T> FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
    try
    {
        List<T> TList = new List<T> { };
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child != null && child is T)
            {
                TList.Add((T)child);
                List<T> childOfChildren = FindVisualChild<T>(child);
                if (childOfChildren != null)
                {
                    TList.AddRange(childOfChildren);
                }
            }
            else
            {
                List<T> childOfChildren = FindVisualChild<T>(child);
                if (childOfChildren != null)
                {
                    TList.AddRange(childOfChildren);
                }
            }
        }
        return TList;
    }
    catch (Exception ee)
    {
        MessageBox.Show(ee.Message);
        return null;
    }
}

  在btn_One_Click事件里面书写代码如下:

/// <summary>
/// 窗体加载事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_One_Click(object sender, RoutedEventArgs e)
{
    string btnName = "";
    List<Button> btnList = FindVisualChild<Button>(TopGrid);
    foreach (Button item in btnList)
    {
        btnName += string.IsNullOrEmpty(btnName) ? item.Name.ToString() : "," + item.Name.ToString();
    }
    Show(string.Format(TopGrid.Name.ToString()+"共有{0}个Button,名称分别为{1}", btnList.Count, btnName));
}

  运行程序,点击Button1,结果如下图:
  
  这里写图片描述
  
  结果表明遍历成功。
  

遍历寻找父级对象

  现在我们来遍历Button2的父级对象,获得其所有父级对象的信息,并且展示。
  打开MainWindow.xaml.cs文件,添加寻找父级对象的代码如下:

/// <summary>
/// 利用VisualTreeHelper寻找指定依赖对象的父级对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static List<T> FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
{
    try
    {
        List<T> TList = new List<T> { };
        DependencyObject parent = VisualTreeHelper.GetParent(obj);
        if (parent != null && parent is T)
        {
            TList.Add((T)parent);
            List<T> parentOfParent = FindVisualParent<T>(parent);
            if (parentOfParent !=null)
            {
                TList.AddRange(parentOfParent);
            }
        }
        else if ( parent != null )
        {
             List<T> parentOfParent = FindVisualParent<T>(parent);
             if (parentOfParent != null)
             {
                 TList.AddRange(parentOfParent);
             }
        }
        return TList;
    }
    catch (Exception ee)
    {
        MessageBox.Show(ee.Message);
        return null;
    }
}

  在btn_Two_Click中添加代码如下:

/// <summary>
/// 遍历Button2父级对象信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Two_Click(object sender, RoutedEventArgs e)
{
    string parentName = "";
    List<Grid> gridList = FindVisualParent<Grid>(btn_Two);
    foreach (Grid item in gridList)
    {
        parentName += string.IsNullOrEmpty(parentName) ? item.Name.ToString() : "," + item.Name.ToString();
    }
    MessageBox.Show(string.Format(btn_Two.Name.ToString() + "共有{0}个逻辑父级,名称分别为{1}", gridList.Count, parentName));
}

  运行程序,点击Button2,效果如下:
这里写图片描述
  结果表明遍历成功。

总结

  通过上述的方法我们就可以随心所欲地获取我们想要的控件对象,并对其进行操作,包括自定义的DataTemplate中的控件都可以获取。

目录
相关文章
|
C#
WPF 遍历DataTemplate(获取所有控件)
原文:WPF 遍历DataTemplate(获取所有控件) 情况1:在设定DataTemplate的Name,并且他是在前台表示时,获取DataTemplate里的指定控件。
2010 0
|
4月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
102 0
WPF界面异常:未将对象引用设置到对象实例
WPF界面异常:未将对象引用设置到对象实例
|
数据可视化 测试技术 C#
WPF中的可视化对象(Visual)
原文:WPF中的可视化对象(Visual) 这是MSDN对Visual的解释:Visual class:Provides rendering support in WPF, which includes hit test...
1034 0
|
C#
WPF中,怎样将XAML代码加载为相应的对象?
原文:WPF中,怎样将XAML代码加载为相应的对象? 在前面“在WPF中,如何得到任何Object对象的XAML代码?”一文中,我介绍了使用System.Windows.Markup.XamlWriter.Save(objName)得到任何Object对象的XAML代码。
932 0
|
C#
WPF中实现图片文件转换成Visual对象,Viewport3D对象转换成图片
原文:WPF中实现图片文件转换成Visual对象,Viewport3D对象转换成图片 1、图片文件转换成Visual对象         private Visual CreateVisual(string imageFileName)        {            BitmapImag...
1186 0
|
C# 容器
WPF遍历当前容器中某种控件的方法
原文:WPF遍历当前容器中某种控件的方法 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37591671/article/details/79528845 ...
1029 0
|
C#
WinForm和WPF颜色对象的转换
原文:WinForm和WPF颜色对象的转换 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangli321456/article/details/52956846 ...
875 0
|
C# 前端开发 Windows
在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象
原文:在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象 这是我辅导的一个项目开发中的例子,他们是用WPF做界面开发,在学习了如何使用MVVM来实现界面与逻辑的分离,并且很好的数据更新之后,有一个疑问就是,这种双向的数据更新确实很不错,但如果我们希望用户可以撤销修改怎么办呢?其实这个功能,很早就有,甚至在原先的Windows Forms里面也可以实现。
971 0
|
C# 存储
【值转换器】 WPF中Image数据绑定Icon对象
原文:【值转换器】 WPF中Image数据绑定Icon对象        这是原来的代码:                这里的MenuIcon是string类型,MenuIcon = "/Image/Tux.ico"。
906 0