Jeet Parekh
Jeet Parekh

Reputation: 740

WPF Canvas not placing objects as expected

I just began learning WPF and XAML, and I was taking a look at the things I could do in Blend.

So what I tried was placing a rectangle in a grid.

Grid size: 517x319 (auto)

Rectangle size: 497x299 (auto)

XAML:

<Window x:Class="UITest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UITest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Rectangle Fill="Black" Margin="10"/>
    </Grid>
</Window>

And it gave this output

enter image description here

But when I tried doing the same thing with a canvas,

Canvas size: 517x319 (auto)

Rectangle size: 497x299 (auto)

XAML:

<Window x:Class="UITest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UITest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Canvas>
        <Rectangle Fill="Black" Height="299" Width="497" Canvas.Left="10" Canvas.Top="10"/>
    </Canvas>
</Window>

it renders into

enter image description here

And then I tried the same thing again... this time: Grid -> Canvas -> Rectangle, and this is what I got

Grid size: 517x319 (auto)

Canvas size: 497x299 (auto)

Rectangle size: 477x279 (auto)

enter image description here

XAML:

<Window x:Class="UITest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UITest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Canvas Margin="10" Background="Black">
            <Rectangle Fill="#FFF4F4F5" Height="279" Width="477" Canvas.Left="10" Canvas.Top="10" Stroke="Black"/>
        </Canvas>
    </Grid>
</Window>

Why isn't the rectangle being placed in the center of the canvas?

Upvotes: 0

Views: 321

Answers (2)

Spluf
Spluf

Reputation: 820

Glad I could help :).

It looks like centering content in WPF canvas is a bit tricky because of Windows (when adding the title bar and practically the entire frame for running the app it messes the sizes a bit). A solution to this is using a converter to get the height and width from the running app and calculate the center points.

So this is how that might look like:

public class HalfValueConverter : IMultiValueConverter
{

    #region IMultiValueConverter Members

    public object Convert(object[] values,
                          Type targetType,
                          object parameter,
                          CultureInfo culture)
    {
        if (values == null || values.Length < 2)
        {
            throw new ArgumentException(
                "HalfValueConverter expects 2 double values to be passed" +
                " in this order -> totalWidth, width",
                "values");
        }

        double totalWidth = (double)values[0];
        double width = (double)values[1];
        return (object)((totalWidth - width) / 2);
    }

    public object[] ConvertBack(object value,
                                Type[] targetTypes,
                                object parameter,
                                CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

and here is the XML for your case:

<Window x:Class="UITest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UITest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <local:HalfValueConverter x:Key="HalfValue" />
        </Grid.Resources>
        <Canvas x:Name="canvas">
            <Rectangle Fill="Black"
                   Height="299"
                   Width="497"
                   x:Name="rectangle"
                   >
                <Canvas.Left>
                    <MultiBinding Converter="{StaticResource HalfValue}">
                        <Binding ElementName="canvas" Path="ActualWidth" />
                        <Binding ElementName="rectangle" Path="ActualWidth" />
                    </MultiBinding>
                </Canvas.Left>
                <Canvas.Top>
                    <MultiBinding Converter="{StaticResource HalfValue}">
                        <Binding ElementName="canvas" Path="ActualHeight" />
                        <Binding ElementName="rectangle" Path="ActualHeight" />
                    </MultiBinding>
                </Canvas.Top>
            </Rectangle>
        </Canvas>
    </Grid>
</Window>

Here is a good article on how to do this: http://blogorama.nerdworks.in/centeringelementsonacanvasinwp/

Upvotes: 1

Grx70
Grx70

Reputation: 10349

I'm guessing you took the Grid and Canvas sizes from properties pane. If that's the case, the problem is that these are sizes computed at design-time, and are different (at least at my side) than the sizes computed at run-time (the outer element was actually 509x311 at run-time and not 517x319).

I believe that's caused by some window resizing policy - I remember reading that windows have extra invisible borders around them so that you don't have to precisely hit it's visible border in order to resize it (the cursor only needs to be "close enough") . Unfortunately, I can't seem to find this link, but I'll post it as soon as I find it.

Upvotes: 0

Related Questions