详解WPF中VisualTree增加Visual的处理方法

这里我们将介绍WPF中VisualTree增加Visual的处理方法,首先我们将从一个典型的问题开始讲述。希望这些讨论能对大家有所帮助。

作为一个WPF控件开发者,我在工作中经常遇到如本文标题所示的问题。其实,这个问题并不是很难,只是在操作上有些繁琐。本文将尝试对这个问题进行解答,并且对相关的一些技术细节加以探讨。

#T#

先从我遇到的一个典型的问题开始吧:写一个MyElement类,要求如下:

从FrameworkElement继承

增加一个Button到它的VisualTree上

在Visual上有一个AddVisualChild方法,相信很多刚接触这个方法的同学们(好吧,至少我是这样)都会“顾名思义”地认为这个方法就可以解决本文的问题。再加上MSDN上也给出了一个例子来“火上浇油”一把。于是,一阵窃喜之后,我兴奋地敲出了以下代码:

 
 
 
  1. Code
  2.  class MyElement : FrameworkElement
  3. {
  4. private Button _button = new Button() { Content = "I'm a Button!"};
  5. public MyElement()
  6. {
  7. this.AssembleVisualChildren();
  8. }
  9. private void AssembleVisualChildren()
  10. {
  11. this.AddVisualChild(this._button);
  12. }
  13. protected override int VisualChildrenCount
  14. {
  15. get
  16. {
  17. return 1;
  18. }
  19. }
  20. protected override Visual GetVisualChild(int index)
  21. {
  22. return this._button ;
  23. }
  24.  }

然后将这个MyElement加入测试窗口,代码如下:

 
 
 
  1. Code   
  2.     
  3. x:Class="AddVisualChildTest.Window1"  
  4. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  5. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  6. xmlns:loc="clr-namespace:AddVisualChildTest"  
  7. WindowStartupLocation="CenterScreen"  
  8. Title="Window1" Height="300" Width="300">  
  9.   
  10.  Margin="10"/>  
  11.   
  12.  

运行后的结果如下:

空空如也!嗯,被忽悠了。一阵失落、打击之后,我的好奇心被激发了:这是为什么呢?于是我狂找资料,终于被我发现了:

实际上,在上面这个例子中,AddVisualChild这个方法只是在MyElement和Button之间建立起了一种VisualTree上的父子关系,但是并没有将Button挂接到MyElement的VisualTree上,所以最终我们没有在屏幕上看到这个Button。

为了将Button真正挂接到MyElement的VisualTree上,还需要额外做一件事情:在VisualTree上为这个Button分配空间并且指定位置,这个过程叫做Layout。此过程分两个部分:一个是Measure,另一个是Arrange。这两个过程在FrameworkElement上对应着两个方法:MeasureOverride和ArrangeOverride方法。具体做法如下:

 
 
 
  1. Code
  2. protected override Size MeasureOverride(Size availableSize)
  3. {
  4. if (this.VisualChildrenCount > 0)
  5. {
  6. UIElement child = this.GetVisualChild(0) as UIElement;
  7. Debug.Assert(child != null); // !Assert
  8. child.Measure(availableSize);
  9. return child.DesiredSize;
  10. }
  11. return availableSize;
  12. }
  13. protected override Size ArrangeOverride(Size finalSize)
  14. {
  15. Rect arrangeRect = new Rect()
  16. {
  17. Width = finalSize.Width,
  18. Height = finalSize.Height
  19. };
  20. if (this.VisualChildrenCount > 0)
  21. {
  22. UIElement child = this.GetVisualChild(0) as UIElement;
  23. Debug.Assert(child != null); // !Assert
  24. child.Arrange(arrangeRect);
  25. }
  26. return finalSize;
  27. }

再次运行程序:

目标实现。

由此,我们可以总结出这个问题的解决方案如下:

在MyElement的构造器中调用AddVisualChild方法;

重写VisualChildCount属性;

重写GetVisualChild方法;

重写MeasureOverride方法;

重写ArrangeOverride方法;

另外,WPF在此问题的解决上也为开发者提供了一些必要的帮助。就我所知的,有如下几个内容:

1、Panel

 还是本文开始提到的问题,只不过要将其中的FrameworkElement换为Panel。除了上面所提到的方法,Panel为我们提供了更加方便的实现方式。代码如下:

 
 
 
  1. Code
  2.  class MyElement : Panel
  3. {
  4. private Button _button = new Button() { Content = "I'm a Button!" };
  5. public MyElement()
  6. {
  7. this.Children.Add(_button);
  8. }
  9. protected override Size MeasureOverride(Size availableSize)
  10. {
  11. if (this.VisualChildrenCount > 0)
  12. {
  13. UIElement child = this.GetVisualChild(0) as UIElement;
  14. Debug.Assert(child != null); // !Assert
  15. child.Measure(availableSize);
  16. return child.DesiredSize;
  17. }
  18. return availableSize;
  19. }
  20. protected override Size ArrangeOverride(Size finalSize)
  21. {
  22. Rect arrangeRect = new Rect()
  23. {
  24. Width = finalSize.Width,
  25. Height = finalSize.Height
  26. };
  27. if (this.VisualChildrenCount > 0)
  28. {
  29. UIElement child = this.GetVisualChild(0) as UIElement;
  30. Debug.Assert(child != null); // !Assert
  31. child.Arrange(arrangeRect);
  32. }
  33. return finalSize;
  34. }
  35. }

之所以能这样做的原因是Panel已经替我们将如下几个工作封装在了UIElementCollection(Panel的Children属性)中:

AddVisualChild

VisualChildCount

GetVisualChild

2、VisualCollection

另外,在这个过程中,我们还可以使用一个叫做VisualCollection的类来作为所有 Visual Child的容器。这个容器构造的时候需要一个Visual类型的Parent,然后在添加、删除Visual Child的时候,它的相应方法(Add,Remove)就会帮助我们自动调用Parent的AddVisualChild和RemoveVisualChild方法。如此一来,我们的工作量又减少了。具体的实现代码很简单,这里就不贴了(总得动动脑子是不?)。

链接:http://www.cnblogs.com/AaronLu/archive/2009/11/09/1599348.html

当前题目:详解WPF中VisualTree增加Visual的处理方法
当前地址:http://www.shufengxianlan.com/qtweb/news46/370546.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联