WPF拖放与Adorner使用鼠标和触摸 [英] WPF Drag and Drop with Adorner using mouse and touch

查看:708
本文介绍了WPF拖放与Adorner使用鼠标和触摸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望这是一个很好的问题,所以我将详细介绍我想要实现的内容,我在互联网上发现了什么,并展示了我迄今为止所做的,以及我曾经尝试过的内容。



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



这里是示例UI:





这里是我现在的用法:





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



我已经根据我的解决方案对这个问题,我无法删除不需要的窗口(靠近游标的图像)



我的XAML看起来像这样:

 < Window x:Class =DragDrop.MainWindow
xmlns =http:// schemas。 $ microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
标题=Drag'n'Drop Height =350Width =525
DataContext ={Binding RelativeSource = {RelativeSource Self}}>
< Grid>
< ListBox Horizo​​ntalAlignment =RightHorizo​​ntalContentAlignment =StretchHeight =300Margin =0,10,10,0VerticalAlignment =TopWidth =234ItemsSource ={Binding People} >
< ListBox.ItemTemplate>
< DataTemplate>
< StackPanel Orientation =VerticalAllowDrop =TruePreviewDrop =UIElement_OnPreviewDrop>
< TextBlock Text ={Binding Name}FontWeight =Bold/>
< ProgressBar Height =20Value ={Binding Points}Margin =0,0,0,0/>
< / StackPanel>
< / DataTemplate>
< /ListBox.ItemTemplate>
< / ListBox>

< Image Horizo​​ntalAlignment =LeftHeight =72Margin =10,10,0,0VerticalAlignment =TopWidth =72Source =Images / coins-60000 -icon.pngRenderTransformOrigin =0.5,0.5
PreviewMouseLeftButtonDown =OnMouseTouchDown
PreviewTouchDown =OnMouseTouchDown
PreviewGiveFeedback =UIElement_OnPreviewGiveFeedbackTag =10/>
< Image Horizo​​ntalAlignment =LeftHeight =72Margin =87,10,0,0VerticalAlignment =TopWidth =72Source =Images / coins-700000-icon.png RenderTransformOrigin =0.5,0.5
PreviewMouseLeftButtonDown =OnMouseTouchDown
PreviewTouchDown =OnMouseTouchDown
PreviewGiveFeedback =UIElement_OnPreviewGiveFeedbackTag =20/>
< Image Horizo​​ntalAlignment =LeftHeight =72Margin =10,87,0,0VerticalAlignment =TopWidth =72Source =Images / coins-7000-icon.png RenderTransformOrigin =0.5,0.5
PreviewMouseLeftButtonDown =OnMouseTouchDown
PreviewTouchDown =OnMouseTouchDown
PreviewGiveFeedback =UIElement_OnPreviewGiveFeedbackTag =30/>
< Image Horizo​​ntalAlignment =LeftHeight =72Margin =87,87,0,0VerticalAlignment =TopWidth =72Source =Images / coins-700-icon.png RenderTransformOrigin =0.5,0.5
PreviewMouseLeftButtonDown =OnMouseTouchDown
PreviewTouchDown =OnMouseTouchDown
PreviewGiveFeedback =UIElement_OnPreviewGiveFeedbackTag =40/>
< / Grid>
< / Window>

代码背后:

  public partial class MainWindow 
{
private readonly ObservableCollection< Person> _people = new ObservableCollection< Person>();

public ObservableCollection< Person> 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);
}

私有窗口_dragdropWindow;

private void CreateDragDropWindow(Visual dragElement)
{
_dragdropWindow = new Window
{
WindowStyle = WindowStyle.None,
AllowTransparency = true ,
AllowDrop = false,
Background = null,
IsHitTestVisible = false,
SizeToContent = SizeToContent.WidthAndHeight,
顶部= 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)]
[返回:MarshalAs(UnmanagedType.Bool)]
内部静态extern bool GetCursorPos (参考Win32Point pt);

[StructLayout(LayoutKind.Sequential)]
内部结构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));
}
}

我在互联网上发现我可以使用类扩展了阿多纳,我发现了一些例子:





但都显示如何拖动一世集合(ItemsControls)。第三个链接是有希望的,但是我根本无法满足我的需要。



所以我的问题是:


  1. 当我取消拖动(MouseUp或不正确的拖动目标)时,如何隐藏我的示例中的小图像窗口

  2. 显示我使用Adorner,如何我在代码中使用它?我需要显示,当我开始拖动和隐藏,当我正确地放下图像或我取消拖放目标是不正确的

