Differences between Canvas Property and Margin - c#

There are any differences between using SetValue with (for example) Canvas.LeftProperty and Margin Property?
To be more clear:
<Canvas>
<Rectangle x:Name="rect">
</Canvas>
Is
rect.SetValue(Canvas.LeftProperty, 10)
equivalent to
rect.Margin = new Thickness(10, 0, 0, 0)
or not?

The Margin property is used with every element to determine extra space around the object. It works in almost all types of layouting (StackPanel, Grid, ContentControls, etc.)
The Canvas.LeftProperty (as well as Top, Right, and Bottom) only apply to elements which are directly inside a Canvas. The Canvas will use these values to determine where an object should be. With Shape elements like a Path, the Canvas also looks at the location data of the Shape when determining the position.
Technically, the Canvas attached properties should accumulate with the inherent location data of a Shape (if any) as well as the Margin. You could use all 3 to modify the position. But usually you would try to keep it simple.
For example, a Rectangle should use its Width and Height properties as well as Canvas.Left and Canvas.Top. A Path would either just rely on its point data or it would offset it with Canvas.Left and Canvas.Top. You shouldn't use margin for elements inside a Canvas since you have better control without using it, but you technically could.

For an element directly in a Canvas, the only difference is in the means. The end result is exactly the same.
When the Rectangle is positioned, the layout engine will add together all the values that affect its position. For the X coordinate this includes Canvas.Left and Margin.Left.
So in one case it is adding 10 + 0, and in the other it is adding 0 + 10.
So go with whichever you prefer. Personally I prefer Canvas.Left in this situation as it seems to make more contextual sense.

It looks same but in first case canvas moves you rect right in 10 point. In second rect moves right in 10 point.
Use one of this way according to your purposes.
EDIT: If look more deeply in WPF code. In first case rect is moved in ArrangeOverride of Canvas in second case in ArrangeOverride of Rectangle.

Canvas.Left
Canvas.Right
Canvas.Top
Canvas.Bottom
are enforced only inside the canvas container, they will not alter the width and height of your the control they're being attached to. (left=10, right=10 will not stretch to give a margin of 10 on each side)
Margin.Left
Margin.Right
Margin.Top
Margin.Bottom
Is controlled by the object that it's been set on, it will work outside of a Canvas on a grid for example and will alter the width and height of any control to enforce it's value (IF the width and height are NaN).

You can use the Margin property inside your template of the object using a TemplateBinding or regular Binding as it is a DependencyProperty. This also adjusts the width and height of the object.
The Canvas properties are attached properties to the FrameworkElement and allow positioning of elements that might not have a Margin property. And they do not work if the object does not have a Canvas parent.

Related

Moving a TabControl

I need to move a TabControl dynamically in code. How do I do it?
I tried setting the margin, wrapping it in a scatterviewitem (using Center, but it always returns 0,0 ), wrapping it in a canvas (in hope of using .Left and .Top) but they all didn't work. Can someone point me in the right direction?
Moving a control in WPF visually is based on the panel you used. For example, you have to adjust rows and columns if you use Grid and Top, Left properties if you used Canvas.
But a good approach is to use transformations. Use TranslateTransform to move your elements. Since transformation will not affect the layout pass.
<TabControl >
<TabControl.RenderTransform>
<TranslateTransform x:Name="translation"/>
</TabControl.RenderTransform>
</TabControl>
Adjust X and Y values in code,
translation.X = 200;

Dynamically creating textbox and setting its location by pixel

In a WPF application, I'd like to create a textbox dynamically which will show in front of the application and be able to freely set its location by pixel. (The textbox is going to follow the mouse cursor).
This was easily done in Winforms on the fly but WPF makes things.. a little bit weird when it comes to setting a control's location by pixel since I have to add the control as a child of a container. I'm aware this is certainly doable on Canvas, but what I actually have is a dockpanel with a richtextbox to the left and a datagrid to the right.
So what are my options here? Do I have to use canvas? Can I get away with using dockpanel (or grid) to implement what I want here?
You can use a Canvas or a Grid. If you use a Canvas, set the Canvas.Left property and the Canvas.Top property. If you use a Grid, you'll need to set a size for your TextBox, set the HorizontalAlignment to Left, and VerticalAlignment to Top. To change the location of the TextBox, assign it values for MarginLeft and MarginTop.

