WPF Drop 事件触发两次

WPF Drop event is firing twice

第二次编辑

所以从控件模板中删除 Panel.ZIndex 属性为我解决了这个问题,给了我 1 个放置事件。 包括它们会触发两个放置事件。 任何人都可以回答我为什么吗? 我很想知道为什么 z 索引?

原题:

我正在尝试将自定义对象(状态)添加到 MainWindow 上名为 MainCanvas 的 canvas。 我正在尝试将状态对象从环绕面板拖放到 canvas.

代码有效,但添加了两项。 我知道有两个,因为我可以在 canvas.

周围移动这两个项目

我搜索了现有答案并添加了 e.Handled=true,但仍然添加了两项 我尝试在 MainCanvas 上使用 Drop 事件和 PreviewDrop 事件,没有区别。

请教我如何才能只添加 1 件商品?

maincanvas 在设计时存在 在运行时在放置事件时创建一个新状态。

这是状态的 OnMouseMove 处理程序

protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        var parent = VisualTreeHelper.GetParent(this);
        if (parent as WrapPanel != null)
        {
            DataObject dragData = new DataObject();
            dragData.SetData(DataFormats.StringFormat, this.ItemType);
            DragDrop.DoDragDrop(this, dragData, DragDropEffects.Copy);
            

        }
    }
    e.Handled = true;
}

在代码隐藏中,我为 canvas 设置了以下事件:

private void MainCanvas_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.Text))

        e.Effects = DragDropEffects.Copy;
    else
        e.Effects = DragDropEffects.None;
    e.Handled = true;
}

private void MainCanvas_Drop(object sender, DragEventArgs e)
{
    var itemType = e.Data.GetData(typeof(string));

    switch (itemType)
    {
        case "state":
            var pos = e.GetPosition(this.MainCanvas);
            State item = new State();
            item.Template = (ControlTemplate)FindResource("StateViewModelControlTemplate");
            this.MainCanvas.Children.Add(item);
            Canvas.SetLeft(item, pos.X);
            Canvas.SetTop(item, pos.Y);
            e.Handled = true;
            break;

        default:
            break;
    }
    e.Handled = true;
}

最后是 xaml 主 Canvas

<Canvas x:Name="MainCanvas" x:Name="MainCanvas"
                                    DockPanel.Dock="Top" 
                                    Background="#666" 
                                    Height="600" 
                                    Margin="4" 
                                    AllowDrop="True" 
                                    DragEnter="MainCanvas_DragEnter" 
                                    Drop="MainCanvas_Drop"/>

编辑:

好的,在狼疮的回应之后,我回去并在一个单独的临时项目中从头开始重建所有内容

<ControlTemplate x:Key="StateViewModelControlTemplate" TargetType="{x:Type vm:State}">
    <Grid Width="100" Height="60">
    
    <!--
    If I comment out the following Thumb 
    the drop event will only trigger once
    If i leave it in then it triggers twice
    
    Move Thumb is derived from thumb
    -->
        <local:MoveThumb Panel.ZIndex="99"
                         x:Name="StateViewModelMoveThumb" 
                         DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" 
                         Opacity="0"/>

        <Border Panel.ZIndex="98" 
                Margin="4" 
                Padding="4" 
                BorderBrush="white" 
                BorderThickness="2" 
                CornerRadius="5">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF59C7D4" Offset="0.5"/>
                    <GradientStop Color="#FF075A64" Offset="0"/>
                    <GradientStop Color="#FF00626E" Offset="1"/>
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding StateName}"/>
        </Border>
    </Grid>

</ControlTemplate>

顺便说一句,我尝试做的事情非常松散地基于以下文章:https://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part-1

我试过你的代码,但我无法重现你的问题。变化:

