有很多针对WPF的Resizing Adorner样本,但是我没有找到一个适合使用简单Line的样本......显然我希望控制点出现在两端线条,而不是围绕它形成一个矩形。有人跑过这样的事吗?
答案 0 :(得分:3)
我的Line Adorner实现,您可以移动起点和终点或移动线(当前已注释)。
public class LineAdorner : Adorner
{
bool IsStartPoint = false;
bool IsControlModeOn = false;
Size size = new Size(10, 10);
SnapToGrid snap = new SnapToGrid();
public LineAdorner(UIElement adornedElement)
: base(adornedElement)
{
this.MouseLeftButtonDown += new MouseButtonEventHandler(LineAdorner_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseButtonEventHandler(LineAdorner_MouseLeftButtonUp);
this.MouseMove += new MouseEventHandler(LineAdorner_MouseMove);
}
void LineAdorner_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control)
IsControlModeOn = true;
Line line = this.AdornedElement as Line;
LineItem lineItem = line.DataContext as LineItem;
Point p = snap.Snap(e.GetPosition(line), SnapToGrid.SnapMode.Move);
double dStart = 0.0;
double dEnd = 0.0;
if (!this.IsMouseCaptured)
{
dStart = Math.Sqrt(Math.Pow(lineItem.StartPoint.X - p.X, 2) + Math.Pow(lineItem.StartPoint.Y - p.Y, 2));
dEnd = Math.Sqrt(Math.Pow(lineItem.EndPoint.X - p.X, 2) + Math.Pow(lineItem.EndPoint.Y - p.Y, 2));
}
if (IsControlModeOn)
{
if (this.IsMouseCaptured)
{
if (IsStartPoint)
lineItem.StartPoint = p;
else
lineItem.EndPoint = p;
this.InvalidateVisual();
this.ReleaseMouseCapture();
IsControlModeOn = false;
}
else
{
if (dStart < dEnd)
IsStartPoint = true;
else
IsStartPoint = false;
this.InvalidateVisual();
this.CaptureMouse();
}
}
else
{
if (!this.IsMouseCaptured)
{
if (dStart < dEnd)
IsStartPoint = true;
else
IsStartPoint = false;
this.InvalidateVisual();
this.CaptureMouse();
}
}
}
void LineAdorner_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!IsControlModeOn)
{
if (this.IsMouseCaptured)
{
Line line = this.AdornedElement as Line;
LineItem lineItem = line.DataContext as LineItem;
Point p = snap.Snap(e.GetPosition(line), SnapToGrid.SnapMode.Move);
if (IsStartPoint)
lineItem.StartPoint = p;
else
lineItem.EndPoint = p;
this.InvalidateVisual();
this.ReleaseMouseCapture();
}
}
}
void LineAdorner_MouseMove(object sender, MouseEventArgs e)
{
if (this.IsMouseCaptured)
{
if (this.AdornedElement.GetType() == typeof(Line))
{
Line line = this.AdornedElement as Line;
LineItem lineItem = line.DataContext as LineItem;
Point p = snap.Snap(e.GetPosition(line), SnapToGrid.SnapMode.Move);
// mode: move start or end point
//*
if (IsStartPoint)
lineItem.StartPoint = p;
else
lineItem.EndPoint = p;
//*/
// mode: move line
/*
if (IsStartPoint)
{
double dX = lineItem.StartPoint.X - p.X;
double dY = lineItem.StartPoint.Y - p.Y;
Point pEnd = new Point(lineItem.EndPoint.X - dX, lineItem.EndPoint.Y - dY);
lineItem.StartPoint = p;
lineItem.EndPoint = pEnd;
}
else
{
double dX = lineItem.EndPoint.X - p.X;
double dY = lineItem.EndPoint.Y - p.Y;
Point pStart = new Point(lineItem.StartPoint.X - dX, lineItem.StartPoint.Y - dY);
lineItem.EndPoint = p;
lineItem.StartPoint = pStart;
}
*/
this.InvalidateVisual();
}
}
}
protected override void OnRender(DrawingContext drawingContext)
{
if (this.AdornedElement.GetType() == typeof(Line))
{
Line line = this.AdornedElement as Line;
LineItem lineItem = line.DataContext as LineItem;
SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
SolidColorBrush penBrush = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
Pen pen = new Pen(penBrush, 1.0);
Point p1 = new Point(lineItem.StartPoint.X, lineItem.StartPoint.Y);
Point p2 = new Point(lineItem.EndPoint.X, lineItem.EndPoint.Y);
p1.Offset(-size.Width / 2, -size.Height / 2);
p2.Offset(-size.Width / 2, -size.Height / 2);
Rect r1 = new Rect(p1, size);
Rect r2 = new Rect(p2, size);
double halfPenWidth = pen.Thickness / 2;
GuidelineSet g1 = new GuidelineSet();
g1.GuidelinesX.Add(r1.Left + halfPenWidth);
g1.GuidelinesX.Add(r1.Right + halfPenWidth);
g1.GuidelinesY.Add(r1.Top + halfPenWidth);
g1.GuidelinesY.Add(r1.Bottom + halfPenWidth);
drawingContext.PushGuidelineSet(g1);
drawingContext.DrawRectangle(brush, pen, r1);
drawingContext.Pop();
GuidelineSet g2 = new GuidelineSet();
g2.GuidelinesX.Add(r2.Left + halfPenWidth);
g2.GuidelinesX.Add(r2.Right + halfPenWidth);
g2.GuidelinesY.Add(r2.Top + halfPenWidth);
g2.GuidelinesY.Add(r2.Bottom + halfPenWidth);
drawingContext.PushGuidelineSet(g2);
drawingContext.DrawRectangle(brush, pen, r2);
drawingContext.Pop();
}
base.OnRender(drawingContext);
}
}
这里是用于捕捉Point的SnapToGrid类(如果不需要,可以从代码中删除)。
class SnapToGrid
{
private Size gridSizeModeCreate = new Size(13.5, 13.5);
private Size gridSizeModeMove = new Size(13.5, 13.5);
private double gridOffsetX = -1.0;
private double gridOffsetY = -1.0;
public enum SnapMode
{
Create,
Move,
Line
}
public Size GridSizeModeCreate
{
get { return gridSizeModeCreate; }
set
{
gridSizeModeCreate = value;
}
}
public Size GridSizeModeMove
{
get { return gridSizeModeMove; }
set
{
gridSizeModeMove = value;
}
}
public double GridOffsetX
{
get { return gridOffsetX; }
set
{
gridOffsetX = value;
}
}
public double GridOffsetY
{
get { return gridOffsetY; }
set
{
gridOffsetY = value;
}
}
private Point Calculate(Point p, Size s)
{
double snapX = p.X + ((Math.Round(p.X / s.Width) - p.X / s.Width) * s.Width);
double snapY = p.Y + ((Math.Round(p.Y / s.Height) - p.Y / s.Height) * s.Height);
return new Point(snapX + gridOffsetX, snapY + gridOffsetY);
}
public Point Snap(Point p, SnapMode mode)
{
if (mode == SnapMode.Create)
return Calculate(p, gridSizeModeCreate);
else if (mode == SnapMode.Move)
return Calculate(p, gridSizeModeMove);
else
return new Point(0, 0);
}
}
以下是模型对象:
public class LineItem : NotifyObject
{
private Point startPoint;
private Point endPoint;
public Point StartPoint
{
get
{
return startPoint;
}
set
{
if (startPoint != value)
{
startPoint = value;
OnPropertyChanged("StartPoint");
}
}
}
public Point EndPoint
{
get
{
return endPoint;
}
set
{
if (endPoint != value)
{
endPoint = value;
OnPropertyChanged("EndPoint");
}
}
}
}
public class NotifyObject : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged(string propertyChanged)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyChanged));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}