Thursday, October 15, 2009

Silverlight 3 XamlWriter - v0.3 - Storyboard and TransformGroup support

An update every day - Wow! Thought I'd keep the momentum going while I have a liiittle free time. Once it goes on the back-burner, it will lie there to bite the dust!

If anyone has tried the XamlWriter (which I am sure no one has, yet!) it would be clear that it doesn't work for Storyboards and TransformGroups. That is because they are a slightly special case. Why? I'll leave that for some future post. Anyways it's fixed now.

Please check out my previous post for download and usage information.

I also thought I'd take this opportunity to point out some issue that I encountered. If you had read my previous posts on this subject you would know that I used reflection to implement the XamlWriter.

The way to retrieve the properties of an object using reflection is like this -
  PropertyInfo[] props = target.GetType().GetProperties();

I now needed to to check if the property is readonly. The reason for this is that a readonly property cannot be used in Xaml. So I went ahead and used the CanWrite property to check if the property could be written to, like this -
  if (!prop.CanWrite)

But, guess what? It doesn't work in all cases. For example, the IsFocussed property of a Button control returns true for CanWrite. I put the IsFocussed property in the Xaml and it threw an error indicating clearly that this was a read only property.

So there had to be a different way. After all the Xaml parser knows more about readonly properties than the CanWrite property. That is when I discovered the GetSetMethod method on ProperyInfo. This worked wonderfully -
  if (prop.GetSetMethod == null)

Whether this is a bug or some explainable feature, I don't know. Maybe I will post this on the Silverlight.net forums and see if there is an explanation. In the meantime, there is a workaround for me to continue making progress!

The Storyboard and TransformGroup example



Assuming an Xaml like this

<UserControl x:Class="test2.MainPage" x:Name="MyControl"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="850" Height="447">
    <Canvas>
        <Canvas.Triggers>
            <EventTrigger RoutedEvent="Canvas.Loaded">
                <EventTrigger.Actions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation To="300" Duration="0:0:1" 
                                             Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Left)" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger.Actions>
            </EventTrigger>
        </Canvas.Triggers>
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="1.05" ScaleY="1"/>
                <SkewTransform AngleX="0" AngleY="0"/>
                <RotateTransform Angle="0"/>
                <TranslateTransform X="1" Y="0"/>
            </TransformGroup>
        </Canvas.RenderTransform>
        <Ellipse x:Name="ellipse" Height="20" Width="20" Canvas.Left="30" Canvas.Top="30" Fill="black"/>
        <Button x:Name="zz" Width="100" Height="100" Click="Button_Click"/>
    </Canvas>
</UserControl>


WriteXaml(MyControl, XamlWriterSettings.LogicalTree) will generate this Xaml


<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="MyControl">
  <Canvas>
    <Ellipse Width="20" Height="20" x:Name="ellipse" Canvas.Left="300" Canvas.Top="30" Fill="#FF000000" />
    <Button Width="100" Height="100" x:Name="zz" />
    <Canvas.Triggers>
      <EventTrigger RoutedEvent="FrameworkElement.Loaded">
        <EventTrigger.Actions>
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation To="300" Duration="00:00:01" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Left)" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger.Actions>
      </EventTrigger>
    </Canvas.Triggers>
    <Canvas.RenderTransform>
      <TransformGroup>
        <ScaleTransform ScaleX="1.04999995231628" />
        <SkewTransform />
        <RotateTransform />
        <TranslateTransform X="1" />
      </TransformGroup>
    </Canvas.RenderTransform>
  </Canvas>
</UserControl>

No comments: