作为弹出窗口的Adorner无法正常工作

时间:2015-06-25 11:21:05

标签: c# wpf adorner

我尝试使用装饰器在WPF中创建一个Popup,以便我可以使背景变灰。这个想法是它会接受任何类型的UIelement,greyout并锁定所有其他的(如表格中的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);
    }}

使用扩展方法允许UIelement关闭并显示。

一切似乎都运转正常,但键盘仍然可以使用窗口(和其他元素)。我尝试使用isEnabled = false但这使它有点难看,我试图产生与showdialog()相同的效果。

第二个问题是当弹出窗口弹出一个弹出窗口时,父窗口会冻结并且不接受任何输入(没有任何输入......)。

我希望有人可以帮助我。也许装饰者不是最好的想法,如果有人有任何建议或更好的想法,请分享。

1 个答案:

答案 0 :(得分:0)

以下是一个不需要任何Adorner的叠加层的简单示例。

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;