WPF使用鼠标和触摸拖放Adorner

我希望这是一个很好的问题,所以我会详细写下我想要实现的内容,我在互联网上发现的内容,并展示我到目前为止所做的以及我尝试过的内容。

我需要在我的应用程序中添加拖放function。 我有图像(基本上是控件),我想拖动到列表框的项目。

这是示例UI:

在此处输入图像描述

这是我现在的用法:

在此处输入图像描述

正如您所看到的,我可以拖动四个图像中的一个并将其放在列表框项目上。 如果我将图像移动到正确的目标(列表框图像)上,光标附近的图像会消失并且一切正常,但是当我不将图像放在列表项目(我释放鼠标)上时,该图像会停留在屏幕上。

我的解决方案基于这个问题的答案,我无法删除那个不需要的窗口(光标附近的图像)

我的XAML看起来像这样:

                  

和代码背后:

 public partial class MainWindow { private readonly ObservableCollection _people = new ObservableCollection(); public ObservableCollection People { get { return _people; } } public MainWindow() { InitializeComponent(); _people.Add(new Person() {Name = "Person1", Points = 10}); _people.Add(new Person() {Name = "Person2", Points = 0}); _people.Add(new Person() {Name = "Person3", Points = 40}); } private void OnMouseTouchDown(object sender, InputEventArgs e) { var item = sender as Image; if (item == null) return; var draggedItem = item; var points = Convert.ToInt32(draggedItem.Tag); CreateDragDropWindow(draggedItem); System.Windows.DragDrop.DoDragDrop(draggedItem, points, DragDropEffects.Move); } private Window _dragdropWindow; private void CreateDragDropWindow(Visual dragElement) { _dragdropWindow = new Window { WindowStyle = WindowStyle.None, AllowsTransparency = true, AllowDrop = false, Background = null, IsHitTestVisible = false, SizeToContent = SizeToContent.WidthAndHeight, Topmost = true, ShowInTaskbar = false }; Rectangle r = new Rectangle { Width = ((FrameworkElement) dragElement).ActualWidth/2, Height = ((FrameworkElement) dragElement).ActualHeight/2, Fill = new VisualBrush(dragElement) }; _dragdropWindow.Content = r; Win32Point w32Mouse = new Win32Point(); GetCursorPos(ref w32Mouse); _dragdropWindow.Left = w32Mouse.X; _dragdropWindow.Top = w32Mouse.Y; _dragdropWindow.Show(); } [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetCursorPos(ref Win32Point pt); [StructLayout(LayoutKind.Sequential)] internal struct Win32Point { public Int32 X; public Int32 Y; }; private void UIElement_OnPreviewGiveFeedback(object sender, GiveFeedbackEventArgs e) { Win32Point w32Mouse = new Win32Point(); GetCursorPos(ref w32Mouse); _dragdropWindow.Left = w32Mouse.X; _dragdropWindow.Top = w32Mouse.Y; } private void UIElement_OnPreviewDrop(object sender, DragEventArgs e) { //var droppedData = e.Data.GetData(typeof(Image)) as Image; var droppedData = (Int32) e.Data.GetData(typeof (Int32)); var stackPanel = sender as StackPanel; if (stackPanel != null) { var student = stackPanel.DataContext as Person; //int targetIndex = _people.IndexOf(student); if (student != null) student.Points += droppedData; } if (_dragdropWindow != null) { _dragdropWindow.Close(); _dragdropWindow = null; } } } public class Person : INotifyPropertyChanged { private string _name; private int _points; public string Name { get { return _name; } set { if (value == _name) return; _name = value; OnPropertyChanged(); } } public int Points { get { return _points; } set { if (value == _points) return; _points = value; if (_points >= 100) { _points -= 100; Debug.WriteLine("100!"); } OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } 

我通过互联网发现我可以使用扩展Adorner的类,我找到了一些例子:

  • http://nonocast.cn/adorner-in-wpf-part-5-drag-and-drop/ – (WaybackMachine存档链接 )
  • http://www.zagstudio.com/blog/488#.VfiMSBHtmko
  • http://www.infragistics.com/community/blogs/alex_fidanov/archive/2009/07/28/drag-amp-drop-with-datapresenter-family-controls.aspx
  • https://github.com/punker76/gong-wpf-dragdrop

但是所有这些都显示了如何从集合中拖动项目(ItemsControls)。 第三个环节很有希望,但我无法满足我的需求。

所以我的问题是:

  1. 当我取消拖动(MouseUp或不正确的拖动目标)时,如何隐藏我的示例中的小图像窗口
  2. 显示我使用Adorner,我如何在我的代码中使用它? 当我正确地拖动图像或者取消拖放目标不正确时,我需要在开始拖动和隐藏时显示它

我开始使用WPF,所以请尽量了解我的挫败感 – 我花了最后两个晚上试图让这个工作。

1)修改你的OnMouseTouchDown处理程序,包括在开始拖动之前将ContinueDragHandler分配给拖动的项目,就像这样

  private void OnMouseTouchDown(object sender, InputEventArgs e) { var item = sender as FrameworkElement; if (item == null) return; var draggedItem = item; var points = Convert.ToInt32(draggedItem.Tag); CreateDragDropWindow(draggedItem); System.Windows.DragDrop.AddQueryContinueDragHandler(draggedItem, DragContrinueHandler); System.Windows.DragDrop.DoDragDrop(draggedItem, points, DragDropEffects.Move); } 

处理程序本身:

 public void DragContrinueHandler(object sender, QueryContinueDragEventArgs e) { if (e.Action == DragAction.Continue && e.KeyStates != DragDropKeyStates.LeftMouseButton) { _dragdropWindow.Close(); } } 

2)我相信创建一个新窗口来显示光标旁边的图像是一个肮脏的黑客。 关于使用拖放器的装饰器,有很多各种各样的文章。 虽然你的方法有效,但不需要很多代码。 另一方面,Adorners会这样做。 我认为你应该创建另一个问题,如果你没有按照某些教程,使用代码示例和你采取的步骤