private void MainCanvas_Drop(object sender, DragEventArgs e)
{
 var itemType = e.Data.GetData(typeof(string));

 switch (itemType)
 {
      var pos = e.GetPosition(this.MainCanvas);
      Border item = new Border()
      {
            Width = 10,
            Height = 10,
            Background = Brushes.Red
      };
      //item.Template = (ControlTemplate)FindResource("StateViewModelControlTemplate");
      this.MainCanvas.Children.Add(item);
        ...
}

protected override void OnMouseMove(MouseEventArgs e)
{
  base.OnMouseMove(e);
  if (e.LeftButton == MouseButtonState.Pressed)
  {
        DataObject dragData = new DataObject();
        dragData.SetData(DataFormats.StringFormat, "state");
        DragDrop.DoDragDrop(this, dragData, DragDropEffects.Copy);
  }
  e.Handled = true;
}

并在 xaml、

<Window ...
        Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.ColumnDefinitions>
         <ColumnDefinition Width="*"/>
         <ColumnDefinition Width="*"/>
     </Grid.ColumnDefinitions>
     <Canvas x:Name="MainCanvas" Grid.Column="0"
             DockPanel.Dock="Top" 
             Background="#666" 
             Height="600" 
             Margin="4" 
             AllowDrop="True" 
             DragEnter="MainCanvas_DragEnter" 
             Drop="MainCanvas_Drop"/>

     <Grid Grid.Column="1" Background="Red"/>
</Grid>

没有接触其他代码。每次我从网格拖动到 Canvas,我都会在放置位置得到一个边框项目。

所以问题可能不在您发布的代码中,而在遗漏或注释的代码中。

所以我最终成功了,方法如下

这里是主窗口xaml的前端

    <cc:DiagramCanvas x:Name="MainCanvas"                         
                        DockPanel.Dock="Top" 
                        Margin="0" 
                        MinHeight="450"
                        AllowDrop="True" Background="White">
                </cc:DiagramCanvas>

这是自定义 canvas 对象和拖放处理程序

    public class DiagramCanvas : Canvas
    {
        public DiagramCanvas()
        {
            this.Drop += DoDrop;
            this.DragEnter += MainCanvas_DragEnter;
        }

        readonly MainWindow mainWin = (MainWindow)Application.Current.MainWindow;

        #region works dont touch
        public void DoDrop(object sender, DragEventArgs e)
        {
            var mainWin = (MainWindow)App.Current.MainWindow;
            DragDropHandler<StateVM>.Instance.Drop(sender, e);
        }


        private void MainCanvas_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))

                e.Effects = DragDropEffects.Copy;
            else
                e.Effects = DragDropEffects.None;
            e.Handled = true;
        }
        #endregion
    //other code here
    }

这是拖放处理程序单例

    public sealed class DragDropHandler<T> where T : Control
    {
        #region singleton
        private static DragDropHandler<T> instance = null;
        private static readonly object padlock = new object();

        DragDropHandler()
        {

        }


        public static DragDropHandler<T> Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new DragDropHandler<T>();
                    }
                    return instance;
                }
            }
            private set
            {
                instance = value;
            }
        }
        #endregion

        public static bool IsDragging { get; set; }
        public static WrapPanel AllowedDragSource { get; set; }
        readonly MainWindow mainWin = (MainWindow)Application.Current.MainWindow;


        public static void CreateInstance(WrapPanel allowedSource)
        {
            if (DragDropHandler<T>.IsDragging == false)
            {
                instance = new DragDropHandler<T>();
                DragDropHandler<T>.AllowedDragSource = allowedSource;
            }
        }

        public void Drag(object sender, MouseEventArgs e)
        {
            if (sender as T == null
                || mainWin.Radio_EditStates.IsChecked == false
                || e.LeftButton != MouseButtonState.Pressed
                || IsDragging == true)
            {
                e.Handled = true;
                return;
            }

            var item = (T)sender;

            if (Control.ReferenceEquals(item.Parent, AllowedDragSource) == false)
            {
                e.Handled = true;
                return;
            }

            IsDragging = true;
            DragDrop.DoDragDrop(((StateVM)sender), new DataObject(((StateVM)sender)), DragDropEffects.Copy);
            IsDragging = false;

            e.Handled = true;
        }

        public void Drop(object sender, DragEventArgs e)
        {
            var mainWin = (MainWindow)App.Current.MainWindow;

            if (IsDragging)
            {
                //TODO: Switch here to handle different shapes               

                var pos = e.GetPosition(mainWin.MainCanvas);
                //
                




                Canvas.SetLeft(item, pos.X.RoundDownTo10());
                Canvas.SetTop(item, pos.Y.RoundDownTo10());
                //update  main win observalbe collections to inclue the item dropped
                
                IsDragging = false;
                e.Handled = true;
                DestroyInstance();
            }
        }

        private static void DestroyInstance()
        {
            DragDropHandler<T>.Instance = null;
        }
    }

这是您正在拖动的项目的鼠标移动代码

    protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (e.LeftButton == MouseButtonState.Pressed && Control.ReferenceEquals(this.Parent, mainWin.libraryContainer))
            {
                DragDropHandler<StateVM>.CreateInstance(mainWin.libraryContainer);
                if (DragDropHandler<StateVM>.Instance != null)
                {
                    DragDropHandler<StateVM>.Instance.Drag(this, e);
                }

            }
        }