Click here to Skip to main content
6,293,171 members and growing! (11,991 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Windows Presentation Foundation » General     Beginner

WPF Tutorial - Part 1 : Transformations

By Christian Graus, Nishant Sivakumar

A brief introduction to using transformations with the WPF
C#, .NET, WinXP, Vista, Visual Studio, XAML, WPF, Dev
Posted:21 Jul 2006
Views:77,029
Bookmarked:65 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
36 votes for this article.
Popularity: 6.57 Rating: 4.22 out of 5

1
1 vote, 2.8%
2
5 votes, 13.9%
3
5 votes, 13.9%
4
25 votes, 69.4%
5

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Authors

Christian Graus


Member
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 now I work for the new owners.
Occupation: Software Developer (Senior)
Location: Australia Australia

Nishant Sivakumar


Member
Nish is a real nice guy living in Atlanta, who has been coding since 1990, when he was 13 years old. Originally from sunny Trivandrum in India, he recently moved to Atlanta from Toronto and is a little sad that he won't be able to play in snow anymore.

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.
Location: United States United States

Other popular Windows Presentation Foundation articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 14 of 14 (Total in Forum: 14) (Refresh)FirstPrevNext
GeneralProblems in Opening project PinmemberSarath.3:02 4 Aug '06  
GeneralRe: Problems in Opening project PinstaffChristian Graus4:20 4 Aug '06  
GeneralA mind-bending use of transforms PinmemberJosh Smith15:22 30 Jul '06  
GeneralSuggestion for next article [modified] PinsupporterMarc Clifton2:31 22 Jul '06  
GeneralRe: Suggestion for next article PinstaffChristian Graus2:44 22 Jul '06  
GeneralRe: Suggestion for next article PinsupporterMarc Clifton7:31 22 Jul '06  
GeneralRe: Suggestion for next article PinstaffChristian Graus13:17 22 Jul '06  
GeneralRe: Suggestion for next article PinmemberRama Krishna Vavilala7:32 22 Jul '06  
GeneralRe: Suggestion for next article PinstaffChristian Graus13:19 22 Jul '06  
GeneralWhy would you transform a ListBox? PinsupporterMarc Clifton14:06 21 Jul '06  
GeneralRe: Why would you transform a ListBox? PinstaffChristian Graus14:26 21 Jul '06  
GeneralRe: Why would you transform a ListBox? PinmemberJamie Nordmeyer20:52 21 Jul '06  
GeneralRe: Why would you transform a ListBox? PinstaffChristian Graus0:36 22 Jul '06  
GeneralVery nice PinmemberPaulC197212:05 21 Jul '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Jul 2006
Editor: Chris Maunder
Copyright 2006 by Christian Graus, Nishant Sivakumar
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project