Estimate position and Width/Height of rendered UserControl

I have a UserControl (boxes) that can have varying size based on the number of items in its ItemsControl.
Many such usercontrols are added to a Canvas programmatically.
I need to draw arrows interconnecting these usercontrols. What is the best way to get the origin coordinates of the control w.r.t the Canvas and the rendered Width/Height so that I can figure out the arrow start and endpoints.
Canvas provides the coordinates of each control via Canvas.Left and Canvas.Top attached properties - which you know if you positioned them yourself anyway. So the (slightly) harder part is getting the other coordinate, and for that you want to know the rendered height/width. ActualHeight and ActualWidth give you this, assuming the control has already been laid out:
double top = Canvas.GetTop(control)
double bottom = top + control.ActualHeight
double left = Canvas.GetLeft(control)
double right = left + control.ActualWidth
If you're doing this before the controls have had a chance to be rendered on the screen, you can first do control.UpdateLayout() (or control.Measure()) to ensure the layout system measures their size.

WPF: How to find space available for Canvas?

I'm using WPF shapes to create Hexagons (for a game map) on a Canvas. After some playing around with ScrollViewer, I've decided to implement the scrolling and zoom of the map myself rather than using WPF functionality, just using WPF to get the events for mouse wheel, arrow keys etc. I'm placing the (Hex Map) Canvas as the last child inside a Dock Panel so it will get all the available remaining space. The Dock Panel will be set to be the content of the Main Window. But I want to find out how big the Canvas can be before I put any Children on the Canvas so that I can centre the screen over the Hex I want and only add the Shapes (Hexs) that can actually be seen. When zoomed out, a long way I will remove Polygons altogether and use another method of rendering and when zoomed in a long way I will add more details.
Is there any neat way of getting the available space? The only way that I can think of that will hopefully work is to get the current dimensions of the windows and subtract the dimensions of the outer elements of the Dock Panel, but that feels rather messy.
You may use the ActualWidth and ActualHeight properties of Canvas to determine size available to it. Be sure that HorizontalAlignment and VerticalAlignment are set to Stretch.

How to resize a Canvas in WPF?

I'm writing a WPF app that has a Canvas in it. This canvas will be custom rendered at runtime. It's sort of like a game in that it needs to be measured in pixels. I need to be able to set my Canvas to 478x478 pixels (client rectangle size). I don't want any scaling or other resolution-independent steps to take place on my Canvas.
I'm not sure if this is possible in WPF, since its nature is to be resolution independent. My questions:
How do I resize my Canvas at runtime (function to call?)
When I resize my Canvas, is the renderable area (the client rectangle) going to be that size? If not, how can I resize it to make sure the client rectangle is a specific width/height?
Is it possible to set the width/height of the Canvas in Pixels? How does the resolution-independent aspect of WPF interfere with what I'm trying to do?
When I resize my Canvas, will other controls resize appropriately as they have been designed to do in the WPF designer?
Thanks in advance.
Any elements positioned in a canvas will not resize or reposition based upon the size of the canvas. So I don't think there's any advantage to setting the size of the canvas. Maybe you should just set a fixed size of the window instead.
Otherwise, just set the Canvas.Width, Height, and ClipToBounds=True and you have a fixed sized canvas that positions its child elements with X/Y coordinates.
Also you should be sure to set SnapsToDevicePixels=True on the canvas so that child elements will have crisp pixel-aligned bounds.
resizing is cake:
MyCanvas.Width = 350;
MyCanvas.Height = 450;
this sets the size, you CAN render to coordinates outside of this, but it will be clipped. You can wrap your canvas inside a scroller to allow the user to see what is outside the height/width of the canvas.
as for the rest of your questions, i think you can see this SO question for your answers
Update 2020: on WPF .NET CORE: If the Canvas is a child of a Viewbox, the content is automatically scaled to the Viewbox height and width.
<Viewbox Stretch="Fill"
Width="50"
Height="50">
<Canvas>
<Path.... />
</Canvas>
</Viewbox>

Categories