使用.NET装饰器同时调整多个不同形状的大小

10
我正在开发一个WPF桌面应用程序,其中包含不同类型的形状(如圆形、半径圆、直径圆)。现在我需要按需调整形状的大小,所以我使用了.Net adorner,它提供了拖动和调整形状的灵活性。确切的问题是,我想同时调整两个元素的大小(即当我调整圆形大小时,半径线也应相对于半径起点和终点调整大小)。
注意:我还没有尝试过任何东西(我还没有进行任何开发,所以我没有代码)。
更新:您的代码试用版。这是一个直径圆,当我拖动它时,它只会拖动椭圆。

enter image description here

public class SimpleCircleAdorner : Adorner
    {
        // Be sure to call the base class constructor.
        public SimpleCircleAdorner(UIElement adornedElement, Panel ownerPanel)
            : base(adornedElement)
        {
            _ownerPanel = ownerPanel;
        }

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            Point point = Mouse.GetPosition(AdornedElement);
            _currentPosition = getMousePosition(point);
            switch (_currentPosition)
            {
                case MousePosition.BR:
                case MousePosition.TL:
                    Cursor = Cursors.SizeNWSE;
                    break;
                case MousePosition.BL:
                case MousePosition.TR:
                    Cursor = Cursors.SizeNESW;
                    break;
            }
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement);
            if (adornerLayer != null)
            {
                Adorner[] adorners = adornerLayer.GetAdorners(AdornedElement);
                if (adorners != null)
                {
                    foreach (Adorner adorner in adorners)
                    {
                        adornerLayer.Remove(adorner);
                    }
                }
            }
        }

        MousePosition _currentPosition;
        Panel _ownerPanel;
        bool _isDraging = false;
        Point _startPosition;

        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (Mouse.Capture(this))
            {
                _isDraging = true;
                _startPosition = Mouse.GetPosition(_ownerPanel);
            }
        }

        protected override void OnPreviewMouseMove(MouseEventArgs e)
        {
            if (_isDraging)
            {
                Point newPosition = Mouse.GetPosition(_ownerPanel);
                double diffX = (newPosition.X - _startPosition.X);
                double diffY = (newPosition.Y - _startPosition.Y);

                // we should decide whether to change Width and Height or to change Canvas.Left and Canvas.Right
                if (Math.Abs(diffX) >= 1 || Math.Abs(diffY) >= 1)
                {
                    switch (_currentPosition)
                    {
                        case MousePosition.TL:
                        case MousePosition.BL:
                            foreach (FrameworkElement ui in _ownerPanel.Children)
                            {
                                if (ui.GetType() == typeof(Ellipse) || ui.GetType() == typeof(Line))
                                {
                                    Canvas.SetLeft(ui, Math.Max(0, Canvas.GetLeft(ui) + diffX));
                                    ui.Width = Math.Max(0, ui.Width - diffX);
                                }
                            }
                            _ownerPanel.InvalidateArrange();

                            break;
                        case MousePosition.BR:
                        case MousePosition.TR:

                            foreach (FrameworkElement ui in _ownerPanel.Children)
                            {
                                if (ui.GetType() == typeof(Ellipse) || ui.GetType() == typeof(Line))
                                {
                                    ui.Width = Math.Max(0, ui.Width + diffX);
                                }
                            }
                            break;
                    }


                    switch (_currentPosition)
                    {
                        case MousePosition.TL:
                        case MousePosition.TR:
                            foreach (FrameworkElement ui in _ownerPanel.Children)
                            {
                                if (ui.GetType() == typeof(Ellipse) || ui.GetType() == typeof(Line))
                                {
                                    Canvas.SetTop(ui, Math.Max(0, Canvas.GetTop(ui) + diffY));
                                }
                            }
                            foreach (FrameworkElement ui in _ownerPanel.Children)
                            {
                                if (ui.GetType() == typeof(Ellipse) || ui.GetType() == typeof(Line))
                                {
                                    ui.Height = Math.Max(0, ui.Height - diffY);
                                }
                            }
                            break;
                        case MousePosition.BL:
                        case MousePosition.BR:
                            foreach (FrameworkElement ui in _ownerPanel.Children)
                            {
                                if (ui.GetType() == typeof(Ellipse) || ui.GetType() == typeof(Line))
                                {
                                    ui.Height = Math.Max(0, ui.Height + diffY);
                                }
                            }
                            break;

                    }
                }
                _startPosition = newPosition;
            }
        }

        protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
        {

        }

        protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)
        {
            if (_isDraging)
            {
                Mouse.Capture(null);
                _isDraging = false;
            }
        }

        MousePosition getMousePosition(Point point) // point relative to element
        {
            double h2 = ActualHeight / 2;
            double w2 = ActualWidth / 2;
            if (point.X < w2 && point.Y < h2)
                return MousePosition.TL;
            else if (point.X > w2 && point.Y > h2)
                return MousePosition.BR;
            else if (point.X > w2 && point.Y < h2)
                return MousePosition.TR;
            else
                return MousePosition.BL;



        }

        enum MousePosition
        {
            TL,
            TR,
            BL,
            BR
        }

        double _renderRadius = 5.0;
        protected override void OnRender(DrawingContext drawingContext)
        {
            Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
            SolidColorBrush renderBrush = new SolidColorBrush(Colors.Black);
            renderBrush.Opacity = 0.3;
            Pen renderPen = new Pen(new SolidColorBrush(Colors.Black), 1.5);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, _renderRadius, _renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, _renderRadius, _renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, _renderRadius, _renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, _renderRadius, _renderRadius);
        }
    }
