What you're looking for can be done even with a Canvas
however you should really consider using something like an ItemsControl
for this.
Solution when forced to use Canvas
:
private void Refresh() {
for (int i = 1; i < canvasboard.Children.Count; ++i) {
var currentElement = canvasboard.Children[i] as FrameworkElement;
var previousElement = canvasboard.Children[i - 1] as FrameworkElement;
if (currentElement == null || previousElement == null)
return;
var requiredTop = Canvas.GetTop(previousElement) + previousElement.Height - 1;
if (Math.Abs(Canvas.GetTop(currentElement) - requiredTop) > 0.0)
Canvas.SetTop(currentElement, requiredTop);
}
}
Now call this function "after" you change the size of an existing element in the Canvas
and it will re-position the elements accordingly to suit the new dimension. In your code, it would be called from the gridInner_CellValueChanged(...)
function after you set the new height in "edit" mode.
What you should try to do:
If your able to persuade whoever you need to and get to use something like an ItemsControl
, this will be so much simpler.
say a rough example:
xaml could be:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
with Items
declared as public ObservableCollection<Rectangle> Items { get; set; }
in code.
Now your Add()
function could just be:
private void Add() {
var rect = new Rectangle {
Stroke = Brushes.Red,
StrokeThickness = 1,
Height = Convert.ToDouble(txtheight.Text),
Width = 100
};
Items.Add(rect);
}
and as for updates when your editing existing control's that would be automatic in this case. There is no hard-coded positioning as the Layout container takes care of all that mess for you.
You can ofcourse switch the Items
collection type to your own custom control type MyLayer
and with it implementing INPC, changes would still continue to be automatic. You'd have to define a DataTemplate
now to get your Item to be rendered but that's like 3 lines of work in just xaml.
You can also just work of the Items
property directly when needing to tweak an exisiting control than having to reference the ItemsControl
in code-behind. Binding's should take care of the updates to the view automatically.