如何在其他一切之上绘制 WPF 装饰器?
Posted
技术标签:
【中文标题】如何在其他一切之上绘制 WPF 装饰器?【英文标题】:How to draw WPF Adorners on top of everything else? 【发布时间】:2012-11-15 00:27:26 【问题描述】:我在DateTimePicker control 中添加了一个装饰器,但它没有显示在其他控件之上。为什么?我该如何解决?
我的 XAML 目前是这样的:
<UserControl x:Class="IntelliMap.WPF.DateTimePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpftc="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
mc:Ignorable="d">
...
<AdornerDecorator>
<Grid>
...
<TextBox x:Name="DateDisplay"
HorizontalAlignment="Stretch" ...>
</TextBox>
...
</Grid>
</AdornerDecorator>
</UserControl>
装饰器本身是一个独立于 UserControl 的类,并添加到构造函数中:
public DateTimePicker()
InitializeComponent();
...
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(DateDisplay);
if (adornerLayer != null)
adornerLayer.Add(_upDownBtns = new TextBoxUpDownAdorner(DateDisplay));
_upDownBtns.Click += (textBox, direction) => OnUpDown(direction); ;
【问题讨论】:
【参考方案1】:这个问题显然是因为由AdornerDecorator
管理的 Adorner 只能保证出现在 AdornerDecorator 内的控件之上。有必要将窗口的大部分内容包装在 AdornerDecorator 中,但这样做之后,AdornerLayer.GetAdornerLayer()
在某些情况下显然看不到 AdornerDecorator 并返回 null。
文档声称“GetAdornerLayer 从指定的UIElement
开始沿着可视化树向上走,并返回它找到的第一个装饰层。”实际上,GetAdornerLayer
找不到位于UserControl
之外的AdornerDecorator
,至少在 .NET 3.5 中找不到。我完全按照GetAdornerLayer
声称自己的方式解决了这个问题:
static AdornerLayer GetAdornerLayer(FrameworkElement subject)
AdornerLayer layer = null;
do
if ((layer = AdornerLayer.GetAdornerLayer(subject)) != null)
break;
while ((subject = subject.Parent as FrameworkElement) != null);
return layer;
public DateTimePicker()
InitializeComponent();
...
this.Loaded += (s, e) =>
// not null anymore!
AdornerLayer adLayer = GetAdornerLayer(DateDisplay);
;
最后,GetAdornerLayer
必须从 Loaded
事件而不是构造函数中调用。
【讨论】:
【参考方案2】:在默认的 Window 样式中已经有一个装饰层,并且该装饰层位于窗口内容的上方。
所以只需从 UserControl 中删除 AdornerLayer 就可以了。
【讨论】:
AdornerDecorator
存在是因为没有它,GetAdornerLayer
返回 null。
啊,在控件的激活事件中进行装饰器设置,而不是构造函数。 GetAdornerLayer 获取窗口 AdornerLayer 之前,控件需要在屏幕上。
什么活动? UserControl 上没有激活事件。我试过Loaded
,但GetAdornerLayer
在那个事件中仍然返回null。
在用户控件中,覆盖ApplyTemplate
。以上是关于如何在其他一切之上绘制 WPF 装饰器?的主要内容,如果未能解决你的问题,请参考以下文章