博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF的逻辑树与视觉树(2)Visual容器
阅读量:6253 次
发布时间:2019-06-22

本文共 4785 字,大约阅读时间需要 15 分钟。

原文:

 

一.摘要

虽然我们平时几乎不会从该类派生,但要想了解视觉树就必须要了解Visual,Visual是一个基本抽象类,继承自DependencyObject.其是所有控件的基类.并提供了视觉树操作的基本方法.

二.提纲

  1. 视觉树是一棵树
  2. 遍历视觉树
  3. 内置Visual集合容器ContainerVisual
  4. 小结

视觉树是一棵树

这好像是一句废话,但也没有错微笑.我们来看下Visual提供的一些基本的成员。

首先我们创立一个测试的对象

public class DefaultVisual : Visual    {        public string Key { get; set; }        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)        {            Console.WriteLine(this.Key + " ChildrenChanged");            if (visualAdded != null) Console.WriteLine((visualAdded as DefaultVisual).Key+" Added");            if (visualRemoved != null) Console.WriteLine((visualRemoved as DefaultVisual).Key+"Removed");            base.OnVisualChildrenChanged(visualAdded, visualRemoved);        }        protected override void OnVisualParentChanged(DependencyObject oldParent)        {            Console.WriteLine(this.Key + " ParentChanged");            if (oldParent != null) Console.WriteLine((oldParent as DefaultVisual).Key);            base.OnVisualParentChanged(oldParent);        }    }
测试代码
public static void Test(){    var test1 = new DefaultVisual();    test1.Key = "test1";    var test2 = new DefaultVisual();    test2.Key = "test2";    test1.AddVisualChild(test2);    var test3 = new DefaultVisual();    test3.Key = "test3";    test2.AddVisualChild(test3);    var test4 = new DefaultVisual();    test4.Key = "test4";    test1.AddVisualChild(test4);    test1.RemoveVisualChild(test4);}

结果

2.遍历视觉树

在调用AddVisualChild的时候,将会为两个Visual之间建立父子关系,子级知道父级,但父级却不知道有几个子级.所以很难遍历全部节点.需要把子节点给保存下来.Visual提供了两个成员用于视觉树的遍历,只要实现这两个成员就可以使用VisualTreeHelper进行遍历了.

image
下面我们就来实现这两个成员

3.Visual容器

Visual本身具备一些功能,同时也可以充当容器。

在实际情况下,容器分为两种,单容器和集合容器.比如Border就是一个单容器,其内部只可以放一个元素.Panel是一个集合容器.可以放多个元素.

单容器实现

public class SigletonVisual : DefaultVisual{    public Visual _child;    public Visual Child    {        get        {            return _child;        }        set        {            this.RemoveVisualChild(_child);            this.AddVisualChild(value);            _child = value;        }    }    protected override Visual GetVisualChild(int index)    {        return _child;    }    protected override int VisualChildrenCount    {        get        {            if (this._child != null)            {                return 1;            }            return 0;        }    }}

集合容器实现

public class PanelVisual : DefaultVisual{    public List
Visuals { get; set; } public PanelVisual() { Visuals = new List
(5); } public void Add(Visual visual) { Visuals.Add(visual); this.AddVisualChild(visual); } protected override Visual GetVisualChild(int index) { return Visuals[index]; } protected override int VisualChildrenCount { get { return Visuals.Count; } }}

遍历测试

void Test(){    var test1 = new PanelVisual();    test1.Key = "test1";    var test2 = new PanelVisual();    test2.Key = "test2";    test1.Add(test2);    var test3 = new PanelVisual();    test3.Key = "test3";    test2.Add(test3);    var test4 = new PanelVisual();    test4.Key = "test4";    test1.Add(test4);    PrintVisualTree(0, test1);}public void PrintVisualTree(int depth, PanelVisual obj){    Console.WriteLine(new string(' ', depth) + obj.Key);    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)    {        PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i) as PanelVisual);    }}

测试结果

3.内置Visual集合容器ContainerVisual

其实我们不用这么复杂,WPF内置类ContainerVisual已经默认实现了Visual集合容器,

ContainerVisual内部采用VisualCollection集合来维护视觉树,所以当我们添加Visual的时候,不需要调用AddVisualChild方法,而是应该调用VisualCollection的Add和Remove等方法

如下测试

public class TestVisual : ContainerVisual{    public static void Test2()    {        var test1 = new TestVisual();        test1.Key = "test1";        var test2 = new TestVisual();        test2.Key = "test2";        test1.Children.Add(test2);        var test3 = new TestVisual();        test3.Key = "test3";        test2.Children.Add(test3);        var test4 = new TestVisual();        test4.Key = "test4";        test1.Children.Add(test4);        PrintVisualTree(0, test1);    }    public static void PrintVisualTree(int depth, TestVisual obj)    {        Console.WriteLine(new string(' ', depth) + obj.Key);        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)        {            PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i) as TestVisual);        }    }    public string Key { get; set; }}

测试结果是一样的,但我们就可以省却手动实现VisualChildrenCount和GetVisualChild这两个成员了.
如果不从ContainerVisual 继承又想简单的维护Visual的话,可以使用VisualCollection来维护.

4.小结

这篇讲到了Visual的基本功能,Visual本身具备父子级关系的功能,但默认没有容器,需要我们自己实现.内置的ContainerVisual 使用VisualCollection实现了一个Visual容器功能.有了容器才能遍历整个视觉树,对Visual进行一些交互.

可能到这里却还没有看到具体UI的呈现.那就下篇了.

转载地址:http://xsysa.baihongyu.com/

你可能感兴趣的文章
python 基础复习 09 之基础函数
查看>>
Extjs 4
查看>>
Java内存模型(JMM)以及 垃圾回收机制 小结
查看>>
开源3D游戏引擎Irrlicht简介
查看>>
如何花更少的时间学习更多的知识
查看>>
学习鸟哥的Linux私房菜笔记(8)——文件查找与文件管理2
查看>>
day04 列表 增删改查 元组 range
查看>>
php 调用百度sms来发送短信的实现示例
查看>>
基于canvas的原生JS时钟效果
查看>>
PL/SQL查看表结构
查看>>
JSON的学习理解
查看>>
经典SQL语句大全
查看>>
升级fedora 18到fedora 19
查看>>
Dictionary和数组查找效率对比
查看>>
alias命令详情
查看>>
自定义异步加载资源插件
查看>>
easyui combobox两种不同的数据加载方式
查看>>
Smarty配置与实例化
查看>>
***Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。hash特别适合用于存储对象...
查看>>
Siege——多线程编程最佳实例
查看>>