#786 – Using Data Binding to Control a 2D Transform

It’s common to use data binding to control the values used for 2D transformations.  Below is a simple example that binds the AngleCenterX and CenterY properties of a RotateTransform to corresponding properties in a class.

    <StackPanel Margin="20,80">
        <Label Content="Dwight D. Eisenhower (1890-1969)" Background="Plum" Margin="10"
               HorizontalAlignment="Center" Padding="20,10" FontSize="16">
            <Label.LayoutTransform>
                <RotateTransform  Angle="{Binding IkeAngle}"
                                  CenterX="{Binding IkeCenterX}"
                                  CenterY="{Binding IkeCenterY}" />
            </Label.LayoutTransform>
        </Label>
    </StackPanel>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            // Test data
            IkeAngle = 25;
            IkeCenterX = 0.0;
            IkeCenterY = 0.0;
        }

        public double IkeAngle { get; set; }
        public double IkeCenterX { get; set; }
        public double IkeCenterY { get; set; }

        //-- INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

786-001

Advertisements

#781 – Transform Order Matters

When you combine several 2D transforms into a transform group, the order in which you list the constituent transforms matters.  The transforms are applied in the order that you list them in the TransformGroup.  The order that they are applied in makes a difference, because if you translate and then rotate an object, you get a different result than if you rotate the object first and then translate it.

In the example below, the labels start out on top of each other, but end up at different positions, because the order of their transforms is different.

    <Grid>
        <Label Content="Dr. Livingstone, I presume?"
               Style="{StaticResource styAfrica}">
            <Label.RenderTransform>
                <TransformGroup>
                    <TranslateTransform X="70" />
                    <RotateTransform Angle="60" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
        <Label Content="Dr. Livingstone, I presume?"
               Style="{StaticResource styAfrica}">
            <Label.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="60" />
                    <TranslateTransform X="70" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
    </Grid>

781-001

#780 – Combining Transforms

When you apply a 2D transform to an element, you use the RenderTransform or LayoutTransform properties to specify the  transform to apply.  You set the value of these properties to a single instance of the Transform type.

Often, the value of the Transform type will be a specific transform, like ScaleTransform.  However, you can combine multiple transforms by setting the property to an instance of a TransformGroup, which in turn contains a collection of Transform elements.

In the example below, we first apply a rotate transform to the middle label, followed by a translation transform.

    <StackPanel>
        <Label Content="We few, we happy few, we band of brothers"
               Style="{StaticResource styRoyal}"/>
        <Label Content="For he to-day that sheds his blood with me"
               Style="{StaticResource styRoyal}">
            <Label.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="20" />
                    <TranslateTransform X="50" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
        <Label Content="Shall be my brother; be he ne'er so vile"
               Style="{StaticResource styRoyal}"/>
    </StackPanel>

780-001

#778 – Animating a Scale Transform

Here’s another example of an animation of a 2D transform.  In this case, we animate the scale of the object so that it grows larger and smaller and then repeats the behavior.  This results in a sort of pulsating button.

    <Grid>
        <Button Content="Ship via Wells, Fargo &amp; Co." HorizontalAlignment="Center" VerticalAlignment="Center"
                Padding="20,10" FontSize="16"
                RenderTransformOrigin="0.5,0.5">
            <Button.RenderTransform>
                <ScaleTransform x:Name="scaleTransform" ScaleX="0.98" ScaleY="1.02"/>
            </Button.RenderTransform>
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                                             Storyboard.TargetProperty="ScaleX"
                                             From="0.98" To="1.02" Duration="0:0:0.3"
                                             AutoReverse="True" RepeatBehavior="Forever"/>
                            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                                             Storyboard.TargetProperty="ScaleY"
                                             From="0.98" To="1.02" Duration="0:0:0.3"
                                             AutoReverse="True" RepeatBehavior="Forever"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </Grid>

778-001

#776 – Setting the Center Point for Skew Transforms

Like rotation transforms, you can set the origin for a skew transform using either the RenderTransformOrigin property on the element, or the CenterX/CenterY properties on the SkewTransform element.

You can think of the center of a skew transform as the point that will be held in one place as the object is tilted.

Also note–setting the X value of the center point only affects skews specified using AngleY and setting the Y value only affects skews specified using AngleX.

In the example below, we use RenderTransformOrigin to move the Y component of the center point, which impacts how the AngleX skew is done.

776-001

 

You can better see how this works by looking at how the Visual Studio designer shows you the skew.  It also shows the pre-transformed element, so you can see which point is being used as the origin.

776-002

 

776-003

#774 – Translate Transforms

You can use a translation transform to translate, or move, a user interface element in the X or Y dimensions.  You specify translation values separately in both X and Y dimensions, expressed in device independent units.

You specify translation using a TranslateTransform element, setting values for the X and Y properties.  Both properties default to a value of 0.

LayoutTransform will ignore translation transforms (since the element will be moved around during the layout process anyway).  So you only use translation transforms with a RenderTransform.

Here’s an example that uses a couple of Sliders to dynamically change the X and Y values of a TranslateTransform.

    <StackPanel Orientation="Vertical">
        <TextBlock Text="Jack Kerouac" FontWeight="Bold" HorizontalAlignment="Center"
                   Padding="10,5" Background="PaleGoldenrod" Margin="5">
            <TextBlock.RenderTransform>
                <TranslateTransform  X="{Binding ElementName=sliX, Path=Value}" Y="{Binding ElementName=sliY, Path=Value}"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <TextBlock Text="Born 12 Mar, 1922" HorizontalAlignment="Center"
                   Padding="10,5" Background="Thistle"/>

        <Slider Name="sliX" Minimum="0" Maximum="300" Margin="10"/>
        <Slider Name="sliY" Minimum="0" Maximum="300" Margin="10"/>
    </StackPanel>

774-001
774-002
774-003

#770 – The Difference Between a LayoutTransform and a RenderTransform

When you are transforming user interface elements using a 2D transform, you can choose one of two types of transforms.

  • LayoutTransform transforms elements before they are layed out by the parent panel
  • A RenderTransform transforms element after they are layed out by the parent panel (but before they are rendered)

Which one you use depends on whether you want transform and then lay out (use LayoutTransform) or to lay out and then transform (use RenderTransform).  (Note: You could also use both types).

    <StackPanel Orientation="Horizontal">
        <StackPanel Orientation="Vertical">
            <Label Content="LayoutTransform"/>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}"/>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}">
                <Button.LayoutTransform>
                    <RotateTransform Angle="20"/>
                </Button.LayoutTransform>
            </Button>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}">
                <Button.LayoutTransform>
                    <RotateTransform Angle="-20"/>
                </Button.LayoutTransform>
            </Button>
        </StackPanel>
        <StackPanel Orientation="Vertical">
            <Label Content="RenderTransform"/>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}"/>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}">
                <Button.RenderTransform>
                    <RotateTransform Angle="20"/>
                </Button.RenderTransform>
            </Button>
            <Button Content="Push Me" Style="{StaticResource buttonStyle}">
                <Button.RenderTransform>
                    <RotateTransform Angle="-20"/>
                </Button.RenderTransform>
            </Button>
        </StackPanel>
    </StackPanel>

770-001