装饰器作为弹出窗口不起作用
Posted
技术标签:
【中文标题】装饰器作为弹出窗口不起作用【英文标题】:Adorner as popup not working 【发布时间】:2015-06-25 11:21:04 【问题描述】:我尝试使用装饰器在 WPF 中创建一个弹出窗口,以便将背景设置为灰色。这个想法是它可以接受任何类型的 UI 元素,灰色并锁定所有其他元素(如表单中的 showDialog),并显示 uielement。
它基于website的教程。
我有一个名为 popup 的类:
class PopUp : Adorner, IDisposable
private static readonly Brush _screenBrush = new SolidColorBrush(Color.FromArgb(0x7f, 0x7f, 0x7f, 0x7f));
private static UIElement _childElement;
private static Window _window;
private AdornerLayer _layer;
public static IDisposable Overlay(UIElement childElement)
_window = Application.Current.MainWindow;
var grid = LogicalTreeHelper.GetChildren(_window).OfType<Grid>().FirstOrDefault();
var adorner = new PopUp(grid, childElement) _layer = AdornerLayer.GetAdornerLayer(grid) ;
adorner._layer.Add(adorner);
return adorner as IDisposable;
private PopUp(UIElement parentParentElement, UIElement childElement)
: base(parentParentElement)
_childElement = childElement;
if (childElement != null)
AddVisualChild(childElement);
GetFocus(this);
protected override int VisualChildrenCount
get return _childElement == null ? 0 : 1;
protected override Visual GetVisualChild(int index)
if (index == 0 && _childElement != null)
return _childElement;
GetFocus(this);
return base.GetVisualChild(index);
protected override Size MeasureOverride(Size constraint)
_childElement.Measure(constraint);
return _childElement.RenderSize;
protected override Size ArrangeOverride(Size finalSize)
if (_childElement == null) return finalSize;
var adorningPoint = new Point(0, 0);
_childElement.Arrange(new Rect(adorningPoint, this.AdornedElement.RenderSize));
return finalSize;
protected override void OnRender(DrawingContext drawingContext)
_screenBrush.Opacity = 0.5;
drawingContext.DrawRectangle(_screenBrush, null, WindowRect());
base.OnRender(drawingContext);
private Rect WindowRect()
if (_window == null)
throw new ArgumentException("cant get main window");
var transformToAncestor = this.AdornedElement.TransformToAncestor(_window);
var windowOffset = transformToAncestor.Inverse.Transform(new Point(0, 0));
// Get a point of the lower-right corner of the window
var windowLowerRight = windowOffset;
windowLowerRight.Offset(_window.ActualWidth, _window.ActualHeight);
return new Rect(windowOffset, windowLowerRight);
private void GetFocus(UIElement element)
element.Focusable = true;
Keyboard.Focus(element);
element.IsEnabled = true;
public void Dispose()
_layer.Remove(this);
这个类具有装饰器的魔力,并在当前窗口内的第一个或默认网格的顶部绘制一个 UIelement。
我创建了一个静态类 PopUpExtender:
public static class PopUpExtender
private static Dictionary<UIElement, IDisposable> _popUps;
public static void ShowAsPopUp(this UIElement child)
if (_popUps == null)
_popUps = new Dictionary<UIElement, IDisposable>();
_popUps.Add(child, PopUp.Overlay(child));
public static void ClosePopUp(this UIElement child)
if (!_popUps.ContainsKey(child)) return;
var disposableChild = _popUps[child];
disposableChild.Dispose();
_popUps.Remove(child);
使用扩展方法允许 UI 元素关闭和显示。
一切似乎都正常,但键盘仍然可以使用窗口(和其他元素)。我尝试使用 isEnabled = false 但这让它有点难看,我试图获得与 showdialog() 相同的效果。
第二个问题是,当弹出窗口打开一个弹出窗口时,父级冻结并且不接受任何输入(什么都不接受..)。
我希望有人可以帮助我。也许装饰者不是这样做的最佳主意,如果有人有任何建议或更好的想法,请分享。
【问题讨论】:
在 XAML 的底部添加Rectangle
并使用 bool
属性(和 BooleanToVisibilityConverter
)切换其 Visibility
以用作您的 非常简单灰色.
也许我对装饰者有点忘乎所以。我会看看它。我有点希望有某种弹出库或可以轻松调用的东西,您不必再在 XAML 或代码中做太多工作
请参阅"Should questions include “tags” in their titles?",其中的共识是“不,他们不应该”!
对不起,我在其他问题中也看到了这个标签,所以我也把它放在那里。不会再发生
【参考方案1】:
这是一个不需要任何Adorner
s 的覆盖的简单示例。
XAML:
<Window x:Class="YourApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
... >
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<!-- Define your normal XAML here -->
<Rectangle Fill="#7FFFFFFF" Visibility="Binding YourBoolProperty,
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Converter=StaticResource BooleanToVisibilityConverter" />
</Window>
在代码中:
// Show overlay
YourBoolProperty = true;
...
// Hide overlay
YourBoolProperty = false;
【讨论】:
灰色效果很好,但似乎无法解决键盘输入的问题。这也意味着我必须将矩形添加到我想要弹出的每个 xaml 中。在使属性可见后,可以通过使用 showdialog 来解决输入问题。我会等到这个周末,看看有没有其他答案或建议,如果没有,我会把这个标记为答案Rectangle
应该添加到您正常内容下方的MainWindow.xaml
,因此您只需添加一个。以上是关于装饰器作为弹出窗口不起作用的主要内容,如果未能解决你的问题,请参考以下文章