在我的应用程序中,我在某些情况下需要一些模态行为,即只允许用户与UI的特定元素进行交互(例如,组框内的所有控件)。我不想使用模态对话框,所以我试图找到一种“淡出”所有的方法,除了应该保持活动的控件,最好是通过使其他所有内容变暗(从而为控件提供视觉焦点)问题)。
如何实现这样的行为?请注意,应该成为模态的元素始终是UI的一部分,因此我不能将它放在叠加层或类似的东西上。
我偶然发现了装饰品和装饰品,但关于这些的信息却很少......
答案 0 :(得分: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);
}
在上面的代码中,root
是窗口的根面板。
这种解决方案有点工作,但它有两个主要问题:
答案 1 :(得分:1)
我会选择一个Adorner,因为它是msdn指定的WPF元素,可用于“视觉掩盖或覆盖部分或全部UIElement”(see here)。
在blog post中可以找到一个很好的起点,您可能希望从渲染区域中排除要强调的UIElement区域。 (此时你甚至可以创建整个窗口的VisualBrush并使用它绘制装饰,如果你想获得很酷的效果,但是否则应该使用0.5不透明度的实心刷子。)
托马斯非常清楚地知道,当这种“模态”行为开启时,你应该禁用用户不应该与之交互的所有控件,因为只有禁用它们才能保证这些控件不会以任何方式响应用户输入(或者至少让它们变得不可聚焦,但我认为当你从“模态”状态返回时,这可能会破坏它们之前的状态)。