使用 .net 装饰器同时调整多个不同形状的大小
Resize more than one different shape at same time using .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);
}
}
假设有这个 MyShapes
class,派生自 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个不同的Shapes作为例子,你可以添加更多。
此 class 的每个形状都必须处理 MouseEnter
事件并使用 AdornerLayer.GetAdornerLayer()
方法添加自定义装饰器。我用了 msdn example:
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);
}
}
如你所见,除了我提供的msdnlink中说明的必需部分(如OnRender()
等),你还应该更改一些其他内容。
首先,在构造函数中发送 Canvas
的实例,因为我们要更改其子项的大小。其次,你应该处理不同的鼠标事件。
处理 MouseEnter
事件以将光标设置为适当的形状。见方法 getMousePosition(...)
.
处理 MouseLeave
事件以从 AdornerElement
中删除装饰器
手柄 PreviewMouseLeftButtonDown
设置拖动的开始。
句柄PreviewMouseLeftButtonUp
设置拖动结束。
处理 PreviewMouseMove
以确定元素的新大小和位置。这部分可能有点棘手,因为在某些情况下您应该更改形状的宽度和高度,在其他情况下更改 Canvas.Left 和 Canvas.Top 属性,在其余情况下两者都更改。
首先,您需要确定一个参考点,即整个选区调整大小的原点。它很可能是 "all selected objects are equal" 模式的边界矩形的一个角,或者 "many selected but one active" 模式的活动对象的一个角。
然后,确定鼠标移动时调整大小的百分比,并将相同百分比的调整大小应用于所选对象的每个点,采用我们在上面确定的原点,而不是它们各自的原点。因此,它们的中心都会移动并且它们的大小也会发生变化。如果您有 "Center and radius" 种圆类型,则需要将半径调整为调整大小百分比的一半等...
这样,您将获得漂亮而平滑的调整大小,就像您选择的对象是图像的一部分并且您正在调整图像大小一样。
注意:每次移动都必须将调整大小应用于所选对象的原始点,直到调整大小结束,否则浮点错误会累积并使对象稍微错位。
I did following for Diameter circle and Radius circle to solve my issue.
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]; }
}
我正在 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);
}
}
假设有这个 MyShapes
class,派生自 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个不同的Shapes作为例子,你可以添加更多。
此 class 的每个形状都必须处理 MouseEnter
事件并使用 AdornerLayer.GetAdornerLayer()
方法添加自定义装饰器。我用了 msdn example:
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);
}
}
如你所见,除了我提供的msdnlink中说明的必需部分(如OnRender()
等),你还应该更改一些其他内容。
首先,在构造函数中发送 Canvas
的实例,因为我们要更改其子项的大小。其次,你应该处理不同的鼠标事件。
处理 MouseEnter
事件以将光标设置为适当的形状。见方法 getMousePosition(...)
.
处理 MouseLeave
事件以从 AdornerElement
手柄 PreviewMouseLeftButtonDown
设置拖动的开始。
句柄PreviewMouseLeftButtonUp
设置拖动结束。
处理 PreviewMouseMove
以确定元素的新大小和位置。这部分可能有点棘手,因为在某些情况下您应该更改形状的宽度和高度,在其他情况下更改 Canvas.Left 和 Canvas.Top 属性,在其余情况下两者都更改。
首先,您需要确定一个参考点,即整个选区调整大小的原点。它很可能是 "all selected objects are equal" 模式的边界矩形的一个角,或者 "many selected but one active" 模式的活动对象的一个角。
然后,确定鼠标移动时调整大小的百分比,并将相同百分比的调整大小应用于所选对象的每个点,采用我们在上面确定的原点,而不是它们各自的原点。因此,它们的中心都会移动并且它们的大小也会发生变化。如果您有 "Center and radius" 种圆类型,则需要将半径调整为调整大小百分比的一半等...
这样,您将获得漂亮而平滑的调整大小,就像您选择的对象是图像的一部分并且您正在调整图像大小一样。
注意:每次移动都必须将调整大小应用于所选对象的原始点,直到调整大小结束,否则浮点错误会累积并使对象稍微错位。
I did following for Diameter circle and Radius circle to solve my issue.
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]; }
}