首先,千万不要觉得Adorner离你很远,因为最简单的WPF界面也会用到Adorner。在WPF中,下面的几个很常见的功能,都是用Adorner实现的。

1. 光标(caret)

2. 焦点(focus)

3. 高亮(highlight)

4. 拖拽预览(drag and drop)

5. 拼写错误提示

6. 数据绑定中用来提示错误的Error Template

当然还有别的,用Reflector很容易找到一些WPF中自带的Adorner。如下图所示。

很多吧!这些Adorner都是放在一个叫Adorner Layer的层上。MSDN解释说Adorner Layer是置于一个窗口内所有其它控件之上的。而且AdornerLayer类又没有public的结构函数,只能用下面的代码来取得某个控件的Adorner Layer的实例:

但是上面的方式会让人产生两个错觉:

1. Adorner Layer是WPF自带的,内置的,我们管不了。

2. 每个控件都有自己的Adorner Layer。

如果继续看看GetAdornerLayer的代码,就很容易知道Adorner Layer是从何而来的了。鉴于这个函数的源代码比较丑陋,就不贴在这里给微软丢人了。但是从源代码我们可以知道:

1. 不是每个控件都有Adorner Layer,其实只有AdornerDecorator和ScrollContentPresenter附带有Adorner Layer。

2. 对某个element取到的Adorner Layer,一般是其Ancestor的。

顺便解释一下,Decorator,很熟悉吧,就是装饰模式在WPF中的产物。是个比Adorner更宽泛的东西,Adorner就是Decorator的一种。我们常见的Border和 Viewbox等都属于Decorator。关于Decorator的更多信息可以看这里。

这样说来,AdornerDecorator就是Adorner Layer的提供者,我们再来看一下Window的默认Template。取自Blend中的aero.normalcolor.xaml文件。

<ControlTemplate TargetType="{x:Type Window}">
    <Border Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}">
        <AdornerDecorator>
            <ContentPresenter/>
        </AdornerDecorator>
    </Border>
</ControlTemplate>

也就是说所有的使用默认Template的Window都会有一个AdornerDecorator为其提供Adorner Layer。所以如果要自定义Window的Template也一定要记得为ContentPresenter加一个AdornerDecorator。

下面是AdornerDecorator的ArrangeOverride函数定义:

protected override Size ArrangeOverride(Size finalSize)
{
    Size size = base.ArrangeOverride(finalSize);
    if (VisualTreeHelper.GetParent(this._adornerLayer) != null)
    {
        this._adornerLayer.Arrange(new Rect(finalSize));
    }
 
    return size;
}

在base.ArrangeOverride中,Window中的Content得以渲染。然后AdornerDecorator才去Arrange自带的_adornerLayer。这样这个Adorner layer就位于所有Window Content之上了。

但是,是不是说就没有办法把东西放在AdornerLayer之上了呢?请读者自己想一想吧。

这里我也很想啰嗦一下,在重写的函数里,要不要调用base函数?在什么地方调用?都是很值得注意的。这个问题是要看具体情况具体分析的。而要想正确地调用base函数,就要对基类有一定了解。所以在需要的时候阅读源代码,了解其工作原理,是很有必要的。这个公理,也可以引出这样一个推论——在短时间内学通一项技术的想法或产品,都是不现实的。(学通的定义:如果把WPF从.NET里删除,理论上,能够自己重写一套出来)

知道了Adorner Layer的来源,我们再来看一下Adorner Layer上的Adorner。Adorner Layer里只能放Adorner,而Adorner也没有无参构造函数。所以有关Adorner的一切操作,在默认情况下,都只能在C#代码中进行(当然总有办法在XAML中定义Adorner)。在构造Adorner的时候,必须把Adorned Element做为参数传给Adorner。因为Adorner需要知道Adorned Element的位置和大小等信息。以便让Adorner Layer知道在什么地方渲染这个Adorner。所有的这些信息由Adorner Layer保存在一个叫Adorner Info的内部类中。

其中包含了渲染每个Adorner时所需要的一些信息。其中RenderSize和Transform都是根据Adorner的AdornedElement计算出来的。一但某个UIElement的位置或Transform等发生了变化。这个Element所关联到的所有的Adorner的AdornerInfo都会被更新一次。这样Adorner看上去和Adorned Element是一个控件一样,其实只是用Trasform把二者从位置关系上粘在了一起而已。

上面算是把Adorner Layer的原理介绍完了。简言之,一般一个Window有唯一的一个Adorner Layer,在渲染时,所有的Adorner都被放在了窗口的左上角,再用RenderTransform把这个Adorner移动到其关联的Adorned Element上。

Adorner继承于FrameworkElement,是个连Content属性,Child属性或是ControlTemplate属性都没有的东西。后果就是你要自己做一个Adorner,就要先继承Adorner类,再重写OnRender函数,并在里面,一条线,一条线地画出你想要的效果。当然谁也不想真的用DrawingContext是画个东西出来,解决方案也有不少。一个就是先给Adorner加上个UIElement类型的Child属性,然后就可以住这个UIElementAdorner里加WPF常见控件了不是?这里也给出了实现方式。

最后一个问题就是应该在什么时候用Adorner?我想应该从其设计理念上来回答这个问题。Adorner本身属于Decorator的一种,能够在不改变原有XAML结构的条件下,提供为每个独立控件,附着其它界面元素或装饰物的手段。这是一个很强大的设计思想。至于你可以用它来做什么?从第一张图中你应该可以看出一些端倪。但是在实际项目中,还要看大家自己的发挥了。下面大致给大家列举一些例子。(微软已经实现的就不再例出来了)

1. ListView列头中,表示当前排序方式的小箭头。我在之前的文章中已经给出了实现方式。

