WPF ListBox drag & drop мешает работе с ContextMenu? - PullRequest
3 голосов
/ 13 октября 2009

Я реализую перетаскивание из 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 Ответ

1 голос
/ 27 октября 2009

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

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

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

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

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

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

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

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

... с установкой contextMenuCloseComplete bool в обработчики контекстных меню для событий Closed и Opened.

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

...