从WPF开始,请尝试了解我的沮丧 - 我花了最后两个晚上和晚上试图让这个工作。

解决方案

p> 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)我相信创建一个新的窗口来显示光标旁边的图像是脏肮脏的黑客。有很多关于使用装饰工具的各种文章。虽然你的方法是有效的,不需要很多的代码。另一方面,装饰品做。我想你应该创建另一个问题,如果您按照某些教程失败,代码示例以及您采取的步骤


I want this to be good question, so I'll write in details what I would like to achieve, what I've found on the internet and I show what I've done so far and what I've tried.

I need to add drag and drop functionality to my application. I have Images (basically controls) that I want to drag to items of listbox.

Here is sample UI:

And here is usage I have now:

As You can see I'm able to drag one of four images and drop it over listbox item. If I move image over correct target (listbox image) image near cursor disappears and everything works fine, but when I don't drop image on list item (I release mouse) that image stays on screen.

I've based my solution on answers to this question, and I'm unable to remove that unwanted window (image near cursor)

My XAML looks like this:

<Window x:Class="DragDrop.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Drag'n'Drop" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <ListBox HorizontalAlignment="Right" HorizontalContentAlignment="Stretch" Height="300" Margin="0,10,10,0" VerticalAlignment="Top" Width="234" ItemsSource="{Binding People}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" AllowDrop="True" PreviewDrop="UIElement_OnPreviewDrop">
                        <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                        <ProgressBar Height="20" Value="{Binding Points}" Margin="0,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <Image HorizontalAlignment="Left" Height="72" Margin="10,10,0,0" VerticalAlignment="Top" Width="72" Source="Images/coins-60000-icon.png" RenderTransformOrigin="0.5,0.5"
               PreviewMouseLeftButtonDown="OnMouseTouchDown"
               PreviewTouchDown="OnMouseTouchDown"
               PreviewGiveFeedback="UIElement_OnPreviewGiveFeedback" Tag="10"/>
        <Image HorizontalAlignment="Left" Height="72" Margin="87,10,0,0" VerticalAlignment="Top" Width="72" Source="Images/coins-700000-icon.png" RenderTransformOrigin="0.5,0.5"
               PreviewMouseLeftButtonDown="OnMouseTouchDown"
               PreviewTouchDown="OnMouseTouchDown"
               PreviewGiveFeedback="UIElement_OnPreviewGiveFeedback" Tag="20"/>
        <Image HorizontalAlignment="Left" Height="72" Margin="10,87,0,0" VerticalAlignment="Top" Width="72" Source="Images/coins-7000-icon.png" RenderTransformOrigin="0.5,0.5"
               PreviewMouseLeftButtonDown="OnMouseTouchDown"
               PreviewTouchDown="OnMouseTouchDown"
               PreviewGiveFeedback="UIElement_OnPreviewGiveFeedback" Tag="30"/>
        <Image HorizontalAlignment="Left" Height="72" Margin="87,87,0,0" VerticalAlignment="Top" Width="72" Source="Images/coins-700-icon.png" RenderTransformOrigin="0.5,0.5"
               PreviewMouseLeftButtonDown="OnMouseTouchDown"
               PreviewTouchDown="OnMouseTouchDown"
               PreviewGiveFeedback="UIElement_OnPreviewGiveFeedback" Tag="40"/>
    </Grid>
</Window>

And code behind:

public partial class MainWindow
{
    private readonly ObservableCollection<Person> _people = new ObservableCollection<Person>();

    public ObservableCollection<Person> 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));
    }
}

I found over the internet that I can use class that extends Adorner and I found some examples:

but all of them show how to drag items from collections (ItemsControls). Third link was promising, but I wasn't able to adopt it to my needs.

So my questions are:

  1. How can I hide that small image window in my example when I cancel drag (MouseUp or incorrect drag target)
  2. Show I use Adorner and how can I use it in my code? I need to show it when I start drag and hide when I drop Image correctly or I cancel drag or drop target is incorrect

I'm starting with WPF so please try to understand my frustration - I've spend last two evenings and night trying to get this working.

解决方案

1) Modify your OnMouseTouchDown handler to include assigning ContinueDragHandler to dragged item before starting the drag, like this

 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);
        }

And the handler itself:

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

2) I believe that creating a new window to display image next to a cursor is a dirty dirty hack. There are plenty of various articles around about using adorners with drag'n'drop. Althought your approach works and doesn't require a lot of code. Adorners do, on the other hand. I think you should create another question, if you fail following certain tutorial, with code examples and what steps you took

这篇关于WPF拖放与Adorner使用鼠标和触摸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