WPF 列表框拖拽drop 会干扰 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;
}
}
}
I'm implementing drag & drop from a ListBox, but I'm seeing some strange behaviour with a ContextMenu elsewhere in the window. If you open the context menu and then start a drag from the ListBox, the context menu closes but won't open again until after you perform another drag.
Does this make sense? Anybody got any ideas what might be going on?
<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;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好像和鼠标捕捉有关!?
拖动过程中事件的正常顺序是这样的...
PreviewMouseLeftButtonDown
处理程序被调用并且
ListBox.IsMouseCaptureWithin
是错误的。
PreviewMouseMove
处理程序被叫。到了这个时候
ListBox.IsMouseCaptureWithin
为 true。PreviewMouseMove
处理程序期间DragDrop.DoDragDrop
被调用并且在此期间的某个时候,鼠标
捕获从列表框中释放。
但是,当上下文菜单打开时开始拖动似乎发生的是......
PreviewMouseLeftButtonDown
处理程序被调用并且
ListBox.IsMouseCaptureWithin
是错误的。
PreviewMouseMove
处理程序获取叫。但这一次
ListBox.IsMouseCaptureWithin
是仍然是假的。
PreviewMouseMove
处理程序ListBox然后获取鼠标捕获
(
ListBox.IsMouseCaptureWithin
变为 true)
这样做的结果是,拖动后,列表框仍然具有鼠标捕获,因此任何单击按钮以打开上下文菜单的操作实际上都会进入列表框而不是按钮。
将以下代码添加到
PreviewMouseLeftButtonDown
处理程序的开头似乎有助于吞下关闭该上下文菜单的单击,而不是尝试从中开始拖动......使用
contextMenuCloseComplete
bool 在上下文菜单的Closed
和Opened
事件的处理程序中设置。这有道理吗?有谁知道这种鼠标捕获行为来自哪里?
It seemed to be something to do with the mouse capture!?
The normal sequence of events during a drag goes something like this...
PreviewMouseLeftButtonDown
handler gets called and
ListBox.IsMouseCaptureWithin
isfalse.
PreviewMouseMove
handlergets called. By this time
ListBox.IsMouseCaptureWithin
is true.PreviewMouseMove
handlerDragDrop.DoDragDrop
gets called andsometime during this the mouse
capture is released from the ListBox.
But, what seems to happening for a drag started when the context menu is open is...
PreviewMouseLeftButtonDown
handler gets called and
ListBox.IsMouseCaptureWithin
isfalse.
PreviewMouseMove
handler getscalled. But this time
ListBox.IsMouseCaptureWithin
isstill false.
PreviewMouseMove
handler theListBox then gets the mouse capture
(
ListBox.IsMouseCaptureWithin
becomes true)
The result of this is that after the drag, the ListBox still has the mouse capture so any clicks on the button to open the context menu are actually going to the listbox not the button.
Adding the following code to the start of the
PreviewMouseLeftButtonDown
handler seems to help by swallowing up the click that closes that context menu rather than trying to start a drag from it......with the
contextMenuCloseComplete
bool getting set in handlers for the context menu'sClosed
andOpened
events.Does that make sense? Does anyone understand where this mouse capture behaviour is coming from?