3个回答

6
假设有一个名为MyShapes的类,它是从Canvas派生而来,包含一些任意形状:
public class MyShapes : Canvas
{
    public MyShapes()
    {
        Background = Brushes.Transparent; // for mouse events to fire as expected.

        Ellipse elip = new Ellipse() { Fill = Brushes.Red, Width=40, Height=40 };
        SetLeft(elip, 50);
        SetTop(elip, 10);
        Children.Add(elip);
        elip.MouseEnter += E_MouseEnter;

        Ellipse elip2 = new Ellipse() { Fill = Brushes.Gray, Width = 40, Height = 40 };
        SetLeft(elip2, 600);
        SetTop(elip2, 400);
        Children.Add(elip2);
        elip2.MouseEnter += E_MouseEnter;

        Rectangle rect = new Rectangle() { Fill = Brushes.Blue, Width = 40, Height = 40 };
        SetLeft(rect, 260);
        SetTop(rect, 260);
        Children.Add(rect);
        rect.MouseEnter += E_MouseEnter;

        Rectangle rect2 = new Rectangle() { Fill = Brushes.Yellow, Width = 40, Height = 40 };
        SetLeft(rect2, 400);
        SetTop(rect2, 100);
        Children.Add(rect2);
        rect2.MouseEnter += E_MouseEnter;

    }


    private void E_MouseEnter(object sender, MouseEventArgs e)
    {
        SimpleCircleAdorner ad = new SimpleCircleAdorner((UIElement)sender, this); 
        AdornerLayer adLayer = AdornerLayer.GetAdornerLayer((UIElement)sender);
        adLayer.Add(ad);
    } 

}

我添加了四个不同的形状,只是作为例子,您可以添加更多。

这个类的每个形状都必须处理MouseEnter事件,并使用AdornerLayer.GetAdornerLayer()方法添加一个自定义装饰器。我使用了msdn示例

public class SimpleCircleAdorner : Adorner
{
    // Be sure to call the base class constructor.
    public SimpleCircleAdorner(UIElement adornedElement, Panel ownerPanel)
      : base(adornedElement)
    {
        _ownerPanel = ownerPanel; 
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
        Point point = Mouse.GetPosition(AdornedElement);
        _currentPosition = getMousePosition(point);
        switch (_currentPosition)
        {
            case MousePosition.BR:
            case MousePosition.TL:
                Cursor = Cursors.SizeNWSE;
                break;
            case MousePosition.BL:
            case MousePosition.TR:
                Cursor = Cursors.SizeNESW;
                break;
        }
    }

