WPF:将 PreviewMouseLeftButtonDown 事件处理程序添加到父 ListBox 后,带扩展器的 ListBoxItem 无法扩展
WPF: ListBoxItem with expander cannot expand after adding PreviewMouseLeftButtonDown event handler to parent ListBox
我有一个列表框,其中的子项是扩展器。我需要为此实现 DragDrop 事件。如果我写 XAML
<ListBox PreviewMouseLeftButtonDown="StartDragDrop">
, StartDragDrop 方法效果很好,但子扩展器无法扩展。
如果我写
<ListBox MouseLeftButtonDown="StartDragDrop">
,子扩展器工作正常,但 StartDragDrop 方法不工作。
我认为问题与气泡和隧道事件有关,但我不知道明确的解决方案。
我需要 StartDragDrop 方法和 ListBox 子扩展器 Expand 方法,它们都可以正常工作。我该怎么办?
你的假设是部分正确的,它必须与隧道效应和冒泡有关。外部控件的隧道(带预览)事件在冒泡(无预览)事件之前执行。但并不妨碍后者被处决。这仅在整个事件链中的某处 e.Handled
设置为 true 时才成立。看这个例子:
XAML:
<Border Background="Red" PreviewMouseMove="OnPreviewMouseMove">
<Border Background="Blue" MouseMove="OnMouseMove" />
</Border>
C#
private void OnPreviewMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("Preview outer");
e.Handled = true; // this prevents OnMouseMove from being executed
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("NoPreview inner");
}
如果删除行 "e.Handled = true;",OnMouseMove 将被命中。如果您不自己设置它,请考虑调用 base."event-name" 可能会做到这一点。
主要思想是当移动偏移量大于某种值时,在 PreviewMouseMove() 事件中调用 DoDragDrop 方法。
1) 这里是列表框:
<ListBox AllowDrop="True" Drop=" ListBox_Drop" PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown" PreviewMouseMove="ListBox_PreviewMouseMove">
ListBoxItems 是扩展器,如果我们实现 DragAndDrop 则无法扩展。
2) 现在我们必须添加 2 个变量(我使用 VB.NET):
Private isDragging As Boolean = False 'flag: is drag operation in process?'
Private dragStartPoint As Point 'coords of dragging start.'
3) 通过鼠标单击预览记住起点坐标:
Private Sub ListBox_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
dragStartPoint = e.GetPosition(Me)
End Sub
4) 在 PreviewMouseMove 上获取移动起点到当前移动点的偏移量。如果偏移量大于某个值,我们启动 DragAndDrop 操作并设置标志 isDragging 以记住这一点。
Private Sub ListBox_PreviewMouseMove(sender As System.Object, e As MouseEventArgs)
If e.LeftButton = MouseButtonState.Pressed Then
Dim diff As Vector = Point.Subtract(dragStartPoint, e.GetPosition(Me))
If (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance) OrElse (Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance) Then
If Not isDragging Then
isDragging = True 'the flag is active until drop event raises.'
Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox'
If lstBox IsNot Nothing Then
Dim data As Object = GetDataFromListBox(lstBox, e.GetPosition(lstBox)) 'get data for drag-and-drop; need to be realized; there are some realizations at whosebug.com presented.'
Dim effects As DragDropEffects = DragDrop.DoDragDrop(lstBox, data, DragDropEffects.Move) 'initiate drag-and-drop.'
End If
End If
End If
End If
End Sub
5) 处理drop操作:
Private Sub ListBox_Drop(sender As Object, e As DragEventArgs)
isDragging = False 'reset isDragging flag.'
Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox.'
If lstBox IsNot Nothing Then
Dim myObj As MyClass = TryCast(e.Data.GetData(GetType(MyClass)), MyClass)
'...some actions'
End If
End Sub
我已经实现了这个想法,它的工作原理正是我所需要的:
- MouseLeftButtonClick 带有扩展器的 ListBoxItems 是扩展和
倒塌,
- 在按下左键的 MouseMove 上 DragAndDrop 操作是
有效,ListBoxItems 可以排序。
我有一个列表框,其中的子项是扩展器。我需要为此实现 DragDrop 事件。如果我写 XAML
<ListBox PreviewMouseLeftButtonDown="StartDragDrop">
, StartDragDrop 方法效果很好,但子扩展器无法扩展。 如果我写
<ListBox MouseLeftButtonDown="StartDragDrop">
,子扩展器工作正常,但 StartDragDrop 方法不工作。 我认为问题与气泡和隧道事件有关,但我不知道明确的解决方案。 我需要 StartDragDrop 方法和 ListBox 子扩展器 Expand 方法,它们都可以正常工作。我该怎么办?
你的假设是部分正确的,它必须与隧道效应和冒泡有关。外部控件的隧道(带预览)事件在冒泡(无预览)事件之前执行。但并不妨碍后者被处决。这仅在整个事件链中的某处 e.Handled
设置为 true 时才成立。看这个例子:
XAML:
<Border Background="Red" PreviewMouseMove="OnPreviewMouseMove">
<Border Background="Blue" MouseMove="OnMouseMove" />
</Border>
C#
private void OnPreviewMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("Preview outer");
e.Handled = true; // this prevents OnMouseMove from being executed
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("NoPreview inner");
}
如果删除行 "e.Handled = true;",OnMouseMove 将被命中。如果您不自己设置它,请考虑调用 base."event-name" 可能会做到这一点。
主要思想是当移动偏移量大于某种值时,在 PreviewMouseMove() 事件中调用 DoDragDrop 方法。
1) 这里是列表框:
<ListBox AllowDrop="True" Drop=" ListBox_Drop" PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown" PreviewMouseMove="ListBox_PreviewMouseMove">
ListBoxItems 是扩展器,如果我们实现 DragAndDrop 则无法扩展。
2) 现在我们必须添加 2 个变量(我使用 VB.NET):
Private isDragging As Boolean = False 'flag: is drag operation in process?'
Private dragStartPoint As Point 'coords of dragging start.'
3) 通过鼠标单击预览记住起点坐标:
Private Sub ListBox_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
dragStartPoint = e.GetPosition(Me)
End Sub
4) 在 PreviewMouseMove 上获取移动起点到当前移动点的偏移量。如果偏移量大于某个值,我们启动 DragAndDrop 操作并设置标志 isDragging 以记住这一点。
Private Sub ListBox_PreviewMouseMove(sender As System.Object, e As MouseEventArgs)
If e.LeftButton = MouseButtonState.Pressed Then
Dim diff As Vector = Point.Subtract(dragStartPoint, e.GetPosition(Me))
If (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance) OrElse (Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance) Then
If Not isDragging Then
isDragging = True 'the flag is active until drop event raises.'
Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox'
If lstBox IsNot Nothing Then
Dim data As Object = GetDataFromListBox(lstBox, e.GetPosition(lstBox)) 'get data for drag-and-drop; need to be realized; there are some realizations at whosebug.com presented.'
Dim effects As DragDropEffects = DragDrop.DoDragDrop(lstBox, data, DragDropEffects.Move) 'initiate drag-and-drop.'
End If
End If
End If
End If
End Sub
5) 处理drop操作:
Private Sub ListBox_Drop(sender As Object, e As DragEventArgs)
isDragging = False 'reset isDragging flag.'
Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox.'
If lstBox IsNot Nothing Then
Dim myObj As MyClass = TryCast(e.Data.GetData(GetType(MyClass)), MyClass)
'...some actions'
End If
End Sub
我已经实现了这个想法,它的工作原理正是我所需要的:
- MouseLeftButtonClick 带有扩展器的 ListBoxItems 是扩展和 倒塌,
- 在按下左键的 MouseMove 上 DragAndDrop 操作是 有效,ListBoxItems 可以排序。