如何从WPF中不透明的画布中剪切透明位?

时间:2014-06-27 18:19:54

标签: wpf drawing transparency

我在WPF中有一个绘图,在那里我设置了一个带有背景颜色的画布,然后绘制了很多东西。现在我想制作切口,即具有相当任意形状的透明区域。我的方法是使用VisualBrush作为不透明蒙版。

以下是正在进行的工作的简化版

<Canvas Background="LightGray" Width="{Binding SizeX}" Height="{Binding SizeY}">
     <Canvas.OpacityMask>
     <VisualBrush 
        VIEWPORT / TILING VOODO HERE
     >
         <VisualBrush.Visual>
             <Canvas Background="#ffffffff" Width="{Binding SizeX}" Height="{Binding SizeY}">
                      DRAW CUTTOUTS HERE. 
                      If I got the Viewport/tiling voodoo right I should
                      just use the same coordinate system as for visible things.
             </Canvas>
         </VisualBrush.Visual>
     </VisualBrush>
     </Canvas.OpacityMask>

    DRAW VISIBLE THINGS HERE
</Canvas>

但我正在与保留模式绘图发生冲突。我的想法是用#ff填充背景alpha通道,以便默认情况下不透明,然后有透明切口。但当然,评估的是完全不透明背景上的透明形状,因此没有镂空。

那么如何获得我的剪影呢?

1 个答案:

答案 0 :(得分:0)

你去吧

我放置了一个内部画布来托管你的内容,并使用相同的画布作为可视画笔的视觉效果,它将用于外部画布的不透明蒙版。这将使您能够根据内部画布中的内容剪切外部画布

<Canvas x:Name="outer" Background="Green" Width="100" Height="100">
    <Canvas x:Name="inner" Width="{Binding ActualWidth,ElementName=outer}" Height="{Binding ActualHeight,ElementName=outer}">
        <!--your arbitery content here-->
        <Ellipse Width="20" Height="10" Fill="Gray" Canvas.Left="10" Canvas.Top="10"/>
    </Canvas>
    <Canvas.OpacityMask>
        <VisualBrush Visual="{Binding ElementName=inner}" 
                     ViewportUnits="Absolute" ViewboxUnits="Absolute"
                     Viewbox="0,0,100,100" Viewport="0,0,100,100"/>
        <!--you may need to write conveter class for conversion from SizeX & SizeY to Viewbox & Viewport-->
    </Canvas.OpacityMask>
</Canvas>

示例中的所有硬编码都是Viewbox&amp;视口编号(也硬编码外部画布的宽度和高度以匹配数字),您可以编写一个转换器,以便与SizeX&amp; SizeY因为可视刷中的所有属性都需要准确才能正确映射

注意不要将背景应用于内部画布

<强>更新

如所讨论的,如果你想剪切画布的背景而不是在这里显示形状是样本,如果没有要剪切的形状,还添加了触发器以禁用不透明蒙版

<Canvas Background="Green">
    <Canvas.Style>
        <Style TargetType="Canvas">
            <Style.Resources>
                <Canvas x:Key="maskVisual">
                    <!--your arbitery content here-->
                    <Ellipse Width="20" Height="10" Fill="Gray" 
                             Canvas.Left="10" Canvas.Top="10"/>
                </Canvas>
            </Style.Resources>
            <Setter Property="OpacityMask">
                <Setter.Value>
                    <VisualBrush Visual="{StaticResource maskVisual}"
                                 ViewportUnits="Absolute" ViewboxUnits="Absolute"
                                 Viewbox="0,0,100,100" Viewport="0,0,100,100"/>
                    <!--you may need to write conveter class for conversion from SizeX & SizeY to Viewbox & Viewport-->
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Children.Count, Source={StaticResource maskVisual}}" Value="0">
                    <Setter Property="OpacityMask" Value="{x:Null}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Canvas.Style>
</Canvas>

1点需要注意的是,由于画布默认情况下不会剪辑,因此您可能无需明确设置宽度和高度