2. 图表中,如果需要每点一下鼠标,可以在图表上留下一个标记。这个标记就可以放在Adorner Layer中。

3. 程序加载或某个操作进行中时,为整个界面加的蒙版与Processing动画。

4. 界面设计工具中,用来调节控件大小的锚点。

这里已经给出了实现方式。

5. 放大镜控件中,放大出来的图像。(没实例,想象中)

6. 鼠标拖出来的选框,这个用图描述比较简洁。

在WPF程序中,善用Adorner Layer,相信不仅能够带来一些出众的效果,也能所软件的架构和模块更加明晰。

转载于:https://www.cnblogs.com/xpvincent/p/3695631.html

详解Adorner Layer(zz)相关推荐

  1. 外部如调用layui中的组件_详解layui.layer独立组件

    layer至今仍作为layui的代表作,她的受众广泛并非偶然,而是这五年多的坚持,不断完善和维护.不断建设和提升社区服务,使得猿们纷纷自发传播,乃至于成为今天的Layui最强劲的源动力. 目前,lay ...

  2. 网络7层协议详解——Network layer protocol

    OSI是一个开放性的通行系统互连参考模型,他是一个定义的非常好的协议规范.OSI模型有7层结构,每层都可以有几个子层.下面我简单的介绍一下这7层及其功能. OSI的7层从上到下分别是 7 应用层 6 ...

  3. 详解BLE 空中包格式—兼BLE Link layer协议解析

    BLE有几种空中包格式?常见的PDU命令有哪些?PDU和MTU的区别是什么?DLE又是什么?BLE怎么实现重传的?BLE ACK机制原理是什么?希望这篇文章能帮你回答以上问题. 虽然BLE空中包(pa ...

  4. SVN switch 用法详解 (ZZ)

    SVN switch 用法详解 (ZZ)  http://www.cnblogs.com/dabaopku/archive/2011/05/21/2052820.html 确实,以前不会用switch ...

  5. zz:NETCONF协议详解

    随着SDN的大热,一个诞生了十年之久的协议焕发了第二春,它就是NETCONF协议.如果你在两年前去搜索NETCONF协议,基本得到的信息都是"这个协议是一个网管协议,主要目的是弥补SNMP协 ...

  6. OpenLayers官方示例详解七之图层的最小、最大分辨率(Layer Min/Max Resolution)

    目录 一.示例简介 二.代码详解 一.示例简介 这个示例加载了一个MapBox的瓦片图层和一个Open Street Map的瓦片图层,同时使用最小.最大分辨率限制图层加载的比例级别. 使用鼠标放大两 ...

  7. Unity动画系统详解7:Layer是什么?

    摘要:使用Layer可以用来管理角色的不同身体部位.比如下半身用于行走或跑步,上半身用于射击或投掷物体. 洪流学堂,让你快人几步.你好,我是跟着大智学Unity的萌新,我叫小新,这几周一起来复(yu) ...

  8. php layer弹出层更改背景,详解Layer弹出层样式

    前言:学习layer弹出框,之前项目是用bootstrap模态框,后来改用layer弹出框,在文章的后面,我会分享项目的一些代码(我自己写的). layer至今仍作为layui的代表作,她的受众广泛并 ...

  9. SSL(Secure Sockets Layer)安全套接层协议详解

    SSL(Secure Sockets Layer)安全套接层协议详解 SSL简介 SSL历史发展 1.诞生 2.更名 3.发展 SSL协议结构 SSL协议结构详解 SSL警告协议 SSL修改密文协议 ...

最新文章

  1. 2019机器学习比赛_2019顶尖的机器学习课程
  2. Microbiome:南土所梁玉婷组-稻田土壤产甲烷菌的共存模式
  3. 美团应届生年薪达 35 万?究竟什么导致薪资倒挂?
  4. JSP第四课:用户注册登录设计(内置对象使用)
  5. centos7.3上yum install nodejs
  6. VTK:Utilities之ArrayLookup
  7. 一个没有收到任何Offer的应届生回想
  8. 信息系统项目管理师论文历年题目2005-2020
  9. OPPO 回应“不务正业”生产口罩;旧款 iPhone 降速被罚 2500 万欧元;Angular 9.0.0 发布| 极客头条...
  10. java循环制作万年历,JAVA-万年历代码--循环语句
  11. PyTorch深度学习实践概论笔记8练习-kaggle的Titanic数据集预测(一)数据分析
  12. POSCMS LOGO替换
  13. 【052】Emoji Mix-Emoji表情趣味合成
  14. 【信息技术学考】2021年深圳市高中学业水平考试卷(解析版)
  15. 初入Linux,M35作业第二弹,牛刀小试
  16. 力扣 25. K 个一组翻转链表
  17. java的environment_Java - 环境设置(Environment Setup)
  18. 聂文涛谈糖尿病并发症的成因
  19. 解决node-gyp ERR (npm install 报 gyp ERR等问题)
  20. python发微信语音没声音怎么回事_微信发语音没声音怎么回事?

热门文章

  1. IO流之过滤流介绍:
  2. centos snmp配置_如何在CentOS系统中安装配置SNMP服务
  3. 003_推箱子-事件
  4. 交叉编译php-5.6.30,linux下用arm-none-linux-gnueabi交叉编译arm内核模块
  5. python 保留两位小数 占位_第17p,Python中格式化输出的3种方式
  6. Java数据结构与算法:队列
  7. ANSYS Products 19.1 安装教程
  8. labview将产生数据存入数组 并保存成Excel
  9. centos7 python3.6升级到3.7_Centos7下把python 2.7升级到python 3.6(升级过程遇到的一些相关问题)...
  10. tableau使用需要收费吗_使用苹果手机时,这些需要注意的点,你都知道吗?