Изменение размера более чем одной фигуры одновременно с помощью.net adorner
Я разрабатываю настольное приложение в WPF, которое содержит различные типы фигур (например, круг, радиус-круг, диаметр-круг). Теперь мне нужно изменить размеры фигуры по требованию, поэтому я использовал .Net adorner
что обеспечивает гибкость для перетаскивания и изменения размеров форм. Точная проблема заключается в том, что я хочу изменить размер двух элементов одновременно (то есть * Когда я изменяю размер круга, Линия радиуса должна также изменить размер относительно начальной и конечной точек радиуса).
Обратите внимание, что я ничего не пробовал (я еще не занимался разработкой, поэтому у меня нет кода).
Обновленная пробная версия вашего кода. Это диаметр круга, поэтому, когда я перетаскиваю его, он будет перетаскивать только эллипс
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 ответа
Я сделал следующее для диаметра круга и радиуса круга, чтобы решить мою проблему.
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]; }
}
Предположим, что есть это 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);
}
}
В качестве примера я добавил 4 разных фигуры, вы можете добавить больше.
Каждая форма этого класса должна обрабатывать MouseEnter
событие и добавляет Custom Adorner, используя 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 на некоторые другие, и оба на остальные.
Во-первых, вы захотите определить одну контрольную точку, источник изменения размера для всего выбора. Скорее всего, это будет угол ограничивающего прямоугольника для шаблона "все выбранные объекты равны" или угол вашего активного объекта для "множества выбранных, но один активный" шаблон.
Затем определите процент изменения размера при перемещении мыши и примените изменение размера на один и тот же процент к каждой точке выбранных объектов, используя источник, который мы определили выше, а не их индивидуальное происхождение. Таким образом, оба их центра будут двигаться, а их размеры изменятся. Если у вас есть тип круга "Центр и радиус", вам нужно изменить радиус на половину процента изменения размера и т. Д.
Таким образом, вы получите хорошее и плавное изменение размера, так же как выбранные вами объекты были частью изображения, а вы изменяли размер изображения.
Примечание: вы должны применять изменение размера к исходным точкам выбранных объектов с каждым движением до тех пор, пока изменение размера не закончится, иначе ошибки с плавающей точкой будут накапливаться и делать объекты немного смещенными.