叠加透明度应覆盖父背景

时间:2014-11-18 09:11:16

标签: c# wpf overlay transparency clip

我的WPF应用程序覆盖了它,它显示了一些寄宿生"上下文敏感的帮助"。寄宿生现在应该否决父母背景并显示背后的内容(某种视图端口通过背景)。

如果没有覆盖,控件看起来像这样:

Overlay Inactive

Overlay Activated看起来像这样:

Overlay Active

Overlay是一个Usercontrol,包含一个ListBox,它应该提供一个寄存器。 ListBoxPanel是一个Canvas,ListBoxItems是你可以看到的Boarders(Buttons),它们使用ItemContainerStyle移动到它们应该包围的UIElements上。

Overlay看起来像这样:

   <ItemsControl ItemsSource="{Binding HelpItems}" KeyboardNavigation.TabNavigation="Cycle" IsTabStop="True"
                  helpers:FocusHelper.FocusOnLoad="True" FocusVisualStyle="{StaticResource EmptyFocusVisual}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Button Command="{Binding ShowPopupCommand}" Background="Transparent" BorderThickness="2">
                        <Button.Style>
                            <Style>
                                <Setter Property="Button.Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="{x:Type Button}">
                                            <Border Background="{TemplateBinding Background}"
                                                    BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}"/>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </Button.Style>
                    </Button>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding Left}" />
                <Setter Property="Canvas.Top" Value="{Binding Top}" />
                <Setter Property="FrameworkElement.Width" Value="{Binding Width}" />
                <Setter Property="FrameworkElement.Height" Value="{Binding Height}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

我希望叠加层在边框内是透明的,同时保持列表框上的半透明调暗背景,换句话说,我的ListBox的空白区域应该是灰色。 有没有简单的方法我可以让Light Blue边框显示面板背后的内容而没有我Overlay的半透明背景?

这是目标结果:

Expected

我也尝试创建一个不透明度过滤器,但这是错误的方法。并且似乎没有一种简单的方法来反转不透明度滤镜。

1 个答案:

答案 0 :(得分:1)

控制台,

好的,我们“要在冰上打个洞”。

所以这是一个自定义控件:OverlayWithGaps自我绘制,给定的背景可以是半透明的。

OverlayWithGaps有一个代表差距的Rect Collection:

    public ObservableCollection<Rect> Gaps
    {
        get { return (ObservableCollection<Rect>)GetValue(GapsProperty); }
        set { SetValue(GapsProperty, value); }
    }
    private static FrameworkPropertyMetadata fpm = new FrameworkPropertyMetadata(
        null,
        FrameworkPropertyMetadataOptions.AffectsRender |
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        null,
        null
    );
    public static readonly DependencyProperty GapsProperty =
        DependencyProperty.Register("Gaps", typeof(ObservableCollection<Rect>), typeof(OverlayWithGaps), fpm);

使用AffectsRender,如果该依赖项属性发生更改,则会发生重绘。

这是绘图功能:

protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
    if (Gaps != null && Gaps.Count > 0)
    {
        Geometry newGeometry = new RectangleGeometry(new Rect(0, 0, ActualWidth, ActualHeight));
        foreach (var gap in Gaps)
            // remove each rectangle  of the global clipping rectangle :
            // we make "a hole in the ice"
            newGeometry = Geometry.Combine(newGeometry, 
                new RectangleGeometry(gap), 
                GeometryCombineMode.Exclude, 
                transform: null);
        // When the geometry is finished, we make the hole
        dc.PushClip(newGeometry);
    }
    dc.DrawRectangle(Background, null, new Rect(0, 0, ActualWidth, ActualHeight));
}

修改
3. ItemsControl ListViewItems

提供了矩形
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    // overlay is the OverlayWithGaps instance   
    // in the window
    overlay.Gaps = new ObservableCollection<Rect>(
        itemsControl1.FindAllVisualDescendants()
            .OfType<Grid>()
            .Select(grid => {
                Point relativePoint = grid.TransformToAncestor(this)
                    .Transform(new Point(0, 0));
                return new Rect(relativePoint.X, 
                    relativePoint.Y, 
                    grid.ActualWidth, 
                    grid.ActualHeight
                );
            })
    );
}

请注意,我在LINQ查询中选择了Grids,因为它们位于DataTemplate中 但是Linq查询几乎可以选择任何东西(按名称,......)

FindAllVisualDescendants()扩展功能可在此处找到:
 Datagrid templatecolumn update source trigger explicit only updates first row

  1. 以下是完整的解决方案:http://1drv.ms/1OO2gWk
  2. 最佳编码