バインドすることでこれらすべてを確実に達成できますが、PanelのActualWidthとActualheightに相対的な位置に子を配置する派生Panelを作成する方がはるかに簡単でクリーンになると思います。
派生したPanelクラスは、Canvas.LeftやCanvas.Topと同様に、子の位置にアタッチされたプロパティを定義できますが、小数値は0から1の範囲です。
また、依存関係プロパティとして背景画像を維持することもできます。この画像を直接描画するには、 OnRenderメソッドをオーバーライドします。
パネルは、ActualWidthを画像の幅で割って現在の倍率を計算することもできます。適切なScaleTransformプロパティは、各子のRenderTransformに簡単にアタッチできます。
編集:背景画像に対するパネルの寸法の均一性を除いて、以下はそのパネルがどのように実装されるかについての考えをあなたに与えるかもしれません:
public class ImagePanel : Panel
{
public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
"Left", typeof(double), typeof(ImagePanel),
new FrameworkPropertyMetadata(PositionChanged));
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
"Top", typeof(double), typeof(ImagePanel),
new FrameworkPropertyMetadata(PositionChanged));
public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
"Image", typeof(ImageSource), typeof(ImagePanel),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
private ScaleTransform scaleTransform = new ScaleTransform();
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
public static double GetTop(DependencyObject obj)
{
return (double)obj.GetValue(TopProperty);
}
public static void SetTop(DependencyObject obj, double value)
{
obj.SetValue(TopProperty, value);
}
public ImageSource Image
{
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
protected override void OnRender(DrawingContext dc)
{
if (Image != null)
{
dc.DrawImage(Image, new Rect(0d, 0d, ActualWidth, ActualHeight));
}
base.OnRender(dc);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (Image != null)
{
scaleTransform.ScaleX = sizeInfo.NewSize.Width / Image.Width;
scaleTransform.ScaleY = sizeInfo.NewSize.Height / Image.Height;
}
}
protected override Size MeasureOverride(Size availableSize)
{
foreach (UIElement element in InternalChildren)
{
element.Measure(availableSize);
}
return new Size();
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement element in InternalChildren)
{
element.RenderTransform = scaleTransform;
ArrangeElement(element, finalSize.Width, finalSize.Height);
}
return finalSize;
}
private static void PositionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var element = obj as UIElement;
var panel = VisualTreeHelper.GetParent(obj) as ImagePanel;
if (element != null && panel != null)
{
ArrangeElement(element, panel.ActualWidth, panel.ActualHeight);
}
}
private static void ArrangeElement(UIElement element, double width, double height)
{
var left = GetLeft(element);
var top = GetLeft(element);
var rect = new Rect(new Point(left * width, top * height), element.DesiredSize);
element.Arrange(rect);
}
}