WPF中实现拖动功能和WinForm中实现的功能有所差异,这里简单介绍下WPF中的拖拽的实现逻辑!
实现拖拽功能,主要包含以下几个步骤:
- 需要拖入到的控件中,设置
AllowDrop="True"
- 需要拖入到的控件中,注册
Drop
事件,在该事件中,将拖动到该控件中的数据进行处理。获取数据的方法:e.Data.GetData(typeof(MyClass))
; - 在拖动的控件,注册
PreviewMouseMove
事件,在该事件中,启动拖拽行为:DragDrop.DoDragDrop
。在设置移动的过程中,因为MouseUp事件会在Drag过程中被吞掉,所以PreviewMouseUp事件不会被触发。为了解决拖动时,鼠标移动触发拖拽情况,只需要在PreviewMouseMove
事件中加上e.LeftButton == MouseButtonState.Pressed
即可。 - 如果需要将拖动的对象,跟随鼠标移动,可以将被拖动元素以自定义
Adorner
的方式,添加到该元素下的AdornerLayer
中。将拖动元素以VisualBrush
的方式赋值给Adorner
。并在GiveFeedback
事件中更新坐标位置。
示例代码:
//定义个自定义的Adorner
DefaultAdorner adorner;
//当鼠标拖入到控件中,并释放鼠标时发生
private void FrameworkElement_Drop(object sender, DragEventArgs e)
{
var data = (MyClass)e.Data.GetData(typeof(MyClass));
//todo:
}
//当鼠标按下,开始移动时开始拖拽
private void FrameworkElement_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
//添加Adorner到AdornerLayer
adorner = new DefaultAdorner((UIElement)Application.Current.MainWindow.Content,(UIElement)this._dragDropObject.SourceObject,this._dragDropObject.StartPosition);
System.Windows.Media.Visual visual = Application.Current.MainWindow.Content as Visual;
AdornerLayer.GetAdornerLayer(visual).Add(this._dragDropObject.DragAdorner);
//开始拖动
DragDrop.DoDragDrop(frameworkElement, data, DragDropEffects.Move);
}
}
private void DragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
//设置移动Adorner的位置
adorner.SetMousePosition(dragAdorner.AdornedElement.PointFromScreen(point));
}
//DefaultAdorner定义
public class DefaultAdorner : Adorner
{
private UIElement _child;
private Point _adornerOrigin;
private Point _adornerOffset;
public DefaultAdorner(UIElement adornedElement, UIElement adornerElement, Point adornerOrigin)
: this(adornedElement, adornerElement, adornerOrigin, 0.3)
{
}
//将需要拖动的元素附加到Adorner
public DefaultAdorner(UIElement adornedElement, UIElement adornerElement, Point adornerOrigin, double opacity)
: base(adornedElement)
{
Rectangle rect = new Rectangle();
rect.Width = adornerElement.RenderSize.Width;
rect.Height = adornerElement.RenderSize.Height;
VisualBrush visualBrush = new VisualBrush(adornerElement);
visualBrush.Opacity = opacity;
visualBrush.Stretch = Stretch.None;
rect.Fill = visualBrush;
this._child = rect;
this._adornerOrigin = adornerOrigin;
}
public void SetMousePosition(Point position) {
this._adornerOffset.X = position.X - this._adornerOrigin.X;
this._adornerOffset.Y = position.Y - this._adornerOrigin.Y;
UpdatePosition();
}
//重绘
private void UpdatePosition() {
AdornerLayer adornerLayer = (AdornerLayer)this.Parent;
if(adornerLayer != null) {
adornerLayer.Update(this.AdornedElement);
}
}
protected override int VisualChildrenCount { get { return 1; } }
protected override Visual GetVisualChild(int index) {
System.Diagnostics.Debug.Assert(index == 0, "Index must be 0, there's only one child");
return this._child;
}
protected override Size MeasureOverride(Size finalSize) {
this._child.Measure(finalSize);
return this._child.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize) {
this._child.Arrange(new Rect(finalSize));
return finalSize;
}
//通过变换,更改移动位置
public override GeneralTransform GetDesiredTransform(GeneralTransform transform) {
GeneralTransformGroup newTransform = new GeneralTransformGroup();
newTransform.Children.Add(base.GetDesiredTransform(transform));
newTransform.Children.Add(new TranslateTransform(this._adornerOffset.X, this._adornerOffset.Y));
return newTransform;
}
}
以上就是拖动功能实现的主题思路,按照以上思路可对拖动操作做一层封装,简化拖动功能实现的复杂度。
本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/WPF%E6%8B%96%E5%8A%A8%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。