    protected override void OnMouseLeave(MouseEventArgs e)
    { 
        AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement);
        if (adornerLayer != null)
        {
            Adorner[] adorners = adornerLayer.GetAdorners(AdornedElement);
            if (adorners != null)
            {
                foreach (Adorner adorner in adorners)
                { 
                    adornerLayer.Remove(adorner);
                }
            }
        }
    }

    MousePosition _currentPosition;
    Panel _ownerPanel;
    bool _isDraging = false;
    Point _startPosition;

    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        if (Mouse.Capture(this))
        {
            _isDraging = true;
            _startPosition = Mouse.GetPosition(_ownerPanel);
        }
    }

    protected override void OnPreviewMouseMove(MouseEventArgs e)
    {
        if (_isDraging)
        {
            Point newPosition = Mouse.GetPosition(_ownerPanel);
            double diffX = (newPosition.X - _startPosition.X);
            double diffY = (newPosition.Y - _startPosition.Y);

            // we should decide whether to change Width and Height or to change Canvas.Left and Canvas.Right
            if (Math.Abs(diffX) >= 1 || Math.Abs(diffY) >= 1)
            { 
                switch (_currentPosition)
                {
                    case MousePosition.TL:
                    case MousePosition.BL:
                        foreach (FrameworkElement ui in _ownerPanel.Children)
                        { 
                            Canvas.SetLeft(ui, Math.Max(0, Canvas.GetLeft(ui) + diffX)); 
                            ui.Width = Math.Max(0, ui.Width - diffX);
                        }
                        _ownerPanel.InvalidateArrange();

                        break;
                    case MousePosition.BR:
                    case MousePosition.TR:
                        foreach (FrameworkElement ui in _ownerPanel.Children)
                            ui.Width = Math.Max(0, ui.Width + diffX);
                        break;
                }


                switch (_currentPosition)
                {
                    case MousePosition.TL:
                    case MousePosition.TR:
                        foreach (FrameworkElement ui in _ownerPanel.Children)
                            Canvas.SetTop(ui, Math.Max(0, Canvas.GetTop(ui) + diffY));
                        foreach (FrameworkElement ui in _ownerPanel.Children)
                            ui.Height = Math.Max(0, ui.Height - diffY);
                        break;
                    case MousePosition.BL:
                    case MousePosition.BR: 
                        foreach (FrameworkElement ui in _ownerPanel.Children)
                            ui.Height = Math.Max(0, ui.Height + diffY);
                        break;

                }
            }
            _startPosition = newPosition;
        }
    }

    protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
    {
        if (_isDraging)
        {
            Mouse.Capture(null);
            _isDraging = false;
        }
    }

    MousePosition getMousePosition(Point point) // point relative to element
    {
        double h2 = ActualHeight / 2;
        double w2 = ActualWidth / 2;
        if (point.X < w2 && point.Y < h2)
            return MousePosition.TL;
        else if (point.X > w2 && point.Y > h2)
            return MousePosition.BR;
        else if (point.X > w2 && point.Y < h2)
            return MousePosition.TR;
        else
            return MousePosition.BL;



    }

    enum MousePosition
    {
        TL,
        TR,
        BL,
        BR
    }

    double _renderRadius = 5.0;

    protected override void OnRender(DrawingContext drawingContext)
    {
        Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize); 
        SolidColorBrush renderBrush = new SolidColorBrush(Colors.Black);
        renderBrush.Opacity = 0.3;
        Pen renderPen = new Pen(new SolidColorBrush(Colors.Black), 1.5); 
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, _renderRadius, _renderRadius);
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, _renderRadius, _renderRadius);
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, _renderRadius, _renderRadius);
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, _renderRadius, _renderRadius);
    }
}

如您所见,除了我提供的msdn链接中解释的必需部分(例如OnRender()等),还需要更改其他一些内容。
首先,在构造函数中发送Canvas的实例,因为我们将更改其子元素的大小。其次,您应该处理不同的鼠标事件。
处理MouseEnter事件以设置光标形状。请参见方法getMousePosition(...)
处理MouseLeave事件以从AdornerElement中删除装饰。
处理PreviewMouseLeftButtonDown以设置拖动的开始。
处理PreviewMouseLeftButtonUp以设置拖动的结束。
处理PreviewMouseMove以确定元素的新大小和位置。这部分可能有点棘手,因为您应在某些情况下更改形状的宽度和高度,在其他情况下更改Canvas.Left和Canvas.Top属性,在剩余情况下同时更改两者。 示例结果

你应该将“Ellipse”和“Line”添加到一个“Grid”中,然后将Grid添加到Canvas中,然后调整“Grid”的大小,而不是单独调整形状。 - rmojab63

