상세 컨텐츠

본문 제목

Reflection using Visual Brush and Opacity Mask

WPF

by happynuri 2008. 1. 31. 14:36

본문

Using brushes in WPF you can paint surfaces with patterns, images, colors, and gradients. One brush that is particularly useful is the VisualBrush. This brush paints an area with other visual objects, allowing elements to be “mirrored”.

The effect of reflection is easily achieved using a VisualBrush. With just a few lines of XAML we can reproduce this effect.

For this example, we will reflect a standard image. The XAML for this is simply:

<Image Source="images/lighthouse.jpg" Width="400" Height="300" />

Now let’s work on the reflection. First we will create a border element with the same dimensions as our image. This will provide us with a shape we can apply our visual brush to. To make sure the reflection is placed under the image, we will place both elements in a StackPanel. By default, a StackPanel stacks elements vertically. We will also set the border's background to “Red” so that we can test that things are rendering properly.

<StackPanel Margin="10">
    <Image Source="images/lighthouse.jpg" Width="400" Height="300" />
    <Border Width="400" Height="300" Background="Red" />
</StackPanel>

When compiled, you should see the following:

Image with red border

Before we can add the reflection we need to name our image so that we can reference it. For the sake of this example, we’ll name our image “myVisual”. We do this simply by adding x:Name=”myVisual” to the Image tag:

<StackPanel Margin="10">
    <Image Source="images/lighthouse.jpg" Width="400" Height="300" x:Name="myVisual"/>
    <Border Width="400" Height="300" Background="Red" />
</StackPanel>

Now it’s time to add the magic. To reflect the original image onto our border element, we will remove the red background and replace it with a VisualBrush referencing our image. We do this by “binding” our visual brush to the image using the namespace we created, “myVisual”. The syntax to support this binding is as follows:

<StackPanel Margin="10">
<Image Source="images/lighthouse.jpg" Width="400" Height="300" x:Name="myVisual"/>
<Border Width="150" Height="150">
    <Border.Background>
        <VisualBrush Visual="{Binding ElementName=myVisual}" />
    </Border.Background>
</Border>
</StackPanel>

We have now mirrored our image by “painting” it onto the border element. When compiled, you should see two images:

Image with visual brush

To make our example look more like it is being reflected, we will flip the visual brush vertically.

To flip the visual brush we will apply a ScaleTransform and set the Y-axis scaling to “-1”. To correctly position the visual brush we need to set the center of the brush to match the center of our image. Since our image is 400x300, our brush’s center coordinates will be 400 divided by 2, or 200, on the x-axis and 300 divided by 2, or 150, on the y-axis. This results in a relative center point (200,150).

<Border Width="400" Height="300">
<Border.Background>
<VisualBrush Visual="{Binding ElementName=myImage}">
    <VisualBrush.Transform>
        <ScaleTransform ScaleX="1" ScaleY="-1" CenterX="200" CenterY="150" />
    </VisualBrush.Transform>
</VisualBrush>
</Border.Background>
</Border>

Our mirrored image now looks more like a reflection:

Image with flipped visual brush

To finish the effect, we will set the border's Opacity and apply an OpacityMask so that the border element containing the visual brush fades into the background. For a final bit of polish, we will also add a border to our image and apply a linear gradient to the background of the main window. This complete, our final coded solution appears as follows:

<Window.Background>
    <LinearGradientBrush StartPoint="0,0.3" EndPoint="1,0">
        <LinearGradientBrush.GradientStops>
            <GradientStop Color="#C4CBD8" Offset="0" />
            <GradientStop Color="#E0E4F0" Offset="0.3" />
            <GradientStop Color="#E6EAF5" Offset="0.5" />
            <GradientStop Color="#CFD7E2" Offset="0.9" />
            <GradientStop Color="#C4CBD8" Offset="1" />
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
</Window.Background>
<Grid>
<StackPanel Margin="10">
<Border BorderBrush="White" BorderThickness="4" Width="408" Height="308">
    <Image Source="images/lighthouse.jpg" Width="400" Height="300" Name="myVisual" />
</Border>
<Border Width="408" Height="308" Opacity="0.2" BorderBrush="White" BorderThickness="4">
<Border.OpacityMask>
    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0" Color="Black"/>
            <GradientStop Offset=".6" Color="Transparent"/>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
</Border.OpacityMask>
<Border.Background>
    <VisualBrush Visual="{Binding ElementName=myVisual}">
        <VisualBrush.Transform>
            <ScaleTransform ScaleX="1" ScaleY="-1" CenterX="200" CenterY="150" />
        </VisualBrush.Transform>
    </VisualBrush>
</Border.Background>
</Border>
</StackPanel>
</Grid>

When compiled, we have our final image.

Final image reflection

관련글 더보기

댓글 영역