Click here to Skip to main content
Click here to Skip to main content

WPF Tutorial - Part 1 : Transformations

, , 28 Jun 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
A brief introduction to using transformations with the WPF

Notes for building/running the sample project

  1. You need to have Visual Studio 2005 as well as the Orcas tools for VS 2005. Alternatively you can also use Expression to run the sample.
  2. You need the June CTP version of the .NET 3.0 Runtime as well the SDK.
  3. You need to change the path to the image in the XAML to point to a valid image file.
  4. If you have an earlier or later CTP, most of the code should still compile the same - though you may have to make some namespace changes.

Introduction

Welcome to this, our first joint article on WPF, which is part of WinFX ( now called .NET 3.0, for reasons that are totally unclear to anyone with half a brain ). In this article we will cover transformations, both in XAML and in code. While this is a logical 'starting' topic, even here WPF shows its power over traditional windows programming, as these transformations can be applied to any element in your UI, creating effects that would have been close to impossible in traditional forms programming. The first part of the article will run you thgrough some transforms in XAML, and the second part will demonstrate a sample app that shows an image and allows you to set transform values with sliders, with the idea that being able to interact in this way will give you a stronger idea of what the transforms can do, both together and individually.

Rotation Transforms

The RotateTransform class is used to rotate a WPF object in an X-Y plane. It can be applied via XAML or directly via imperative code. For our examples, we'll use a WPF ListBox control and we'll apply a Rotation Transform to it. Here's what the ListBox would look like when a Rotation Transform of -20 degrees (20 degrees anti-clockwise) is applied to it.

