【问题标题】:WPF Drop event is firing twiceWPF Drop 事件触发两次
【发布时间】:2020-07-18 22:39:32
【问题描述】:

第二次编辑

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

原始问题:

我正在尝试将自定义对象(状态)添加到 MainWindow 上名为 MainCanvas 的画布。 我正在尝试将状态对象从包装面板中拖放到画布上。

代码有效,但添加了两个项目。 我知道有两个,因为我可以在画布上移动这两个项目。

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

有人帮忙看看我如何才能做到只添加 1 个项目?

主画布在设计时存在 在运行时的 drop 事件中会创建一个新状态。

这里是状​​态的 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;
}

在后面的代码中,我为画布设置了以下事件:

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 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

【问题讨论】:

  • 你有没有想过这个问题?我们遇到了两次触发 TabControl 的 Drop 事件,其中我已将 drop 事件专门放置在一个元素上(并且没有其他 drop 处理程序)。 TabPanel 有一个 ZIndex 属性集,我尝试删除它,但它并没有像你的那样解决
  • 这是很久以前的事了,但从记忆来看,这是 drop 和 preview drop 之间的区别......以及每个事件的传播方式不同......我让代码工作......但我'm onlyba hobby coder,这是很久以前的事了......我找到它并回复你。
  • 我找到了有问题的代码并添加了我自己的答案,希望下面的代码对您有所帮助

标签: wpf xaml events drag-and-drop event-handling


【解决方案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>

没有接触过另一段代码。每次我从 Grid 拖动到 Canvas 时,我都会在放置位置获得一个 Border 项目。

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

【讨论】:

    【解决方案2】:

    所以我最终得到了这个工作,这是如何工作的

    这是主窗口上的前端 xaml

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      相关资源
      最近更新 更多