如何消除给定控件"周围"的所有内容?

Sen*_*rst 8 wpf user-interface

在我的应用程序中,我在某些情况下需要一些模态行为,即只允许用户与UI的特定元素进行交互(例如,组框内的所有控件).我不想使用模态对话框,因此我尝试找到一种方法来"淡出" 除了应该保持活动的控件之外的所有内容,最好是通过使其他所有内容变暗(从而为所讨论的控件提供视觉焦点).

怎么可能实现这样的行为?请注意,应该成为模态的元素始终是UI的一部分,因此我不能将它放在叠加层或类似的东西上.

我偶然发现了装饰品和装饰品,但关于这些的信息却很少......

Tho*_*que 3

您可以将覆盖层应用到整个窗口,并设置该OpacityMask覆盖层的 ,使其在必须是模态的元素上方透明。我将尝试在几分钟内发布一个示例。


编辑:好的,这比我预期的要难一点......这是一个有点有效但丑陋的解决方案:

    private Grid _modalOverlay;

    private void btnShowOverlay_Click(object sender, RoutedEventArgs e)
    {
        if (_modalOverlay != null)
            root.Children.Remove(_modalOverlay);
        _modalOverlay = MakeModalOverlay(groupBox1, root, 0.5);
        root.Children.Add(_modalOverlay);
    }

    private static Grid MakeModalOverlay(FrameworkElement element, FrameworkElement root, double opacity)
    {
        var offset = GetRelativeOffset(element, root);

        Grid g = new Grid();

        var c0 = new ColumnDefinition();
        c0.Width = new GridLength(offset.X);
        var c1 = new ColumnDefinition();
        c1.Width = new GridLength(element.ActualWidth);
        var c2 = new ColumnDefinition();
        c2.Width = new GridLength(root.ActualWidth - element.ActualWidth - offset.X);

        var r0 = new RowDefinition();
        r0.Height = new GridLength(offset.Y);
        var r1 = new RowDefinition();
        r1.Height = new GridLength(element.ActualHeight);
        var r2 = new RowDefinition();
        r2.Height = new GridLength(root.ActualHeight - element.ActualHeight - offset.Y);

        g.ColumnDefinitions.Add(c0);
        g.ColumnDefinitions.Add(c1);
        g.ColumnDefinitions.Add(c2);
        g.RowDefinitions.Add(r0);
        g.RowDefinitions.Add(r1);
        g.RowDefinitions.Add(r2);

        Brush b = new SolidColorBrush(Colors.Black) { Opacity = opacity };
        for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
        {
            if (i == 1 && j == 1)
                continue;

            Rectangle r = new Rectangle();
            r.Fill = b;
            Grid.SetColumn(r, i);
            Grid.SetRow(r, j);
            g.Children.Add(r);
        }

        Panel.SetZIndex(g, int.MaxValue);

        return g;
    }

    private static Vector GetRelativeOffset(Visual visual, Visual ancestor)
    {
        Visual tmp = visual;
        Vector offset = default(Vector);
        while (tmp != ancestor)
        {
            offset += VisualTreeHelper.GetOffset(tmp);

            tmp = (Visual) VisualTreeHelper.GetParent(tmp);
            if (tmp == null)
                throw new ArgumentException("ancestor is not an visual ancestor of visual");
        }
        return offset;
    }

    private void btnHideOverlay_Click(object sender, RoutedEventArgs e)
    {
        if (_modalOverlay != null)
            root.Children.Remove(_modalOverlay);
    }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,root是窗口的根面板。

这个解决方案确实有效,但有两个主要问题:

  • 不支持调整大小;这可能可以通过使用转换器绑定覆盖网格的列宽和行高来解决,但这并不是很简单
  • 它会阻止您单击其他控件,但您仍然可以使用键盘与它们交互。我认为防止这种情况的唯一方法是实际上禁用它们......