1

我开发了一个自定义项CheckedListBox,用户可以使用它来指定哪些字段应该显示在报告中或不显示在报告中。我现在有一个来自用户的新要求,即能够按照他们希望在报告中看到的顺序对字段进行重新排序。我尝试这样做的方式是在我的CheckedListBox.

目前,我正在使用该ListBoxItem.PreviewMouseMoveEvent事件来启动拖动。结合PreviewMouseLeftButtonDownEventPreviewMouseLeftButtonUpEvent确定鼠标在移动过程中是否向下,并DropEvent处理下降,一切正常。

但是,它似乎阻止了某些事件的触发,因为它破坏了与IsChecked属性的绑定。事实上,我无法再选中/取消选中某个项目。绑定在 中完成ListBox.ItemTemplate,其中有一个简单CheckBox的包含TextBlock用于显示文本的 a。

我尝试使用MouseMoveEvent,它可以CheckBox恢复生机,但会破坏拖放功能。似乎MouseMoveEvent甚至不再触发(或者鼠标按钮事件之一不再触发)。

问题似乎出在这一行:DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move). 如果我删除它,我没有功能拖放,但所有事件都会正确触发。

这是我在实验阶段的代码示例:

    Public Sub New()

         ' This call is required by the designer.
         InitializeComponent()

         Items = New ObservableCollection(Of CheckListBoxItem)
         oListBox.ItemsSource = Items

         ' Add any initialization after the InitializeComponent() call.
         oListBox.ItemContainerStyle.Setters.Add(New Setter(ListBoxItem.AllowDropProperty, True))
         oListBox.ItemContainerStyle.Setters.Add(New EventSetter(ListBoxItem.PreviewMouseLeftButtonDownEvent, New MouseButtonEventHandler(AddressOf ListBoxItem_PreviewMouseLeftButtonDown)))
         oListBox.ItemContainerStyle.Setters.Add(New EventSetter(ListBoxItem.PreviewMouseLeftButtonUpEvent, New MouseButtonEventHandler(AddressOf ListBoxItem_PreviewMouseLeftButtonUp)))
         oListBox.ItemContainerStyle.Setters.Add(New EventSetter(ListBoxItem.PreviewMouseMoveEvent, New MouseEventHandler(AddressOf ListBoxItem_PreviewMouseMove)))
         oListBox.ItemContainerStyle.Setters.Add(New EventSetter(ListBoxItem.DropEvent, New DragEventHandler(AddressOf ListBoxItem_Drop)))

    End Sub

    Private source As CheckListBoxItem
    Private bMouseLeftButtonDown As Boolean = False

    Private Sub ListBoxItem_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
        bMouseLeftButtonDown = True
    End Sub

    Private Sub ListBoxItem_PreviewMouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs)
         bMouseLeftButtonDown = False
    End Sub

    Private Sub ListBoxItem_PreviewMouseMove(sender As Object, e As MouseEventArgs)

        If TypeOf sender Is ListBoxItem AndAlso bMouseLeftButtonDown Then
            Dim draggedItem As ListBoxItem = CType(sender, ListBoxItem)
            source = CType(draggedItem.DataContext, CheckListBoxItem)
            DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move)
            draggedItem.IsSelected = True
        End If

    End Sub

    Private Sub ListBoxItem_Drop(sender As Object, e As DragEventArgs)

        bMouseLeftButtonDown = False

        Dim target As CheckListBoxItem = CType((CType(sender, ListBoxItem)).DataContext, CheckListBoxItem)

        Dim removedIdx As Integer = Items.IndexOf(source)
        Dim targetIdx As Integer = Items.IndexOf(target)

        If (removedIdx < targetIdx) Then
            Items.Insert(targetIdx + 1, source)
            Items.RemoveAt(removedIdx)
        Else
            Dim remIdx As Integer = removedIdx + 1
            If (Items.Count + 1 > remIdx) Then
                Items.Insert(targetIdx, source)
                Items.RemoveAt(remIdx)
            End If
        End If

    End Sub

这是我的 XAML 示例:

        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding IsChecked}">
                    <TextBlock Text="{Binding DisplayText}" />
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>

我正在寻找的是找到一个事件或一种处理事件的方法,这些事件将允许我进行功能性拖放以及功能性CheckBox. 我会接受一个解释完全不同方法的答案,是否使用(免费)第三方库。

我不是在寻找依赖于特定 ViewModel 的代码,因为这旨在成为我们公司的可重用控件,并且并非所有内容都将按照 MVVM 样式完成。这就是我为每个列表项创建一个CheckListBoxItem充当“DataContext”的具体原因。

4

1 回答 1

1

我终于想出了PreviewMouseMoveEvent通过将鼠标的当前位置减去鼠标的开始位置(来自PreviewMouseLeftButtonDownEvent事件)与最小值进行比较来验证事件的解决方案,以将其视为拖动(SystemParameters.MinimumHorizontalDragDistanceSystemParameters.MinimumVerticalDragDistance)。

以下是生成的代码示例:

Private oSource As CheckListBoxItem
Private oStartPosition As Point

Private Sub ListBoxItem_PreviewMouseLeftButtonDownEvent(sender As Object, e As MouseButtonEventArgs)
    oStartPosition = e.GetPosition(Nothing)
End Sub

Private Sub ListBoxItem_PreviewMouseMove(sender As Object, e As MouseEventArgs)

    If TypeOf sender Is ListBoxItem AndAlso e.LeftButton = MouseButtonState.Pressed Then

        Dim oCurrentPosition As Point = e.GetPosition(Nothing)

        If Math.Abs(oCurrentPosition.X - oStartPosition.X) > SystemParameters.MinimumHorizontalDragDistance OrElse Math.Abs(oCurrentPosition.Y - oStartPosition.Y) > SystemParameters.MinimumVerticalDragDistance Then

            Dim oDraggedItem As ListBoxItem = CType(sender, ListBoxItem)
            oSource = CType(oDraggedItem.DataContext, CheckListBoxItem)
            DragDrop.DoDragDrop(oDraggedItem, oDraggedItem.DataContext, DragDropEffects.Move)
            oDraggedItem.IsSelected = True

        End If

    End If

End Sub

它解决了我的问题,因为DragDrop.DoDragDrop仅当移动被认为是拖动时才调用,而不是仅在选择项目时调用(选中/取消选中CheckBox)。

于 2013-10-09T17:21:16.747 回答