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

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

问题描述

我想这是很好的问题,所以我会在细节我想实现什么,我发现在互联网上写,我展示一下我到目前为止做什么,我已经试过。

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.

下面是样本UI:

在这里输入的形象描述

和这里的用法我现在:

你可以看到,我能拖四象之一,其放到列表框项目。
。如果我移动图像过正确的目标(列表框图像)图像附近光标消失,一切工作正常,但是当我不能在列表项(我松开鼠标)的形象在屏幕上停留。拖放图片

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)

我的XAML看起来像这样

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>

和后面的代码:

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



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

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

  • http://nonocast.cn/adorner-in-wpf-part-5-drag-and-drop/
  • 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)。第三环节是有前途的,但我不能将它采纳我的需求。

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.

所以我的问题是:


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

  2. 显示我用的Adorner哪有我用它在我的代码?我需要显示它的时候,我开始拖动和隐藏,当我正确滴图像或我取消拖动或下降的目标是不正确

我初始的M与WPF所以请理解我沮丧 - 我去年花两个晚上和夜间试图让这个工作。

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)修改OnMouseTouchDown处理程序,以包括分配ContinueDragHandler来拖动项目开始拖动,这样

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

和处理程序本身:

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



2)我认为,创建一个新的窗口来显示旁边的一个光标图像是一个肮脏的黑客。有大量的各种物品的有关使用装饰器与拖放左右。 Althought你的方法可行,并不需要大量的代码。装饰器做的,另一方面。我认为你应该创建一个问题,如果你不遵循一定的教程,用代码示例和什么步骤你拿了

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拖放与装饰器使用鼠标和触控的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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