WPF的逻辑树与视觉树(2)Visual容器
一.摘要
虽然我们平时几乎不会从该类派生,但要想了解视觉树就必须要了解Visual,Visual是一个基本抽象类,继承自DependencyObject.其是所有控件的基类.并提供了视觉树操作的基本方法.
二.提纲
- 视觉树是一棵树
- 遍历视觉树
- 内置Visual集合容器ContainerVisual
- 小结
视觉树是一棵树
这好像是一句废话,但也没有错
.我们来看下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进行遍历了.
![]()
下面我们就来实现这两个成员
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<Visual> Visuals { get; set; } public PanelVisual()
{
Visuals = new List<Visual>(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的呈现.那就下篇了.
WPF的逻辑树与视觉树(2)Visual容器的更多相关文章
- 【WPF】逻辑树和视觉树
WPF中提供了遍历逻辑树和视觉树的辅助类:System.Windows.LogicalTreeHelper和 System.Windows.Media.VisualTreeHelper. 注意遍历的位 ...
- WPF的逻辑树与视觉树(1)基本概念
原文:WPF的逻辑树与视觉树(1)基本概念 一.摘要 逻辑树与视觉树属于WPF的基本概念,学过WPF或者Silverlight的朋友一定会对其有所耳闻,这篇文章将来探讨逻辑树与视觉树的特质以及 ...
- WPF的逻辑树和视觉树
原文:WPF的逻辑树和视觉树 这部分的内容来自于即将出版的新书<WPF Unleashed>的第三章样章.关于什么是逻辑树,我们先看下面的一个伪XAML代码的例子: <Window ...
- 理解WPF中的视觉树和逻辑树
轉載地址:http://blog.csdn.net/changtianshuiyue/article/details/26981797 理解WPF中的视觉树和逻辑树 Understanding th ...
- WPF的逻辑树与视觉树(3)Visual呈现
原文:WPF的逻辑树与视觉树(3)Visual呈现 这篇就点到为止,挑重点讲 绘图方式有两种 1.继承UIElement,重写OnRender方法 public partial class Windo ...
- wpf 逻辑树与可视化树
XAML天生就是用来呈现用户界面的,这是由于它具有层次化的特性.在WPF中,用户界面由一个对象树构建而成,这棵树叫作逻辑树.逻辑树的概念很直观,但是为什么要关注它呢?因为几乎WPF的每一方面(属性.事 ...
- WPF学习(4)逻辑树和可视树
前面几节说了一些WPF的基础,包括XAML和布局等.在接下来的几节,我们来说说WPF的核心概念,包括逻辑树和可视树.依赖对象和依赖属性.路由事件.命令这几个部分.本节介绍下逻辑树(Logical Tr ...
- WPF中的逻辑树和可视化树
WPF中的逻辑树是指XAML元素级别的嵌套关系,逻辑树中的节点对应着XAML中的元素. 为了方便地自定义控件模板,WPF在逻辑树的基础上进一步细化,形成了一个“可视化树(Visual Tree)”,树 ...
- WPF路由事件一:逻辑树和可视树
一.什么是逻辑树 逻辑树就是描述WPF界面元素的实际构成,它是由程序在XAML中所有的UI元素组成.最显著的特点就是由布局控件.或者其他常用的控件组成. <Window x:Class=&quo ...
随机推荐
- python3中numpy函数tile的用法
tile函数位于python模块 numpy.lib.shape_base中,他的功能是重复某个数组.比如tile(A,n),功能是将数组A重复n次,构成一个新的数组,我们还是使用具体的例子来说明问题 ...
- 交换排序(java)
package exchange_sort; import java.util.Random; /*各类交换排序 * ------数据存储范围1~s.length-1 ------ *主要包含 ...
- 搭建hbase-0.94.26集群环境 分类: B7_HBASE 2015-01-24 17:14 861人阅读 评论(0) 收藏
先安装hadoop1.2.1,见http://blog.csdn.net/jediael_lu/article/details/38926477 1.配置hbase-site.xml <prop ...
- JDK8 JVM性能优化-1
原文地址:https://blog.csdn.net/xingkongtianma01/article/details/80689928 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的 ...
- thinkphp mysql 坐标按距离排序
$cha1 = new Model(); $shops = $cha1->query("select *,(2 * 6378.137* ASIN(SQRT(POW(SIN(3.1415 ...
- iOS writeTofile 和对象的序列化
前言:做了一个图片浏览的小demo,支持随意添加.删除图片,图片放大.缩小,带矩形框的截图.随后几篇博客都会详细讲解在此过程中遇到的各种问题.这篇主要讲,在做添加.删除这个功能时,遇到的存文件的问题. ...
- Net Reactor 5
Net Reactor 5脱壳教程 今天别人发来一个.Net的DLL让我脱壳,第一步自然是先扔进de4dot 我这个de4dot 是集成了 Ivancito0z / TheProxy / PC- ...
- 【u027】神秘大三角
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 判断一个点与已知三角形的位置关系. [输入格式] 前三行:每行一个坐标,表示该三角形的三个顶点 第四行 ...
- 【codeforces 750A】New Year and Hurry
time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...
- [Ramda] Create an Array From a Seed Value with Ramda's unfold
In this lesson we'll look at how you can use Ramda's unfold function to generate a list of values ba ...