Reputation: 2049
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
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
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
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