您现在的位置是:群英 > 开发技术 > 编程语言
WPF在VisualTree中加Visual的方法操作是什么
Admin发表于 2022-11-01 17:32:49421 次浏览
今天就跟大家聊聊有关“WPF在VisualTree中加Visual的方法操作是什么”的内容,可能很多人都不太了解,为了让大家更加了解“WPF在VisualTree中加Visual的方法操作是什么”,小编给大家总结了以下内容,希望这篇文章能帮助大家,下面我们一起来了解看看吧。


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

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

  • 从FrameworkElement继承
  • 增加一个Button到它的VisualTree上

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

    class MyElement : FrameworkElement
    {
        private Button _button = new Button() { Content = "I'm a Button!"};        

        public MyElement()
        {
            this.AssembleVisualChildren();
        }

        private void AssembleVisualChildren()
        {
            this.AddVisualChild(this._button);
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }
        protected override Visual GetVisualChild(int index)
        {            
            return this._button ;
        }
     }

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

<Window 
    x:Class="AddVisualChildTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:AddVisualChildTest"
    WindowStartupLocation="CenterScreen"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <loc:MyElement Margin="10"/>
    </Grid>
</Window>

运行后的结果如下:

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

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

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

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.VisualChildrenCount > 0)
            {
                UIElement child = this.GetVisualChild(0) as UIElement;
                Debug.Assert(child != null); // !Assert
                child.Measure(availableSize);
                return child.DesiredSize;
            }

            return availableSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            Rect arrangeRect = new Rect()
            {
                Width = finalSize.Width,
                Height = finalSize.Height
            };

            if (this.VisualChildrenCount > 0)
            {
                UIElement child = this.GetVisualChild(0) as UIElement;
                Debug.Assert(child != null); // !Assert
                child.Arrange(arrangeRect);
            }

            return finalSize;
        }

再次运行程序:

目标实现。

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

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

  • 重写VisualChildCount属性;

  • 重写GetVisualChild方法;

  • 重写MeasureOverride方法;

  • 重写ArrangeOverride方法; 

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

1、Panel

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

    class MyElement : Panel
    {
        private Button _button = new Button() { Content = "I'm a Button!" };

        public MyElement()
        {
            this.Children.Add(_button);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.VisualChildrenCount > 0)
            {
                UIElement child = this.GetVisualChild(0) as UIElement;
                Debug.Assert(child != null); // !Assert
                child.Measure(availableSize);
                return child.DesiredSize;
            }

            return availableSize;
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            Rect arrangeRect = new Rect()
            {
                Width = finalSize.Width,
                Height = finalSize.Height
            };

            if (this.VisualChildrenCount > 0)
            {
                UIElement child = this.GetVisualChild(0) as UIElement;
                Debug.Assert(child != null); // !Assert
                child.Arrange(arrangeRect);
            }

            return finalSize;
        }
    }

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

  • AddVisualChild

  • VisualChildCount

  • GetVisualChild

2、VisualCollection

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



以上就是关于WPF在VisualTree中加Visual的方法操作是什么的介绍,本文内容仅供参考,有需要的朋友可以借鉴了解看看,希望对大家学习或工作,想要了解更多欢迎关注群英网络,小编每天都会为大家更新不同的知识。

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

相关信息推荐
2022-12-01 16:14:40 
摘要:php验证码失效的解决办法:1、开启gd2选项;2、使用windows自带的记事本编辑器对网站配置文件进行修改和保存;3、使用“ob_clean()”方法清除相关缓存;4、重写规则“.htaccess”;5、开启Redis服务即可。
2022-04-28 11:54:59 
摘要:给大家带来一篇关于jquery获取上传文件名称、类型和大小的代码分析的相关教程文章,内容涉及到jquery、上传文件、名称、类型和大小、通过jquery获取上传文件名称、类型和大小的实现代码等相关内容,更多关于通过jquery获取上传文件名称、类型和大小的实现代码的内容希望能够帮助到大家。
2022-06-28 17:05:00 
摘要:Golang不可以把包名去掉,包名是一种类似命名空间的管理和组织代码的方式,而Golang的包有两种类型,一种是“main”包,该包的可以有唯一的一个“main”函数,这个函数也是程序的入口,另外一种就是非“main”包。
云活动
推荐内容
热门关键词
热门信息
群英网络助力开启安全的云计算之旅
立即注册,领取新人大礼包
  • 联系我们
  • 24小时售后:4006784567
  • 24小时TEL :0668-2555666
  • 售前咨询TEL:400-678-4567

  • 官方微信

    官方微信
Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
微信公众号
返回顶部
返回顶部 返回顶部