【问题标题】:wpf Drag and Drop at exact mouse locationwpf拖放到确切的鼠标位置
【发布时间】:2016-10-19 04:05:19
【问题描述】:

我有一个 ListBox 和一个 Canvas。我想将 ListBoxItem 拖到画布上,正好放在鼠标所在的位置。这是我的 xaml。问题是无论鼠标位置如何,这些项目都被放置在其他项目之上。如何根据画布上的鼠标指针将拖动的项目放置在确切的位置。请帮忙。

<DockPanel LastChildFill="True" >
        <ListBox DockPanel.Dock="Left" Name="lstLabels">
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListBoxItem_PreviewMouseLeftButtonDown"/>
                    <EventSetter Event="PreviewMouseMove" Handler="ListBoxItem_PreviewMouseMove"/>

                </Style>
            </ListBox.Resources>
            <ListBoxItem>A</ListBoxItem>
            <ListBoxItem>B</ListBoxItem>
            <ListBoxItem>C</ListBoxItem>
            <ListBoxItem>D</ListBoxItem>
            <ListBoxItem>E</ListBoxItem>
            <ListBoxItem>F</ListBoxItem>
            <ListBoxItem>G</ListBoxItem>
            <ListBoxItem>H</ListBoxItem>
        </ListBox>
        <Canvas AllowDrop="True" Background="Azure"
                DragEnter="cvsSurface_DragEnter" Drop="cvsSurface_Drop" 
                Name="cvsSurface" >
        </Canvas>
    </DockPanel>

这是我完整的cs代码

 private ListBoxItem draggedItem;
 private Point startDragPoint;
private void cvsSurface_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
        }
        private void cvsSurface_Drop(object sender, DragEventArgs e)
        {
            Label newLabel = new Label();
            newLabel.Content = e.Data.GetData(DataFormats.Text);

            cvsSurface.Children.Add(newLabel);
            Canvas.SetLeft(newLabel, 100);
            Canvas.SetTop(newLabel, 200);

            draggedItem = null;
            lstLabels.SelectedItem = null;
        }
        private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            draggedItem = sender as ListBoxItem;
            startDragPoint = e.GetPosition(null);
        }
        private void ListBoxItem_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            Point position = e.GetPosition(null);
            if (draggedItem != null)
            {
                DragDrop.DoDragDrop(draggedItem, draggedItem.Content, DragDropEffects.Copy);
            }
        }

【问题讨论】:

  • 您的 'dropped' 标签布局位置被硬编码为 {100, 200},您为什么希望它们不会一个接一个地出现?使用DragEventArgs'GetPosition()方法获取Cavas内的相对鼠标点。
  • 对不起,我的坏。正如你所说,我做了 var canvas = sender as Canvas; var positionX = e.GetPosition(canvas).X; var positionY = e.GetPosition(canvas).Y;并作为参数而不是 100 和 200 传递,它工作正常。如果它对某人有帮助,我将保持原样。
  • 一个问题安德鲁。现在让我们说列表框项目是椭圆或矩形。现在在 cvsSurface_Drop 事件中,我说类似 StackPanel p=new StackPanel(); p.Children.Add(e.Data.GetData(DataFormats.Text));现在我该说什么而不是 Text 来添加形状?
  • DragEventArgs.Data 对象有许多方法可以查询哪些格式可用。但是如果你只使用矩形和椭圆,你可以使用像 e.Data.GetData(typeof(Shape)) 这样的东西。尽管如此,我认为您仍需要一些额外的逻辑来重新创建形状,因为您不能只将 UIElement 添加到可视化树中两次。
  • 谢谢 Andrew 我想我需要从可视树中检索形状。当我尝试 UIElement sp = e.Data.GetData(typeof(Shape)) as UIElement; sp 始终为空。所以我需要从visualtree中获取基于id的形状吗?

标签: c# wpf canvas


【解决方案1】:

检查我的 OnDrop 处理程序以将位置分配给标签

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CanvasDragDrop
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private ListBoxItem draggedItem;

        private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            draggedItem = sender as ListBoxItem;

            if (draggedItem != null)
            {
                DragDrop.DoDragDrop(draggedItem, draggedItem.Content, DragDropEffects.Copy);
            }

        }


        private void CvsSurface_OnDragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }

        }

        private void CvsSurface_OnDrop(object sender, DragEventArgs e)
        {
            Object droppedData = e.Data; //This part is not important

        /*Translate Drop Point in reference to Stack Panel*/
            Point dropPoint = e.GetPosition(this.cvsSurface);

            Console.WriteLine(dropPoint); ;
            Label lbl = new Label();
            lbl.Content = draggedItem.Content;
            cvsSurface.Children.Add(lbl);

            Canvas.SetLeft(lbl, dropPoint.X);
            Canvas.SetTop(lbl, dropPoint.Y);

        }



    }
}

你也需要更少的事件

<Window x:Class="CanvasDragDrop.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="True" >
        <ListBox DockPanel.Dock="Left" Name="lstLabels">
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListBoxItem_PreviewMouseLeftButtonDown"/>


                </Style>
            </ListBox.Resources>
            <ListBoxItem>A</ListBoxItem>
            <ListBoxItem>B</ListBoxItem>
            <ListBoxItem>C</ListBoxItem>
            <ListBoxItem>D</ListBoxItem>
            <ListBoxItem>E</ListBoxItem>
            <ListBoxItem>F</ListBoxItem>
            <ListBoxItem>G</ListBoxItem>
            <ListBoxItem>H</ListBoxItem>
        </ListBox>
        <Canvas AllowDrop="True" Background="Azure"
                DragEnter="CvsSurface_OnDragEnter" Drop="CvsSurface_OnDrop" 
                Name="cvsSurface" >
        </Canvas>
    </DockPanel>
</Window>

【讨论】:

  • 谢谢,现在我可以将 dropdata 作为 Object droppedData = e.Data as Shape 添加到 stackpanel;
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
相关资源
最近更新 更多