Silverlight - Live Reflections for WPF programmers

|

One of the demos I like to give when showing XAML in WPF is the "Live Reflection"; this is where you have a video playing and you show a reflection of the video using a VisualBrush and LinearGradientBrush for the opacity. In WPF the XAML for this would be:

<Window x:Class="LiveReflection.Window2"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="LiveReflection" Height="400" Width="400"
    >
  <StackPanel x:Name="LayoutRoot" Margin="0,4,0,0">
    <MediaElement Width="328" Height="248" Source="Bear.wmv" x:Name="_movie" />
    <Rectangle Width="328" Height="248" RenderTransformOrigin="0.5,0.5">
      <Rectangle.Fill>
        <VisualBrush Visual="{Binding ElementName=_movie}" />
      </Rectangle.Fill>
      <Rectangle.OpacityMask>
       <LinearGradientBrush EndPoint="0.5,0.25" StartPoint="0.5,1.161">
          <GradientStop Color="#64000000" Offset="0"/>
          <GradientStop Color="#00FFFFFF" Offset="1"/>
        </LinearGradientBrush>
      </Rectangle.OpacityMask>
      <Rectangle.RenderTransform>
        <RotateTransform Angle="-180"/>
      </Rectangle.RenderTransform>
    </Rectangle>
  </StackPanel>
</Window>

Once compiled this produces an output similar to the following:

 WPFLiveReflection

Naturally, when I first started looking at Silverlight the first thing I wanted to try was reproduce my "Live Reflection" sample. The first stumbling block was that there is no such thing as a VisualBrush in Silverlight.

Did this mean that failed at the first hurdle? Well, no. It is true to say that there is not an equivalent brush to the VisualBrush in Silverlight; there is nothing that will render any part of the visual tree as a brush. However, there is a brush that will render any part of a MediaElement, and this brush also supports transforms. This brush is unique to Silverlight and it is called a VideoBrush.

Next I wrote this XAML in Silverlight:

<Canvas
  xmlns="
http://schemas.microsoft.com/client/2007"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="346" Height="516">
  <MediaElement Width="328" Height="248" Canvas.Left="8" Canvas.Top="8"
                x:Name="video" Source="Bear.wmv" Stretch="Fill" />

  <Rectangle Width="328" Height="248" Canvas.Left="8" Canvas.Top="506">
    <Rectangle.Fill>
      <VideoBrush SourceName="video" />
    </Rectangle.Fill>
    <Rectangle.RenderTransform>
      <ScaleTransform ScaleX="1" ScaleY="-1"/>
    </Rectangle.RenderTransform>
    <Rectangle.OpacityMask>
      <LinearGradientBrush EndPoint="0.5,0.605" StartPoint="0.5,0.94">
        <GradientStop Color="#64000000" Offset="0"/>
        <GradientStop Color="#00FFFFFF" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.OpacityMask>
  </Rectangle>
</Canvas>

Once hosted in a browser produces an output similar to the following:

Mission accomplished.

There is a moral to this post; which is that this encounter is not uncommon with many aspects of WPF vs. Silverlight. While there is not always a 1:1 match in Silverlight there usually is a way (with the exception of 3D and Binding, concepts not supported by Silverlight 1.0, 1.1 or v.next from what I can tell, in any way what-so-ever). I have been working closely with Silverlight 1.0, day in day out, for a little over a month now and I am really impressed.

Initially, when my day job involved writing production as opposed to now where I write about writing production code, I dismissed Silverlight 1.0. I really did not fancy writing reams of JavaScript and messing around with a very small subset of a technology that I loved the from moment it was released (WPF if you had not already guessed) - especially with 1.1, meaning C# on the client-side, no JavaScript :-0, hot on it's heals. But over the last few weeks I have come to appreciate what Silverlight 1.0 is and is capable of. While your RIA might be far from easy to write, there is a way. You just have to want to do it.


Finally, an apology: to my friends. Yes, this is yet another Live Reflection example that you've had to endure - for that I'm sorry (JP: I am truly, truly sorry to you; you've had to put up with this, and much more from me, more than most - thank you my friend).

2 comments:

John Powell said...

Again another excellent example, keep them coming! Using this type of brush technology can you "copy paint" text, images and video onto different parts of the screen?

Paul said...

Unfortunately that better describes the VisualBrush, which is only available in WPF. The VideoBrush can only paint video; more specifically it can only paint video playback from a MediaElement - the SourceName property of the VideoBrush must point to the x:Name of a MediaElement within your Silverlight applications.

It is still a very powerful and useful brush however, you can use it to produce all kinds of interesting video effects, such as a video fill for some text or, as I have used more recently, as the full screen representation of a custom video player.

Thanks for your feedback and I hope this clears up the misunderstanding.

-PJ