GANI
GANI

Reputation: 2049

How set children position in canvas based on its width wpf

Lets say canvas child has values left = 50, top = 50 when width of canvas = 500. When canvas is resizes how to set the left and top positions relative with the width of the canvas.

If user runs the application in big window or resizes the window, left and top positions of canvas children are messed up. How to rearrange the left and top positions of canvas children

Upvotes: 1

Views: 2088

Answers (3)

Maria
Maria

Reputation: 364

You can make a custom canvas with override OnPropertyChanged like this:

 public class YourCustomCanvas : Canvas
{
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);
        var ep = e.Property;
        if (ep != null)
        {
            if(ep.Name == "Left")
            foreach (FrameworkElement child in Children)
              SetLeft(child, GetLeft(child) / (double)e.OldValue * (double)e.NewValue);
            else if (ep.Name == "Top")
                foreach (FrameworkElement child in Children)
                    SetTop(child, GetTop(child) / (double)e.OldValue * (double)e.NewValue);
        }
    }
}

Then use YourCustomCanvas istead of the Canvas in your project like this:

// Canvas canvas = new Canvas();
YourCustomCanvas canvas = new YourCustomCanvas();

Upvotes: 1

Guttsy
Guttsy

Reputation: 2119

I will provide a recommendation, but because the question gives us nothing to work with in terms of existing code, I can't provide any specific/complete code until the question is updated.

A drag-and-drop interface, if done properly with the MVVM pattern, probably involves an ItemsControl (or something derived from it) whose ItemsPanelTemplate is a Canvas. Bindings will have to provide the Left and Top placements, probably as a percentage of the canvas dimensions, e.g.

...
<ItemsControl.ItemContainerStyle>
    <Style>
        ...
        <Setter Property="Canvas.Left">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource RelativePositionConverter}">
                    <MultiBinding.Bindings>
                        <Binding Path="Left" />
                        <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}" />
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>
        <Setter Property="Canvas.Top">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource RelativePositionConverter}">
                    <MultiBinding.Bindings>
                        <Binding Path="Top" />
                        <Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}" />
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>
        ...
    </Style>
</ItemsControl.ItemContainerStyle>
...

You will then need to create a class implementing IMultiValueConverter (the StaticResource I happened to call RelativePositionConverter in that XAML) that takes multiplies the first value (relative position; double value between 0 and 1) by the second value (the width or height of the canvas) to get the correct position. Note that you can't really implement the ConvertBack, so the code for your Thumb to enable the drag functionality is going to have to do similar math to set the backing value.

There are a lot of moving parts to accomplish this, but I think I have provided enough information to get you on the right path. If you have further questions on how to do bindings, converters, thumbs, control templating, etc., it would probably be best to create a new question with more specific information.

Upvotes: 0

Mini
Mini

Reputation: 453

Well if you are just putting your elements on the window and then giving them margins, they won't scale with the window. I recommend keeping them inside a Grid element, which automatically scales its contents. Then give your row/column definitions that allow the contents to scale. For example:

<RowDefinition Height="Auto" /> will resize to fit the contents and no more,

and <RowDefinition Height="*" /> will take up all remaining space.

Edit: Read this for more information. You might have to play around with the xaml code.

Upvotes: 1

Related Questions