punker76 / gong-wpf-dragdrop

The GongSolutions.WPF.DragDrop library is a drag'n'drop framework for WPF
BSD 3-Clause "New" or "Revised" License
2.28k stars 399 forks source link

Canvas MouseMove event not firing when dragging items over canvas. #245

Closed theitdejan closed 5 years ago

theitdejan commented 7 years ago

What steps will reproduce this issue?

I've written a custom CanvasMouseBehavior, which implements Interactivity.Behavior. It tracks mouse position while moving within the control (in this case- Canvas) - and it works good when i'm just using mouseover. When I start Dragging item, Mouse X and Mouse Y is no longer getting updated on Canvas MouseOver. Debugging it, it's not entering the Behavior anymore.

<Canvas
        dd:DragDrop.DropHandler="{Binding CanvasDragDrop}"
        dd:DragDrop.IsDropTarget="True"
        dd:DragDrop.UseDefaultDragAdorner="True"
        Background="{DynamicResource WhiteBrush}">
        <i:Interaction.Behaviors>
             <behaviours:CanvasMouseBehaviour MouseX="{Binding MouseX, Mode=OneWayToSource}" MouseY="{Binding MouseY, Mode=OneWayToSource}" />
        </i:Interaction.Behaviors>
</Canvas>

I've tried adding AllowDrop=True but it changed nothing.

IDropTarget is implemented in separate class CanvasDragDrop which is referenced in ViewModel : public CanvasDragDrop CanvasDragDrop { get; set; }

Expected outcome

MouseOver should be properly detected even when dragging items over Canvas.

Repo

https://github.com/punker76/gong-wpf-dragdrop

Environment

punker76 commented 7 years ago

@Desomph I need 2 things... can you create a short sample with your Behavior in there and second, can you try latest source (self compiled)? Thx.

theitdejan commented 7 years ago

@punker76 Sorry for so much code, but I've added it because I believe there's another issue: I cannot drop on top of items that are nested in Canvas, in this case: GroupBox. If you need an actually short sample, I'll try mashing up one a bit later. Don't wanna waste your time. I've added some labels for you to see. I've rebuilt the dll's from the source, and referenced the newly built ones in my project. Everything is done through the MVVM.

Note I forgot: I'm using Canvas within a SimpleChildWindow, your other project. https://github.com/punker76/MahApps.Metro.SimpleChildWindow

Here's a short gif/video preview: https://gfycat.com/ImaginaryMajesticBarnswallow

So here's the behavior class:

    public class CanvasMouseBehaviour : System.Windows.Interactivity.Behavior<Canvas>
    {
        public static readonly DependencyProperty MouseYProperty = DependencyProperty.Register(
            "MouseY", typeof(double), typeof(CanvasMouseBehaviour), new PropertyMetadata(default(double)));

        public double MouseY
        {
            get { return (double)GetValue(MouseYProperty); }
            set { SetValue(MouseYProperty, value); }
        }

        public static readonly DependencyProperty MouseXProperty = DependencyProperty.Register(
            "MouseX", typeof(double), typeof(CanvasMouseBehaviour), new PropertyMetadata(default(double)));

        public double MouseX
        {
            get { return (double)GetValue(MouseXProperty); }
            set { SetValue(MouseXProperty, value); }
        }

        protected override void OnAttached()
        {
            AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
        }

        private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
        {
            var pos = mouseEventArgs.GetPosition(AssociatedObject);
            MouseX = pos.X;
            MouseY = pos.Y;
        }

        protected override void OnDetaching()
        {
            AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
        }
    }

Here's the SimpleChildWindow view (important part) :

