Absolute Positioning of WPF Controls
February 14th, 2007 | 2 Comments
In one of my earlier posts, I mentioned that it is tricky to absolutely position WPF controls on your stage. When I mention “absolutely position”, what I am referring to is the ability to directly specify the X and Y position of your control. When you are dynamically adding controls to your applications, you have to explicitly specify where you want the control to be positioned. In this post, I will explain the three ways I have found (so far) of positioning controls on the screen.
I. Controls not Nested in a Canvas
Let’s first look at how to position an object that is not nested inside a Canvas control:
- btnMain.HorizontalAlignment = HorizontalAlignment.Left;
- btnMain.VerticalAlignment = VerticalAlignment.Top;
- btnMain.Margin = new Thickness(10, 10, 0, 0);
- btnMain.VerticalAlignment = VerticalAlignment.Top;
As you can see, you have to adjust your control’s Margins to specify the exact location of your control. In order to do that, I first must specify the default Horizontal and Vertical alignment. By having my margin’s origin anchored at 0,0 (the top-left corner), I can easily set my Margin property by altering the first two (x and y) arguments of Thickness.
II. Controls Nested in a Canvas
The second scenario is when your control is actually nested inside a Canvas. When inside a canvas, you can use the simple, yet strange, syntax seen below:
- Canvas.SetLeft(btnMain, 10);
- Canvas.SetTop(btnMain, 10);
In the above code, the word Canvas is not referring to the name of my Canvas object. It is referring to the Canvas class itself, so all you do is directly access the Canvas class’s SetLeft and SetTop properties. If you attempt to use the above approach on a control that isn’t nested inside a Canvas, nothing will happen. You won’t receive a Compiler error or warning, but your control will also not be positioned where you want it to be.
III. Transforms
Finally, we get to the approach I used in my Display Squares example where I use the Transform properties to position my object:
- TransformGroup transformGroup = new TransformGroup();
- TranslateTransform buttonTransform = new TranslateTransform(10, 10);
- transformGroup.Children.Add(buttonTransform);
- btnMain.RenderTransform = transformGroup;
- TranslateTransform buttonTransform = new TranslateTransform(10, 10);
This approach clearly involves the most written code. Transforms are very interesting, but explaining them would deviate too much from what this post is about, so I’ll table that topic for later. The main thing to keep in mind with Transforms is that, unlike the earlier positiniong approaches, the initial location of your control matters.
For example, if your btnMain button is originally located at 100, 100, instead of being positioned at 10, 10 like you would want, your btnMain will actually be positioned at 110, 110. The transform approach is relative to the original position. This isn’t a problem if you are dynamically creating your controls where the origin is 0,0 by default. This is a problem is you are positioning a control that you already created in a program like Expression Blend where you are able to visually set an initial position.
WinForms and Flash
Before I wrap this post up, I’ll briefly explain how to WinForms and Flash handle absolute positioning. In WinForms, you can set the position of our btnMain button by using the following syntax:
- btnMain.Location = new Point(10, 10);
The Location property takes a Point object whose arguments can be the X and Y position you want to use. Even this may seem a bit complicated if you are familar with Flash. Flash provides a very simple and direct approach by allowing you to use the _x and _y property on any control with an instance name:
- btnMain._x = 10;
- btnMain._y = 10;
I hope this post helped you to understand how to absolutely position controls in your WPF applications. In many cases, you will never be in a situation where you have to manually specify the location of your controls. The layout managers you use such as StackPanel, DockPanel, etc. automatically take care of control placement for you.
Only in situations, such as those that I’ve written about in this blog, where you use code to dynamically create visual controls will these positioning tricks come in handy.
Cheers!
Kirupa





August 24th, 2007 at 5:26 am
thats fine but not sure how you ask a textblock or image where it is positioned relative to another grid.
August 24th, 2007 at 9:10 am
I found some more information but not resolved it yet
[code]
void tabItemClicked(object sender, RoutedEventArgs e)
{
//convert positions in list box to the listBoxes holder
// (TransformToDecendant is the other one you can use)
GeneralTransform gentran = sender.TransformToAncester(tabHolderGrid);
Point createPos = gentran.Transform( new Point( 0, 0) );
}
[/code]