Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a GeometryDrawing displayed on Canvas with clipped coordinates?

Tags:

c#

wpf

xaml

I have the following simple code that draws rectangle

    <Canvas Name="MainImageLayer" >
        <Image >
            <Image.Source >
                <DrawingImage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" >
                    <DrawingImage.Drawing >                            
                        <DrawingGroup>
                            <DrawingGroup.Children>
                                <GeometryDrawing>
                                    <GeometryDrawing.Pen>
                                        <Pen Brush="#FF1acc33" Thickness="1" />
                                    </GeometryDrawing.Pen>
                                    <GeometryDrawing.Brush>
                                        <SolidColorBrush>Red</SolidColorBrush>
                                    </GeometryDrawing.Brush>
                                    <GeometryDrawing.Geometry>
                                        <RectangleGeometry Rect="300,480,287,83" />
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>

                            </DrawingGroup.Children>
                        </DrawingGroup>
                    </DrawingImage.Drawing>
                </DrawingImage>
            </Image.Source>                
        </Image>
    </Canvas>

The result looks like this - note that the rectangle is in (0,0), even that the Rect is defined as

<RectangleGeometry Rect="300,480,287,83" />

enter image description here

I want it to start at (300,480), like that:

enter image description here

I can achieve that by inspecting my DrawingImage and doing :

            <Canvas.Top>300</Canvas.Top>
            <Canvas.Left>480</Canvas.Left>

But isn't there a better way, considering the fact that this data is encoded into the Geometry?

like image 405
Andrey Rubshtein Avatar asked Feb 21 '23 21:02

Andrey Rubshtein


1 Answers

Your problem comes from the fact that you have all of your geometry wrapped in an 'Image' object. By default, the .Height and .Width properties of an Image object are set to 'Auto', and the .Stretch property is set to 'Uniform'. This guarantees that your rectangle will always appear in the top left corner of your Canvas.

If you really need to encapsulate your geometry in an 'Image' object (which I would caution you not to do) you will need to set the Margin of your Image object to 300,480,0,0. in order to get your rectangle to appear where you want it. This is required because of the way an 'Image' object handles its contents.

An Image object does not behave like a Canvas object, even if it is inside one.

Unless there is some overwhelming reason to keep the Image object, you will have much better success if you discard the Image and draw directly on the Canvas.

EDIT

Why should an Image object not be used in this case?
An Image object is primarily used for displaying...well, images, like bitmaps and such. It is not suited for drawing geometry in it at a specific location (and size). Like most WPF controls, it is what I would call a 'relative' control, meaning it is well suited for automatically resizing and positioning itself in relation to both its contents and its parent. A Canvas on the other hand is an example of an 'absolute' control. Its entire reason for existence is to allow content to be drawn upon it in an exact location with an exact size. Adding an Image inside a Canvas and then drawing the geometry inside the Image just adds an unnecessary layer of complexity between the Canvas and the geometry that needs to be drawn.

How can the geometry be added directly?
One of the easiest ways would be to use the Path object given in Clemens' answer. Just replace your entire Image object and all its contents with the 5 lines of that Path and your rectangle will appear exactly where it should be. You can also do it with a single line and a Rectangle object:

<Rectangle Height="83" Width="287" Margin="300,480,0,0" Stroke="#FF1acc33" StrokeThickness="1" Fill="Red" />

but I would recommend the Path since it contains the size and position of the rectangle in one set of numbers. The Path also allows you much more flexibility if you are working with shapes other than rectangles.

like image 69
Stewbob Avatar answered Apr 09 '23 02:04

Stewbob