Перетаскивание WPF ListBox мешает 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;
        }
    }
}
13.10.2009 08:36:33
1 ОТВЕТ
РЕШЕНИЕ

Казалось, что-то связано с захватом мыши !?

Обычная последовательность событий во время перетаскивания выглядит примерно так ...

  1. PreviewMouseLeftButtonDown Обработчик вызывается и ListBox.IsMouseCaptureWithinложно.
  2. PreviewMouseMoveОбработчик вызывается. К этому времени ListBox.IsMouseCaptureWithinверно.
  3. Во время PreviewMouseMoveвызова обработчика DragDrop.DoDragDropи когда-то во время этого захват мыши освобождается из ListBox.

Но то, что, по-видимому, происходит для перетаскивания, когда контекстное меню открыто, - это ...

  1. PreviewMouseLeftButtonDown Обработчик вызывается и ListBox.IsMouseCaptureWithinложно.
  2. PreviewMouseMoveОбработчик вызывается. Но это время ListBox.IsMouseCaptureWithinвсе еще ложно.
  3. Через некоторое время после завершения PreviewMouseMoveобработчика ListBox получает захват мыши ( ListBox.IsMouseCaptureWithin становится истинным)

Результатом этого является то, что после перетаскивания ListBox все еще имеет захват мыши, поэтому любые щелчки на кнопке, чтобы открыть контекстное меню, фактически переходят к списку, а не к кнопке.

Добавление следующего кода в начало PreviewMouseLeftButtonDownобработчика, кажется, помогает, поглощая щелчок, закрывающий это контекстное меню, а не пытаясь начать перетаскивание из него ...

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

... с установкой contextMenuCloseCompletebool в обработчиках контекстного меню Closedи Openedсобытий.

Имеет ли это смысл? Кто-нибудь понимает, откуда происходит это поведение при захвате мыши?

1
27.10.2009 09:49:20