当 window 大小更改时,如何在装饰器上绘制一个矩形以随其绑定到的图像元素缩放?

How do I get a Rectangle drawn on an adorner to scale with the Image element its bound to when the window size is changed?

我正在使用在装饰器上绘制的矩形来标记图像上的感兴趣区域。问题是,如果我调整 window 的大小,矩形不会改变大小。

我是 WPF 的新手,所以我做了很多研究,用谷歌搜索了我能用多个不同的搜索词。实际上,我只是通过这种方式学习了装饰器,而且我已经做到了这一点,但我在如何完成最后一块的问题上遇到了瓶颈。我知道我的问题是基于矩形的大小,但我不知道如何 capture/look 来调整它,因为 wpf 在 window 调整大小时调整实际图像对象的大小,所以没有要查看的比例因子。

这是我正在测试的应用程序的 XAML。

<Window x:Class="TestingAdorners.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestingAdorners"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
        <Grid ClipToBounds="True">
            <AdornerDecorator>
                <Image Name="Btn" Source="nyan.png" Stretch="Uniform"/>
            </AdornerDecorator>
        </Grid>
</Window>

装饰者class:

    class RoiAdorner : Adorner
    {
        public Rect rectangle = new Rect();
        public RoiAdorner(UIElement adornedElement) : base(adornedElement)
        {
            rectangle.Height = 30;
            rectangle.Width = 100;
            IsHitTestVisible = false;

        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            Pen pen = new Pen(Brushes.Green, 5);

            drawingContext.DrawRectangle(null, pen, rectangle);

        }
    }

还有 Xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            AdornerLayer.GetAdornerLayer(Btn).Add(new RoiAdorner(Btn));

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        }
    }

期望的结果是矩形随图像对象缩放,以便它始终覆盖图像的相同区域。问题是我不知道如何捕获比例因子以在 window 调整大小时将其放大和缩小。

更新:在思考了 Frenchy 的建议后,我意识到答案很简单:"Normalize your coordinates"

你只需像这样调整你的渲染方法:

class RoiAdorner : Adorner
{
    public double factorX = 0d;
    public double factorY = 0d;
    public Rect rectangle = new Rect();
    public RoiAdorner(UIElement adornedElement) : base(adornedElement)
    {

        rectangle.Height = 30;
        rectangle.Width = 100;
        IsHitTestVisible = false;

    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (factorY == 0)
            factorY =  rectangle.Height / AdornedElement.DesiredSize.Height;
        if (factorX == 0)
            factorX = rectangle.Width / AdornedElement.DesiredSize.Width;
        var r = new Rect(new Size(AdornedElement.DesiredSize.Width * factorX, AdornedElement.DesiredSize.Height * factorY));
        //Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
        drawingContext.DrawRectangle(null, new Pen(Brushes.Red, 5), r);

    }

this.AdornedElement.DesiredSize 给你图片的大小。

我会使用的方法是将图片和矩形渲染成相同的东西。然后那一件事被拉伸、缩放或其他。

执行此操作的一种方法是使用 DrawingImage。绘图方法虽然水平较低,但效率很高。

    <Grid ClipToBounds="True">
        <AdornerDecorator>
            <Image Name="img" Stretch="Uniform">
                <Image.Source>
                    <DrawingImage PresentationOptions:Freeze="True">
                        <DrawingImage.Drawing>
                            <DrawingGroup>
                                <ImageDrawing Rect="0,0,595,446" ImageSource="DSC00025.jpg"/>
                                <GeometryDrawing Brush="Green">
                                    <GeometryDrawing.Geometry>
                                        <RectangleGeometry Rect="0,0,100,30"  />
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>
                            </DrawingGroup>
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
        </AdornerDecorator>
    </Grid>

另一个是视觉画笔。控件继承自视觉 - 这是更高级别的编码。

    <Grid ClipToBounds="True">
        <AdornerDecorator>
            <Rectangle Name="rec">
            <Rectangle.Fill>
                <VisualBrush Stretch="Uniform">
                    <VisualBrush.Visual>
                        <Grid Height="446" Width="595">
                            <Image Source="DSC00025.jpg" Stretch="Fill"/>
                            <Rectangle Height="30" Width="100" Fill="Green"
                                       VerticalAlignment="Top" HorizontalAlignment="Left"/>
                        </Grid>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Rectangle.Fill>
            </Rectangle>
        </AdornerDecorator>
    </Grid>

请注意,这两个都是快速而粗略的插图,可以让您了解想法。我从我的硬盘驱动器中随机选择的图像大小为 446 * 595。您可以根据自己的要求计算大小或绑定或拉伸。