WPF ListBox拖放drop干扰ContextMenu?

时间:2009-10-13 08:36:34

标签: wpf listbox drag-and-drop contextmenu

我正在实施拖拽从ListBox中删除,但我在窗口的其他地方看到了ContextMenu的一些奇怪行为。如果打开上下文菜单然后从ListBox开始拖动,则上下文菜单会关闭,但在您执行另一次拖动之前不会再次打开。

这有意义吗?任何人都有任何想法可能会发生什么?

<ListBox Grid.Row="0" ItemsSource="{Binding SourceItems}" MultiSelectListboxDragDrop:ListBoxExtension.SelectedItemsSource="{Binding SelectedItems}" SelectionMode="Multiple" PreviewMouseLeftButtonDown="HandleLeftButtonDown" PreviewMouseLeftButtonUp="HandleLeftButtonUp" PreviewMouseMove="HandleMouseMove"/>
<ListBox Grid.Row="1" ItemsSource="{Binding DestinationItems}" AllowDrop="True" Drop="DropOnToDestination" />
<Button Grid.Row="2">
    <Button.ContextMenu>
        <ContextMenu x:Name="theContextMenu">
            <MenuItem Header="context 1"/>
            <MenuItem Header="context 2"/>
            <MenuItem Header="context 3"/>
        </ContextMenu>
    </Button.ContextMenu>
    Button with context menu
</Button>

...

public partial class Window1
{
    private bool clickedOnSourceItem;

    public Window1()
    {
        InitializeComponent();

        DataContext = new WindowViewModel();
    }

    private void DropOnToDestination(object sender, DragEventArgs e)
    {
        var viewModel = (WindowViewModel)e.Data.GetData(typeof(WindowViewModel));
        viewModel.CopySelectedItems();
    }

    private void HandleLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var sourceElement = (FrameworkElement)sender;
        var hitItem = sourceElement.InputHitTest(e.GetPosition(sourceElement)) as FrameworkElement;

        if(hitItem != null)
        {
            clickedOnSourceItem = true;
        }
    }

    private void HandleLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        clickedOnSourceItem = false;
    }

    private void HandleMouseMove(object sender, MouseEventArgs e)
    {
        if(clickedOnSourceItem)
        {
            var sourceItems = (FrameworkElement)sender;
            var viewModel = (WindowViewModel)DataContext;

            DragDrop.DoDragDrop(sourceItems, viewModel, DragDropEffects.Move);
            clickedOnSourceItem = false;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

这似乎与鼠标捕获有关!?

拖动过程中正常的事件序列就像这样......

  1. PreviewMouseLeftButtonDown 处理程序被调用 ListBox.IsMouseCaptureWithin是 假的。
  2. PreviewMouseMove处理程序 被叫。到了这个时候 ListBox.IsMouseCaptureWithin是真的。
  3. PreviewMouseMove处理程序中 DragDrop.DoDragDrop被调用了 在此期间的某个时候鼠标 捕获从ListBox中释放。
  4. 但是,当上下文菜单打开时,似乎发生的阻力似乎是......

    1. PreviewMouseLeftButtonDown 处理程序被调用 ListBox.IsMouseCaptureWithin是 假的。
    2. PreviewMouseMove处理程序获取 调用。但这一次 ListBox.IsMouseCaptureWithin是 仍然是假的。
    3. 结束后的某个时间 PreviewMouseMove处理程序 ListBox然后获取鼠标捕获 (ListBox.IsMouseCaptureWithin 变得真实)
    4. 这样做的结果是,在拖动之后,ListBox仍然具有鼠标捕获功能,因此任何打开上下文菜单的按钮实际上都会转到列表框而不是按钮。

      将以下代码添加到PreviewMouseLeftButtonDown处理程序的开头似乎有助于吞掉关闭该上下文菜单的点击,而不是试图从它开始拖动......

      if (!contextMenuCloseComplete)
      {
          sourceElement.CaptureMouse();
          return;
      }
      

      ...将contextMenuCloseComplete bool设置为上下文菜单ClosedOpened事件的处理程序。

      这有意义吗?有谁知道这种鼠标捕获行为的来源?