Вы можете применить наложение ко всему окну и установить 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);
}
В приведенном выше коде root
является корневой панелью окна.
Это решение работает, но имеет две основные проблемы:
- Это не поддерживает изменение размера;Вероятно, это можно решить, связав ширину столбца и высоту строки наложенной сетки, используя конвертеры, но это не очень простовзаимодействовать с ними с помощью клавиатуры.Я думаю, что единственный способ предотвратить это - отключить их ...