Compare the ListBox on the left which is rotated, with the one on the right (identical except that it's not rotated). And here's the XAML that achieves this.

<ListBox Name="listBox1" FontSize="15" 
   Canvas.Bottom="140" Canvas.Left="30" 
    Canvas.Right="150" Canvas.Top="40">         
    <ListBoxItem IsSelected="True">Canada</ListBoxItem>
    . . .
    <ListBoxItem>Spain</ListBoxItem>    

    <ListBox.RenderTransform> *(1)*
            <RotateTransform Angle="-20" 
              CenterX="50" CenterY="50" /> *(2)*
    </ListBox.RenderTransform>
</ListBox>
  • (1) - We specify a RenderTransform on the object, which modifies how the object is rendered by the UI system. (This is in contrast to the LayoutTransform which doesn't affect rendering, but affects how the object is processed by the layout system)
  • (2) - We use a RotateTransform which lets us specify the angle of rotation in clock wise degrees. We can also optionally specify the X,Y point about which the object is rotated. Setting X and Y points equal to Width/2 and Height/2 will cause an object to 'spin' as opposed to rotate around an imaginary curve.

Later, we'll write a more flexible demo that demonstrates various transforms and how various properties can be applied to each of those transforms. Next let's look at a Scale Transform.

Scale Transforms

In the above screenshot, you can see a Scale Transform that has stretched the ListBox on the left by 1.5 times in the X axis, and compressed it by 0.75 times in the Y axis. Here's the XAML that achieves this.

<ListBox.RenderTransform>
    <ScaleTransform ScaleX="1.5" ScaleY="0.75"/>
</ListBox.RenderTransform>

We just replaced the Rotation Transform with a Scale Transform. Note that it's possible to apply multiple transforms on a single object, and we'll see that later. But before that, let's take a look at using the SkewTransform class.

Skew Transforms

Skew Transforms skew an object by specified X and Y angles, and can be used to create some fancy transformation effects (and are also used for animations). The following screenshot shows a skew transformation of 20 degrees in the X axis and 30 degrees in the Y axis.

Here's the XAML code that achieves the above transformation.

<ListBox.RenderTransform>
    <SkewTransform AngleX="20" AngleY="30"/>
</ListBox.RenderTransform>

Thus far we've only looked at single transformations on an object, next we'll look at how to achieve multiple transformations on an object.

Applying multiple transformations on an object

In the below example, we are going to apply two transforms on an object :

  1. A ScaleTransform to mirror-invert the ListBox
  2. A TranslateTransform to move the object back to the visible window

Here's what the final effect looks like.

And here's the code that achieves the above effect.

<ListBox.RenderTransform>
    <TransformGroup>
        <ScaleTransform ScaleX="-1" ScaleY="1" />
        <TranslateTransform X="100" />
    </TransformGroup>
</ListBox.RenderTransform>

Notice the use of the TransformGroup object that allows us to group multiple transforms and then apply them on a single object. Here's another example of multiple transforms on the list box, which tries to achieve a 3d effect.

The XAML for the above effect is shown below.

<ListBox.RenderTransform>
    <TransformGroup>
        <RotateTransform Angle="15" CenterY="30" />
        <SkewTransform AngleY="-45" />
    </TransformGroup>
</ListBox.RenderTransform>

A sample app to play around with transformations

Ok, now that we know how to do transforms, let's write a little app that we can use to interact with them, and see how they work. The sample app has an image in it, and here's how it is defined using XAML. You will need to modify the ImageSource property of the ImageBrush element to point to an image on your local hard disk. In the zip download, we have included the JPG image that we used, so you could use that if you want to.

<Rectangle Stroke="#FF000000" HorizontalAlignment="Stretch" 
    VerticalAlignment="Stretch"
    Margin="198,80,260,230" Width="Auto" Height="Auto" x:Name="rect"> 
	<Rectangle.Fill>
    		<ImageBrush ImageSource="d:\toofast.jpg" /> 
	</Rectangle.Fill> 
</Rectangle>

You probably realize that we can define our transforms inside the XAML, but we're trying to show some operations within the code. So, we define the transforms like this:

        private TransformGroup trGrp;
        private SkewTransform trSkw;
        private RotateTransform trRot;
        private TranslateTransform trTns;
        private ScaleTransform trScl;

	public Scene1()
	{
	   this.InitializeComponent();

            trSkw = new SkewTransform(0, 0);
            trRot = new RotateTransform(0);
            trTns = new TranslateTransform(0, 0);
            trScl = new ScaleTransform(1, 1);

            trGrp = new TransformGroup();
            trGrp.Children.Add(trSkw);
            trGrp.Children.Add(trRot);
            trGrp.Children.Add(trTns);
            trGrp.Children.Add(trScl);
        }

This code creates the four possible transform objects and adds them to a TransformGroup. This group is now a member variable, it's initialized, but it's not associated with our object. To do this, we need to add the following to the opening tag for our XAML document :

Loaded="OnSceneLoaded"

This has the effect of defining a method that will be called when the scene loads, and that method is defined as follows:

private void OnSceneLoaded(object sender, System.Windows.RoutedEventArgs e) 
{ 
    rect.RenderTransform = trGrp; 
    slSclX.Value = slSclY.Value = 1; 
}

As you can see, this method assigns the transform group to the rectangle object, and sets initial slider values to the scaling sliders. The rest of the program logic is pretty simple : we just define a single method which sets all the transform values based on the various sliders, and hook all the value changed events on the sliders to the one method. An example XAML snippet goes like this:

<Slider LargeChange="0.1" Maximum="50" Minimum="-50" SmallChange="0.1" 
   Name="slSkwX" ValueChanged="OnValueChanged" />

Some attributes have been removed to make the example clearer. Now we just need that central method:

protected void OnValueChanged(object sender,
                         System.Windows.RoutedEventArgs e)
{
    trRot.Angle = slRot.Value;
    trRot.CenterX = slRotX.Value;
    trRot.CenterY = slRotY.Value;
    trScl.ScaleX = slSclX.Value;
    trScl.ScaleY = slSclY.Value;
    trScl.CenterX = slSclOX.Value;
    trScl.CenterY = slSclOY.Value;

    trSkw.AngleX = slSkwX.Value;
    trSkw.AngleY = slSkwY.Value;
    trSkw.CenterX = slSkwOX.Value;
    trSkw.CenterY = slSkwOY.Value;

    trTns.X = slTrnX.Value;
    trTns.Y = slTrnY.Value;
}

Now all our transform values will be set whenever you move any slider. This is arguably inefficient, but it does simplify the code for this example.

Conclusion

As was stated in the introduction, the real power of WPF becomes apparent pretty quickly, even this simple example shows off things that under 'traditional' development would be a lot of work. However, we've really only just begun, our next article on animation will really start to show what's possible with this new framework.

History

  • Jul 21, 2006 - Article first published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Authors

Christian Graus
Software Developer (Senior)
Australia Australia
Programming computers ( self taught ) since about 1984 when I bought my first Apple ][. Was working on a GUI library to interface Win32 to Python, and writing graphics filters in my spare time, and then building n-tiered apps using asp, atl and asp.net in my job at Dytech. After 4 years there, I've started working from home, at first for Code Project and now for a vet telemedicine company. I owned part of a company that sells client education software in the vet market, but we sold that and I worked for the owners for five years before leaving to get away from the travel, and spend more time with my family. I now work for a company here in Hobart, doing all sorts of Microsoft based stuff in C++ and C#, with a lot of T-SQL in the mix.

Nish Sivakumar

United States United States
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Comments and Discussions

 
GeneralMy vote of 2 Pinmembersmton20-Aug-13 13:54 
GeneralRe: My vote of 2 PinmvpChristian Graus20-Aug-13 13:55 
GeneralRe: My vote of 2 PinsitebuilderNish Sivakumar21-Aug-13 5:18 
GeneralMy vote of 5 PinmemberChristian Amado20-Aug-12 11:02 
QuestionWhy the line is not smooth after rotation? PinmemberNaresh Goradara22-Apr-12 20:42 
AnswerRe: Why the line is not smooth after rotation? PinmvpChristian Graus22-Apr-12 20:44 
GeneralRe: Why the line is not smooth after rotation? PinmemberNaresh Goradara22-Apr-12 20:52 
GeneralRe: Why the line is not smooth after rotation? PinmemberNaresh Goradara23-Apr-12 1:25 
GeneralMy vote of 5 PinmemberRaj Pratap16-Jun-11 9:45 
GeneralProblems in Opening project PinmemberSarath.4-Aug-06 3:02 
GeneralRe: Problems in Opening project PinstaffChristian Graus4-Aug-06 4:20 
GeneralRe: Problems in Opening project Pinmemberdakeefer28-Jun-10 8:37 
AnswerRe: Problems in Opening project PinmvpNishant Sivakumar28-Jun-10 8:45 
GeneralA mind-bending use of transforms PinmemberJosh Smith30-Jul-06 15:22 
GeneralSuggestion for next article [modified] PinprotectorMarc Clifton22-Jul-06 2:31 
GeneralRe: Suggestion for next article PinstaffChristian Graus22-Jul-06 2:44 
GeneralRe: Suggestion for next article PinprotectorMarc Clifton22-Jul-06 7:31 
GeneralRe: Suggestion for next article PinstaffChristian Graus22-Jul-06 13:17 
GeneralRe: Suggestion for next article PinmemberRama Krishna Vavilala22-Jul-06 7:32 
GeneralRe: Suggestion for next article PinstaffChristian Graus22-Jul-06 13:19 
QuestionWhy would you transform a ListBox? PinprotectorMarc Clifton21-Jul-06 14:06 
AnswerRe: Why would you transform a ListBox? PinstaffChristian Graus21-Jul-06 14:26 
GeneralRe: Why would you transform a ListBox? PinmemberJamie Nordmeyer21-Jul-06 20:52 
GeneralRe: Why would you transform a ListBox? PinstaffChristian Graus22-Jul-06 0:36 
GeneralVery nice PinmemberPaulC197221-Jul-06 12:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 28 Jun 2010
Article Copyright 2006 by Christian Graus, Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid