c# - 使用 VisualBrush 作为 OpacityMask

标签 c# .net wpf xaml visualbrush

我想将 OpacityMask 设置为控件,但我需要动态构建该蒙版。 它应该是这样的:


整个(红色)矩形的宽度和高度是动态的,基于父控件的宽度和高度。但我需要在左上角和右上角放置两个小矩形(静态宽度和高度),如图所示。那么我怎样才能实现这一点呢?

我尝试了这段代码,但它不起作用:(根本没有显示任何内容)

<Border BorderBrush="#80FFFFFF" BorderThickness="1" CornerRadius="5">
    <Border.OpacityMask>
        <VisualBrush>
            <VisualBrush.Visual>
                <DockPanel>
                    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Height="2">
                        <Border Background="Transparent" Width="12" VerticalAlignment="Stretch" HorizontalAlignment="Left" />
                        <Border Background="Black" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
                        <Border Background="Transparent" Width="12" VerticalAlignment="Stretch" HorizontalAlignment="Right" />
                    </StackPanel>

                    <Border Background="Black" />
                </DockPanel>
            </VisualBrush.Visual>
        </VisualBrush>
    </Border.OpacityMask>
</Border>

以这种方式使用 VisualBrush(作为 OpacityMask)是否有效?

最佳答案

如果我正确理解你的问题,你希望图像中的那些黑色方 block 是透明的吗?

更新:已在此处上传示例项目:http://www.mediafire.com/?5tfkd1cxwfq0rct

我认为问题在于 VisualBrush 内的 Panel 不会拉伸(stretch)。您可以通过将您使用的任何 Panel 的宽度和高度绑定(bind)到 Border

的 ActualWidth 和 ActualHeight 来获得所需的效果
<Border Name="border" BorderBrush="Red" BorderThickness="1" CornerRadius="5">
    <Border.OpacityMask>
        <VisualBrush>
            <VisualBrush.Visual>
                <Grid Width="{Binding ElementName=border, Path=ActualWidth}"
                      Height="{Binding ElementName=border, Path=ActualHeight}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="20"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="20"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Rectangle Fill="Transparent" Grid.Column="0"/>
                    <Rectangle Fill="Black" Grid.Column="1"/>
                    <Rectangle Fill="Transparent" Grid.Column="2"/>
                    <Rectangle Fill="Black" Grid.Row="1" Grid.ColumnSpan="3"/>
                </Grid>
            </VisualBrush.Visual>
        </VisualBrush>
    </Border.OpacityMask>
    <Grid>
        <TextBlock Text="Testing OpacityMask with a rather long string................." Grid.ZIndex="3"/>
        <Rectangle Fill="Green"/>
    </Grid>
</Border>

再次更新
Border 的装饰器子级的 DropShadowEffect 似乎插入了 Border 垂直和水平方向的 OpacityMask。更糟糕的是,它似乎堆叠起来,因此在您的示例中,当您为三个嵌套的装饰器拥有三个 DropShadowEffects 时,BlurRadius 的总和为 45 (20+15+10),因此 OpacityMask 为插入了 45 的值(至少看起来是这样,但有点难以判断......)。您可以尝试通过增加 ColumnDefinition 宽度和 RowDefinition 高度来弥补这一点,但我认为很难找到动态解决方案。

解决您的问题的更好方法可能是使用 Border.Clip 但这也并不容易。

Point1:  0, 2
Point2: 12, 2
Point3: 12, 0
Point4: Width of Border - 12, 0
Point5: Width of Border - 12, 2
Point5: Width of Border, 2
Point6: Width of Border, Height of Border
Point7: 0, Height of Border

更新3
想出了一个更好的解决方案,不需要那么多绑定(bind)。创建一个派生自 Border 的自定义类并重写 GetLayoutClip。这在设计器和运行时都有效。为了提高 ClippedBorder 的灵活性,您可以引入一些依赖属性来代替硬编码的 2 和 12。此处的新示例应用程序:http://www.mediafire.com/?9i13rrqpbmzdbvs

public class ClippedBorder : Border
{
    protected override Geometry GetLayoutClip(Size layoutSlotSize)
    {
        PathGeometry pathGeometry = new PathGeometry();
        pathGeometry.Figures = new PathFigureCollection();

        //Point1:  0, 2
        PathFigure pathFigure = new PathFigure();
        pathFigure.StartPoint = new Point(0, 2);

        //Point2: 12, 2
        LineSegment lineSegment1 = new LineSegment();
        lineSegment1.Point = new Point(12, 2);

        //Point3: 12, 0
        LineSegment lineSegment2 = new LineSegment();
        lineSegment2.Point = new Point(12, 0);

        //Point4: Width of Border - 12, 0
        LineSegment lineSegment3 = new LineSegment();
        lineSegment3.Point = new Point(this.ActualWidth-12, 0);

        //Point5: Width of Border - 12, 2
        LineSegment lineSegment4 = new LineSegment();
        lineSegment4.Point = new Point(this.ActualWidth-12, 2);

        //Point5: Width of Border, 2
        LineSegment lineSegment5 = new LineSegment();
        lineSegment5.Point = new Point(this.ActualWidth, 2);

        //Point6: Width of Border, Height of Border
        LineSegment lineSegment6 = new LineSegment();
        lineSegment6.Point = new Point(this.ActualWidth, this.ActualHeight);

        //Point7: 0, Height of Border 
        LineSegment lineSegment7 = new LineSegment();
        lineSegment7.Point = new Point(0, this.ActualHeight);

        pathFigure.Segments.Add(lineSegment1);
        pathFigure.Segments.Add(lineSegment2);
        pathFigure.Segments.Add(lineSegment3);
        pathFigure.Segments.Add(lineSegment4);
        pathFigure.Segments.Add(lineSegment5);
        pathFigure.Segments.Add(lineSegment6);
        pathFigure.Segments.Add(lineSegment7);

        pathGeometry.Figures.Add(pathFigure);

        return pathGeometry;
    }
}

关于c# - 使用 VisualBrush 作为 OpacityMask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4981696/

相关文章:

.net - 欺骗 .net 程序集并讨论以前发布的注释

c# - 为什么在 C# 中使用动态类型?

C# WPF 主窗口始终位于桌面前面

WPF-Listview 列标题使用自定义样式调整大小

c# - 有没有办法测量 WPF flowdoc 中 block /部分的高度?

c# - 读取 SOAP 消息响应 ASP.NET MVC4 C#

c# - 如何强制文本框只接受 WPF 中的数字?

C# - 方法签名中的通用类型 - 为什么是 CS1503, "Cannot Convert from IThing to ns.IThing"?

.net - 使用 NuGet 包确保可重复构建

c# - 无法加载文件或程序集 'System.Windows.Interactivity'