2

均一に伸びる背景の画像が欲しいです。次に、キャンバスのサイズを均一に引き伸ばされた画像と同じにします(回避策として、グリッド内に画像とキャンバスを配置し、キャンバスの幅/高さを画像の実際の高さ/幅にバインドします)。

次に、キャンバス内に絶対的に配置されるアイテムが必要ですが、ここに問題があります。アイテムXが50で、画像の幅が200ピクセルの場合は、問題ありません。ただし、画像の幅が100ピクセルの場合、アイテムXは25になります。また、小規模な変換が必要です。バインディングを介してこれを達成する方法はありますか?他にクリーンなソリューションがないため、カスタムパネルのユーザーコントロールを実装する必要がありますか?

4

1 に答える 1

3

バインドすることでこれらすべてを確実に達成できますが、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);
    }
}
于 2012-12-05T12:47:56.113 に答える