<ItemsControl ItemsSource="{Binding DcCanvasFields}">
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <Canvas
                  dd:DragDrop.DropHandler="{Binding FlowScreenCreationCanvasDragDrop}"
                  dd:DragDrop.IsDropTarget="True"
                  dd:DragDrop.UseDefaultDragAdorner="True"
                  Background="Wheat">
                <i:Interaction.Behaviors>
                  <behaviours:CanvasMouseBehaviour MouseX="{Binding InnerMouseX, Mode=OneWayToSource}" MouseY="{Binding InnerMouseY, Mode=OneWayToSource}" />
                </i:Interaction.Behaviors>
              </Canvas>
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>

          <!--  ReSharper disable Xaml.BindingWithContextNotResolved  -->
          <ItemsControl.ItemContainerStyle>
            <Style TargetType="{x:Type ContentPresenter}">
              <Setter Property="Canvas.Left" Value="{Binding X}" />
              <Setter Property="Canvas.Top" Value="{Binding Y}" />
            </Style>
          </ItemsControl.ItemContainerStyle>
          <!--  ReSharper restore Xaml.BindingWithContextNotResolved  -->

          <ItemsControl.ItemTemplateSelector>
            <customControl:FlowScreenFieldTemplateSelector>

              <!--  GROUP BOX TEMPLATE  -->
              <customControl:FlowScreenFieldTemplateSelector.GroupBoxTemplate>
                <DataTemplate>
                  <GroupBox
                      Width="{Binding Width}"
                      Height="{Binding Height}"
                      d:DataContext="{d:DesignInstance Type=dataCollection1:DcCanvasFlowScreenField,
                                                       IsDesignTimeCreatable=False}"
                      dd:DragDrop.DropHandler="{Binding DataContext.FlowScreenCreationGroupBoxDragDrop, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
                      dd:DragDrop.IsDropTarget="True"
                      dd:DragDrop.UseDefaultDragAdorner="True"
                      Background="{DynamicResource WhiteBrush}"
                      Header="{Binding Label}">
                    <Label Content="{Binding Label}" />
                  </GroupBox>
                </DataTemplate>
              </customControl:FlowScreenFieldTemplateSelector.GroupBoxTemplate>

              <!--  REGULAR FIELD TEMPLATE  -->
              <customControl:FlowScreenFieldTemplateSelector.FieldTemplate>
                <DataTemplate />
              </customControl:FlowScreenFieldTemplateSelector.FieldTemplate>

           </customControl:FlowScreenFieldTemplateSelector>
      </ItemsControl.ItemTemplateSelector>
</ItemsControl>

DropHandler is bound to this property in ViewModel:

 public FlowScreenCreationCanvasDragDrop FlowScreenCreationCanvasDragDrop { get; set; }

And at the end, I've implemented IDropTarget, which calls ViewModel for the drop implementation:

    public class FlowScreenCreationCanvasDragDrop : IDropTarget
    {
        private DataCollectionViewModel Base { get; set; }

        public FlowScreenCreationCanvasDragDrop(DataCollectionViewModel baseref)
        {
            Base = baseref;
        }

        public void DragOver(IDropInfo dropInfo)
        {
            dropInfo.DropTargetAdorner = typeof(DropTargetHighlightAdorner);
            dropInfo.Effects = DragDropEffects.Move;
        }

        public void Drop(IDropInfo dropInfo)
        {
            Base.FlowScreenCanvasDropFn(dropInfo);
        }
    }
punker76 commented 7 years ago

@Desomph Did you tried to use PreviewMouseMove at the CanvasMouseBehaviour instead normal one?

theitdejan commented 7 years ago

@punker76 I just tried swapping between PreviewMouseMove and MouseMove, on separate canvas and it still didn't work. Which is weird, because I remember it working at first, but nothing changed on my code part.

punker76 commented 7 years ago

@Desomph I'll try to find out what's the problem is...

theitdejan commented 7 years ago

@punker76 Thanks a lot! Let me know if you come up with a solution so I can stop hacking things.

punker76 commented 5 years ago

@Desomph Sorry to keep you waiting so long, but I need more info or better a simple sample app where I can debug this issue. With the latest alpha you can now set which events shouls be used #300