3
我针对直径圆和半径圆采取了以下措施来解决我的问题。
public class ResizingAdorner : Adorner
    {
        // Resizing adorner uses Thumbs for visual elements.  
        // The Thumbs have built-in mouse input handling.

        System.Windows.Controls.Primitives.Thumb topLeft, topRight, bottomLeft, bottomRight, Left, Right, RightCenter, Center;

        string m_strelement_prefix = string.Empty;
        List<UIElement> multiObject = new List<UIElement>();
        List<Point> contextData = new List<Point>();
        Panel _ownerPanel;

        // To store and manage the adorner's visual children.
        VisualCollection visualChildren;

        public ResizingAdorner(UIElement adornedElement, Panel ownerPanel)
            : base(adornedElement)
        {
            _ownerPanel = ownerPanel;
            visualChildren = new VisualCollection(this);

            m_strelement_prefix = (adornedElement.Uid != "") ? adornedElement.Uid.Substring(0, 2) : string.Empty;
            if (m_strelement_prefix == string.Empty) { return; }

            switch (m_strelement_prefix)
            {
                case "DC":
                    if (adornedElement.GetType() == typeof(Line) || adornedElement.GetType() == typeof(Ellipse))
                    {
                        BuildAdornerCorner(ref Left, Cursors.Hand);
                        BuildAdornerCorner(ref Right, Cursors.Hand);
                        Left.DragDelta += new DragDeltaEventHandler(onDragDeltaLeft);
                        Right.DragDelta += new DragDeltaEventHandler(onDragDeltaRight);

                        foreach (UIElement ui in _ownerPanel.Children)
                            if (ui.Uid.Contains(m_strelement_prefix)) { multiObject.Add(ui); }
                    }
                    break;
                case "RC":
                    if (adornedElement.GetType() == typeof(Line) || adornedElement.GetType() == typeof(Ellipse))
                    {
                        BuildAdornerCorner(ref Right, Cursors.Hand);
                        Right.DragDelta += new DragDeltaEventHandler(onDragDeltaRight);
                        foreach (UIElement ui in _ownerPanel.Children)
                            if (ui.Uid.Contains(m_strelement_prefix)) { multiObject.Add(ui); }
                    }
                    break;
                case "TC":
                    break;

            }
        }

        void onDragDeltaLeft(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = AdornedElement as FrameworkElement;
            System.Windows.Controls.Primitives.Thumb hitThumb = sender as System.Windows.Controls.Primitives.Thumb;
            if (adornedElement == null || hitThumb == null) return;
            Point position = Mouse.GetPosition(this);

            double distance = 0;
            Point _startPoint = new Point();

            switch (m_strelement_prefix)
            {
                #region Diameter Circle
                case "DC":  
                foreach (UIElement ui in multiObject)
                {
                    if (ui.GetType() != AdornedElement.GetType())
                    {
                        switch (ui.GetType().ToString())
                        {
                            //Selected Element is Ellipse
                            case "System.Windows.Shapes.Line":
                                _startPoint = new Point();
                                distance = getMidPoint(new Point(((Line)ui).X2, ((Line)ui).Y2), position, out _startPoint, true);

                                ((Line)ui).X2 = position.X;
                                ((Line)ui).Y2 = position.Y;

                                ((Ellipse)adornedElement).Height = ((Ellipse)adornedElement).Width = distance * 2;
                                Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);

                                break;
                            //Selected Element is Line
                            case "System.Windows.Shapes.Ellipse":
                                _startPoint = new Point();
                                distance = getMidPoint(new Point(((Line)adornedElement).X2, ((Line)adornedElement).Y2), position, out _startPoint, true);

                                ((Line)adornedElement).X2 = position.X;
                                ((Line)adornedElement).Y2 = position.Y;

                                ((Ellipse)ui).Height = ((Ellipse)ui).Width = distance * 2;
                                Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);
                                break;
                        }
                    }
                }
                break;
                #endregion 
            }
        }

        void onDragDeltaRight(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = AdornedElement as FrameworkElement;
            System.Windows.Controls.Primitives.Thumb hitThumb = sender as System.Windows.Controls.Primitives.Thumb;
            if (adornedElement == null || hitThumb == null) return;

            Point position = Mouse.GetPosition(this);
            double distance = 0;
            Point _startPoint = new Point();

            switch (m_strelement_prefix)
            {
                #region Diameter Circle
                case "DC":
                    foreach (UIElement ui in multiObject)
                    {
                        if (ui.GetType() != AdornedElement.GetType())
                        {
                            switch (ui.GetType().ToString())
                            {
                                //Selected Element is Ellipse
                                case "System.Windows.Shapes.Line":
                                    _startPoint = new Point();
                                    distance = getMidPoint(new Point(((Line)ui).X1, ((Line)ui).Y1), position, out _startPoint, true);

                                    ((Line)ui).X2 = position.X;
                                    ((Line)ui).Y2 = position.Y;

                                    ((Ellipse)adornedElement).Height = ((Ellipse)adornedElement).Width = distance * 2;
                                    Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                    Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);

                                    break;
                                //Selected Element is Line
                                case "System.Windows.Shapes.Ellipse":
                                    _startPoint = new Point();
                                    distance = getMidPoint(new Point(((Line)adornedElement).X1, ((Line)adornedElement).Y1), position, out _startPoint, true);

                                    ((Line)adornedElement).X2 = position.X;
                                    ((Line)adornedElement).Y2 = position.Y;

                                    ((Ellipse)ui).Height = ((Ellipse)ui).Width = distance * 2;
                                    Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                    Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);
                                    break;
                            }
                        }
                    }
                    break;
                #endregion

                #region Radius Circle
                case "RC":
                    foreach (UIElement ui in multiObject)
                    {
                        if (ui.GetType() != AdornedElement.GetType())
                        {
                            switch (ui.GetType().ToString())
                            {
                                //Selected Element is Ellipse
                                case "System.Windows.Shapes.Line":
                                    _startPoint = new Point();

                                    distance = getMidPoint(new Point(((Line)ui).X1, ((Line)ui).Y1), position, out _startPoint, false);

                                    ((Line)ui).X2 = position.X;
                                    ((Line)ui).Y2 = position.Y;

                                    ((Ellipse)adornedElement).Height = ((Ellipse)adornedElement).Width = distance * 2;
                                    Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                    Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);

                                    break;
                                //Selected Element is Line
                                case "System.Windows.Shapes.Ellipse":
                                    _startPoint = new Point();
                                    distance = getMidPoint(new Point(((Line)adornedElement).X1, ((Line)adornedElement).Y1), position, out _startPoint, false);

                                    ((Line)adornedElement).X2 = position.X;
                                    ((Line)adornedElement).Y2 = position.Y;

                                    ((Ellipse)ui).Height = ((Ellipse)ui).Width = distance * 2;
                                    Canvas.SetLeft(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Left);
                                    Canvas.SetTop(ui, (new Thickness((_startPoint.X - ((distance * 2) / 2)), (_startPoint.Y - ((distance * 2) / 2)), 0, 0)).Top);
                                    break;
                            }
                        }
                    }
                    break;
                #endregion 
            }
        }

        private static double getMidPoint(Point _start,Point _end,out Point _middle , bool findMidPoint)
        {
            _middle = (findMidPoint) ? new Point(((_start.X + _end.X) / 2), ((_start.Y + _end.Y) / 2)) : _start;
            return getDistanceBetweenTwoPoints(_middle, _end);
        }

        private static double getDistanceBetweenTwoPoints(Point StartPoint, Point EndPoint)
        {
            return Math.Round(Math.Sqrt(Math.Pow((EndPoint.X - StartPoint.X), 2) + Math.Pow((EndPoint.Y - StartPoint.Y), 2)), 2);
        }
        // Arrange the Adorners.
        protected override Size ArrangeOverride(Size finalSize)
        {

            // desiredWidth and desiredHeight are the width and height of the element that's being adorned.  
            // These will be used to place the ResizingAdorner at the corners of the adorned element.  
            double desiredWidth = AdornedElement.DesiredSize.Width;
            double desiredHeight = AdornedElement.DesiredSize.Height;

            // adornerWidth & adornerHeight are used for placement as well.
            double adornerWidth = this.DesiredSize.Width;
            double adornerHeight = this.DesiredSize.Height;

            switch (m_strelement_prefix)
            {
                case "DC":
                    if (AdornedElement.GetType() == typeof(Line) || AdornedElement.GetType() == typeof(Ellipse))
                    {
                        if (AdornedElement.GetType() == typeof(Ellipse)) { contextData = ((List<Point>)((AdornedElement as FrameworkElement).DataContext)); }

                        Line selectedLine = ((AdornedElement.GetType() == typeof(Ellipse)) && contextData.Count != 0)
                            ? new Line() { X1 = contextData[0].X, Y1 = contextData[0].Y, X2 = contextData[1].X, Y2 = contextData[1].Y }
                            : (AdornedElement as Line);

                        double left = Math.Min(selectedLine.X1, selectedLine.X2);
                        double top = Math.Min(selectedLine.Y1, selectedLine.Y2);
                        var startRect = new Rect(selectedLine.X1 - (Left.Width / 2), selectedLine.Y1 - (Left.Width / 2), Left.Width, Left.Height);
                        var endRect = new Rect(selectedLine.X2 - (Right.Width / 2), selectedLine.Y2 - (Right.Height / 2), Right.Width, Right.Height);
                        Left.Arrange(startRect);
                        Right.Arrange(endRect);
                    }
                    break;
                case "RC":
                    if (AdornedElement.GetType() == typeof(Line) || AdornedElement.GetType() == typeof(Ellipse))
                    {
                        if (AdornedElement.GetType() == typeof(Ellipse)) { contextData = ((List<Point>)((AdornedElement as FrameworkElement).DataContext)); }

                        Line selectedLine = ((AdornedElement.GetType() == typeof(Ellipse)) && contextData.Count != 0)
                            ? new Line() { X1 = contextData[0].X, Y1 = contextData[0].Y, X2 = contextData[1].X, Y2 = contextData[1].Y }
                            : (AdornedElement as Line);

                        double top = Math.Min(selectedLine.Y1, selectedLine.Y2);
                        var endRect = new Rect(selectedLine.X2 - (Right.Width / 2), selectedLine.Y2 - (Right.Height / 2), Right.Width, Right.Height);
                        Right.Arrange(endRect);
                    }
                    break;
            }
            return finalSize;
        }

        // Helper method to instantiate the corner Thumbs, set the Cursor property, 
        // set some appearance properties, and add the elements to the visual tree.
        void BuildAdornerCorner(ref System.Windows.Controls.Primitives.Thumb cornerThumb, Cursor customizedCursor)
        {
            if (cornerThumb != null) return;

            cornerThumb = new System.Windows.Controls.Primitives.Thumb();

            // Set some arbitrary visual characteristics.
            cornerThumb.Cursor = customizedCursor;
            cornerThumb.Height = cornerThumb.Width = 10;
            cornerThumb.Background = new SolidColorBrush(Colors.Black);

            visualChildren.Add(cornerThumb);
        }

        // This method ensures that the Widths and Heights are initialized.  Sizing to content produces
        // Width and Height values of Double.NaN.  Because this Adorner explicitly resizes, the Width and Height
        // need to be set first.  It also sets the maximum size of the adorned element.
        void EnforceSize(FrameworkElement adornedElement)
        {
            if (adornedElement.Width.Equals(Double.NaN))
                adornedElement.Width = adornedElement.DesiredSize.Width;
            if (adornedElement.Height.Equals(Double.NaN))
                adornedElement.Height = adornedElement.DesiredSize.Height;

            FrameworkElement parent = adornedElement.Parent as FrameworkElement;
            if (parent != null)
            {
                adornedElement.MaxHeight = parent.ActualHeight;
                adornedElement.MaxWidth = parent.ActualWidth;
            }
        }

        // Override the VisualChildrenCount and GetVisualChild properties to interface with 
        // the adorner's visual collection.
        protected override int VisualChildrenCount { get { return visualChildren.Count; } }
        protected override Visual GetVisualChild(int index) { return visualChildren[index]; }

    }    

enter image description here

enter image description here


0

首先,您需要确定一个单一的参考点,即整个选择区域的调整起点。它很可能是“所有选定对象相等”的边界矩形的一个角落,或者是“多个选定但一个活动”的您当前对象的一个角落。

然后,确定鼠标移动时的调整百分比,并将同样的百分比应用于所选对象的每个点,以我们上面确定的起点为基准,而不是它们各自的起点。因此,它们的中心将移动并且它们的大小会改变。如果您有“中心和半径”类型的圆形,则需要将半径按缩放百分比的一半进行调整等等...

这样,您就可以获得一个漂亮而平滑的调整效果,就像您的所选对象是图像的一部分,而您正在调整该图像一样。

注意:您必须在每次移动时将调整应用于所选对象的原始点,直到调整结束,否则浮点错误将累积并使对象略微错位。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接