zoukankan      html  css  js  c++  java
  • VisualTreeHelper使用——使用BFS实现高效率的视觉对象搜索

    BFS,即广度优先搜索,是一种典型的图论算法。BFS算法与DFS(深度优先搜索)算法相对应,都是寻找图论中寻路的常用算法,两者的实现各有优点。

    其中DFS算法常用递归实现,也就是常见的一条路找到黑再找另一条。如果我们要找的数据存储在一棵树最靠左侧的一边时,DFS的好处就显现出来了。无论数据在树的多深,DFS都能在线性的时间内找出这个数据。

    而BFS算法常用队列实现,在查找树内对象时,会由树的根节点,一层一层向下找到目标。BFS的好处在于不管数据存在树的哪个节点,BFS都能以一个比较恒定的速度找到对象,这个速度几乎只与没寻找的深度和每层的节点数量相关。

    所以在遍历视觉树时使用BFS相较于DFS有什么好处呢?

    一个很明显的视觉树遍历特点就是,一般要找到的视觉对象都不会存储在离根节点特别远的地方。此时BFS相比DFS更不容易出现一条分支摸到黑啥都没找的情况。

    话不多少了,上代码!

    public static class VisualTreeExtension
    {
    
        /// <summary>
        /// Find all children T in dpObj using BFS.
        /// </summary>
        /// <param name="maxDepth">max finding depth of visual tree.</param>
        /// <param name="maxChildCount">maximum number of child nodes. Whose number of child nodes exceeds this value will be excluded</param>
        /// <returns></returns>
        public static IEnumerable<T> GetChild<T>(this DependencyObject dependencyObject, uint maxDepth = uint.MaxValue, uint maxChildCount = 20)
            where T : DependencyObject
        {
            int depth = 1;
            int count = VisualTreeHelper.GetChildrenCount(dependencyObject);
            Queue<DependencyObject> qObjs = new Queue<DependencyObject>();
            for (int i = 0; i < count; i++)
            {
                qObjs.Enqueue(VisualTreeHelper.GetChild(dependencyObject, i));
            }
    
            while (qObjs.Count != 0)
            {
                if (depth > maxDepth)
                    yield break;
                depth++;
                count = qObjs.Count;
                for (int i = 0; i < count; i++)
                {
                    var obj = qObjs.Dequeue();
                    if (obj is T result)
                        yield return result;
                    int child_count = VisualTreeHelper.GetChildrenCount(obj);
                    if (child_count > maxChildCount)
                        continue;
                    for (int j = 0; j < child_count; j++)
                    {
                        qObjs.Enqueue(VisualTreeHelper.GetChild(obj, j));
                    }
                }
            }
        }
    
        /// <summary>
        /// Find all children T in dpObj using BFS.
        /// </summary>
        /// <param name="maxDepth">max finding depth of visual tree.</param>
        /// <param name="maxChildCount">maximum number of child nodes. Whose number of child nodes exceeds this value will be excluded</param>
        /// <returns></returns>
        public static IEnumerable<T> GetChild<T>(this DependencyObject dependencyObject, string name, uint maxDepth = uint.MaxValue, uint maxChildCount = 20)
            where T : FrameworkElement
        {
            int depth = 1;
            int count = VisualTreeHelper.GetChildrenCount(dependencyObject);
            Queue<DependencyObject> qObjs = new Queue<DependencyObject>(count);
            for (int i = 0; i < count; i++)
            {
                qObjs.Enqueue(VisualTreeHelper.GetChild(dependencyObject, i));
            }
    
            while (qObjs.Count != 0)
            {
                if (depth > maxDepth)
                    yield break;
                depth++;
                count = qObjs.Count;
                for (int i = 0; i < count; i++)
                {
                    var obj = qObjs.Dequeue();
                    if (obj is T result && result.Name == name)
                        yield return result;
                    int child_count = VisualTreeHelper.GetChildrenCount(obj);
                    if (child_count > maxChildCount)
                        continue;
                    for (int j = 0; j < child_count; j++)
                    {
                        qObjs.Enqueue(VisualTreeHelper.GetChild(obj, j));
                    }
                }
            }
        }
    }

    使用方法:

    var scrollViewer = listView.GetChild<ScrollViewer>().First();

    也可以手动指定BFS的最大深度和最大子节点数量,避免遍历浪费太多时间

  • 相关阅读:
    重构之重新组织函数(Split Temporary Variable)
    HammperSpoon 不能 Focus Google Chrome 的问题
    如何让 vim 可以在命令行执行命令并且附加参数
    This bison version is not supported for regeneration of the Zend/PHP parsers
    php cURL library is not loaded
    aws linuxbrew GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2
    gen-cpp/.deps/ChildService.Plo: No such file or directory
    快速解码base64和utf-8的ASCII编码和URL解码
    英文版firefox显示中文字体丑的问题
    linux find 反转 查找没有被找到的结果
  • 原文地址:https://www.cnblogs.com/loyieking/p/11661793.html
Copyright © 2011-2022 走看看