使用 VisualBrush 作为 OpacityMask

发布于 2024-10-17 10:13:08 字数 1354 浏览 8 评论 0原文

我想将 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)?

I want to set OpacityMask to a control, but I need to build that mask dynamically.
Here is how it should look:



The width and height of the whole (red) rectangle is dynamic, based on width and height of parent control. But I need to place two small rectangles (static width and height) in top left and top right corner, as shown on image. So how can I make this happen?

I tried this code, but it doesn't work: (nothing is displayed at all)

<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>

Is it even valid to use VisualBrush this way (as a OpacityMask)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怕倦 2024-10-24 10:13:08

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

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

我认为问题在于 VisualBrush 内的 Panel 不会拉伸。您可以通过将您使用的任何 Panel 的宽度和高度绑定到 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
想出了一个更好的解决方案,不需要那么多绑定。创建一个派生自 Border 的自定义类并重写 GetLayoutClip。这在设计器和运行时都有效。为了提高 ClippedBorder 的灵活性,您可以引入一些依赖属性来代替硬编码的 2 和 12。此处的新示例应用程序:

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;
    }
}

If I understand your question correctly you want those Black squares in you image to be transparent?

Update: Uploaded sample project here: http://www.mediafire.com/?5tfkd1cxwfq0rct

I think the problem is that the Panel inside the VisualBrush won't stretch. You could get the desired effect by Binding the Width and Height of whatever Panel you use to the ActualWidth and ActualHeight of the Border

<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>

Update Again
The DropShadowEffect for the Decorator Child of the Border seems to push the OpacityMask for the Border both Verticaly and Horizontaly. And what's even worse is that it seems to stack, so in your example when you have three DropShadowEffects for three nested Decorators, the sum of the BlurRadius is 45 (20+15+10) so the OpacityMask is pushed by a value of 45 (at least it looks like this is whats going on, but it's a little hard to tell..). You could try to compensate for this by increasing the ColumnDefinition Widths and RowDefinition Heights but I think it'll be hard to find a dynamic solution.

A better approach to your problem may be to use Border.Clip but that doesn't come easy either.

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

Update 3
Came up with a better solution that doesn't require so many Bindings. Create a custom class that derives from Border and override GetLayoutClip. This works both in Designer and Runtime. To increase flexibility of ClippedBorder you could introduce some Dependency Properties to use instead of the hardcoded 2 and 12. New sample app here: 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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文