Reflecting on XAML..

Wow, its been quite a bit since my last post – but I’ve got a good excuse. I’ve been busy soaking up all I can on the Holy trio of WPF/WCF/WWF. There’s just so much to absorb, and I’m already 3+ years behind! (WPF has been around since 2003/4)

Anyway. I’m here now!

Ok, the reflection stuff is getting a bit overdone, and I’ve seen another example of an animating cog,  so not wanting to feel left out i thought I’d add my own reflection example with a minor twist.

Here’s the code :

<Window x:Class=”WindowsApplication1.Window1″
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
    Title=”BalmyWin” Height=”480″ Width=”600″>
       
<Window.Background>
               
<LinearGradientBrush EndPoint=”0.5,1″ StartPoint=”0.5,0″>
      <GradientStop Color=”#FF0000FF” Offset=”1″/>
      <GradientStop Color=”#FF0000DF” Offset=”0.63″/>
      <GradientStop Color=”#FF000082″ Offset=”0.543″/>
      <GradientStop Color=”#FF000000″ Offset=”0″/>
    </LinearGradientBrush>
       
</Window.Background>
    <StackPanel>
      <Grid HorizontalAlignment=”Center” VerticalAlignment=”Center” Margin=”0,80,0,0″ Background=”#FF0000AF”>
        <MediaElement x:Name=”balmy” Source=”ballmerwindows.wmv” Width=”320″ Height=”240″  Margin=”5,5,5,5″ TextElement.Foreground=”#FFFFFFFF”/>

      </Grid>
      <Rectangle Width=”320″ Height=”240″ Margin=”5,0,5,5″ >
        <Rectangle.Fill>
          <VisualBrush Visual=”{Binding ElementName=balmy}”/>
        </Rectangle.Fill>
        <Rectangle.RenderTransform>
          <TransformGroup>
            <ScaleTransform ScaleY=”-0.25″/>
            <TranslateTransform Y=”60″ />
            <SkewTransform AngleX=”70″ />
          </TransformGroup>
        </Rectangle.RenderTransform>
        <Rectangle.OpacityMask>
                <LinearGradientBrush EndPoint=”0.515,1.15″ StartPoint=”0.487,0.017″>
                        <GradientStop Color=”#0E000000″ Offset=”0.135″/>
                        <GradientStop Color=”#FFFFFFFF” Offset=”1″/>
                </LinearGradientBrush>
        </Rectangle.OpacityMask>
      </Rectangle>
    </StackPanel>
</Window>

and here’s the result.

Balmy windows

To try this out, cut and paste it into XAMLPadX or other XAML editor that allows a window as the root element.

Although in the original example on the WPF/E blog, an image is used for both the graphic and its reflection, and animation rotates both. Thats ok when you have a static image, what if you want to reflect a video? Loading up the video twice is a bit of a resource hog, and then there’s the risk they’ll get out of sync for some reason, plus even a few millisecond delay will give some really odd audio phasing artifacts.

Enter the <VisualBrush> element. This allows you to ‘capture’ the content of a visual tree of pretty much any element in your Xaml. Because the content of a <MediaElement> is a dependency property, anytime the video codec renders a new frame of video data, the visual brush also gets a copy of the surface data.

In addition to a simple inversion, which could be done with a <RelativeTransform> and a Y of -1, i wanted to add a skew transform the the rendered output. i think this gives more realistic cast reflection than a simple reflection about the X axis when you really notice the lack of a true perspective transform.

Anyway, there are two types of transforms you can add to a visual element, layout transforms , and render transforms. A layout transform performs the transformation before the layout engine positions all the controls, so if we were doing a rotation, as the horizontal size of the control increased, the other controls would get pushed around on screen which wouldn’t be too pretty. To avoid that, we use a render transform, which performs the transformation as the last stage of the rendering pipeline, so it doesn’t affect the positions of any of the other controls on screen.

So, we make a RenderTransform that consist of a Translation, a Skew, and a Scale. When we flip the brush, we also need to translate back into a position underneath the video, and we apply a scale to make it look slightly more realistic.

As a final touch we apply a linear gradient over the transformed visualbrush that affects only the reflections opacity mask . This causes the alpha on the visual brushes pixels to decrease the further away we get from the base of the reflection.

Thats about it! There’s no code required, everything is in the one XAML file. The media element can present pretty much any type that has a registered codec, and it will even do animated gifs (although there’s a bug in WPF which doesn’t clear the background of gifs with transparency)

The example also uses the video attached to this blog entry, save it in the same location as the XAML file or you’ll end up with an empty window!

so, happy XAML’ing!

File Attachment: ballmerwindows.wmv (830 KB)

This entry was posted in General. Bookmark the permalink.

Leave a Reply