2

我想要一个可以均匀拉伸的图像作为背景。然后我希望我的画布的大小等于均匀拉伸的图像。(我发现的一种解决方法是将图像和画布放在网格内,并将画布宽度/高度绑定到图像的实际高度/宽度)。

然后我想在画布内放置绝对定位的项目。但这是问题所在。如果项目 X 为 50 且图像宽度为 200 像素,则可以。但如果图像宽度为 100 像素,项目 X 应该是 25。我也想要一个小比例的变换。有没有办法通过绑定来实现这一点?我是否必须实现我的自定义面板用户控件,因为我看不到其他干净的解决方案。

4

1 回答 1

3

您当然可以通过绑定来实现这一切,但我想创建一个派生面板会更容易和更清晰,该面板将子项安排在相对于面板的实际宽度和实际高度的位置。

派生的 Panel 类可以定义子位置的附加属性,类似于 Canvas.Left 和 Canvas.Top,但小数值范围为 0 到 1。

它还可以将背景图像维护为依赖属性。您将覆盖OnRender方法以直接绘制此图像。

面板还可以通过将其实际宽度除以图像宽度来计算当前比例因子。适当的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 回答