Jippers
Jippers

Reputation: 2715

Disable drag and drop on listboxitem in a bound listbox; Collection was modified exception

I have a WPF listbox with it's ItemSource bound to a collection. When the user clicks and drags the selected item over the next item in the listbox I sometimes get an Invalid Operation Exception: "Collection was modified; enumeration operation may not execute".

I've tried setting AllowDrop on the ItemContainerStyle to false, and handling PreviewDragEnter/Leave with e.Handled=true; but I can still get the crash.

Is there a way to really stop this behaviour? I have no need to move the listbox items around.

Here's my WPF listbox code:

    <ListBox ItemsSource="{Binding Conversations}"
             SelectedItem="{Binding SelectedConversation}"
             VirtualizingStackPanel.IsVirtualizing="True"
             PreviewDragEnter="UIElement_OnPreviewDragEnter">
       <ListBox.ItemContainerStyle>
          <Style BasedOn="{StaticResource MyListBoxItemStyle}" TargetType="{x:Type ListBoxItem}">
             <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
             <Setter Property="AllowDrop" Value="False"/>
             <EventSetter Event="PreviewDragEnter" Handler="UIElement_OnPreviewDragEnter" />
             <EventSetter Event="PreviewDragLeave" Handler="UIElement_OnPreviewDragEnter"/>
             <EventSetter Event="MouseEnter" Handler="EventSetter_OnHandler"></EventSetter>
          </Style>
       </ListBox.ItemContainerStyle>
    </ListBox>

And some codebehind:

  private void UIElement_OnPreviewDragEnter(object sender, DragEventArgs e)
  {
     e.Handled = true;
  }

  private void EventSetter_OnHandler(object sender, MouseEventArgs e)
  {
     if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
     {
        e.Handled = true;
     }
  }

Here's the exception message

Current_DispatcherUnhandledException : System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at System.Collections.Generic.List`1.Enumerator.MoveNext()
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List`1 unselectedItems, List`1 selectedItems)
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(ItemInfo info, Boolean assumeInItemsCollection)
   at System.Windows.Controls.ListBox.MakeSingleSelection(ListBoxItem listItem)
   at System.Windows.Controls.ListBox.MakeKeyboardSelection(ListBoxItem item)
   at System.Windows.Controls.ListBox.FocusItem(ItemInfo info, ItemNavigateArgs itemNavigateArgs)
   at System.Windows.Controls.ItemsControl.NavigateToItem(Object item, Int32 elementIndex, ItemNavigateArgs itemNavigateArgs, Boolean alwaysAtTopOfViewport)
   at System.Windows.Controls.ListBox.NotifyListItemMouseDragged(ListBoxItem listItem)
   at System.Windows.Controls.ListBoxItem.OnMouseEnter(MouseEventArgs e)
   at System.Windows.UIElement.OnMouseEnterThunk(Object sender, MouseEventArgs e)
   at System.Windows.Input.MouseEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.MouseOverProperty.FireNotifications(UIElement uie, ContentElement ce, UIElement3D uie3D, Boolean oldValue)
   at System.Windows.ReverseInheritProperty.FirePropertyChangeInAncestry(DependencyObject element, Boolean oldValue, DeferredElementTreeState treeState, Action`2 originChangedAction)
   at System.Windows.ReverseInheritProperty.FirePropertyChangeInAncestry(DependencyObject element, Boolean oldValue, DeferredElementTreeState treeState, Action`2 originChangedAction)
   at System.Windows.ReverseInheritProperty.FirePropertyChangeInAncestry(DependencyObject element, Boolean oldValue, DeferredElementTreeState treeState, Action`2 originChangedAction)
   at System.Windows.ReverseInheritProperty.FirePropertyChangeInAncestry(DependencyObject element, Boolean oldValue, DeferredElementTreeState treeState, Action`2 originChangedAction)
   at System.Windows.ReverseInheritProperty.OnOriginValueChanged(DependencyObject oldOrigin, DependencyObject newOrigin, IList`1 otherOrigins, DeferredElementTreeState& oldTreeState, Action`2 originChangedAction)
   at System.Windows.Input.MouseDevice.ChangeMouseOver(IInputElement mouseOver, Int32 timestamp)
   at System.Windows.Input.MouseDevice.PreNotifyInput(Object sender, NotifyInputEventArgs e)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

Upvotes: 1

Views: 815

Answers (2)

Jippers
Jippers

Reputation: 2715

Seems that binding the IsSelected to my model was causing the issue. Removing the binding fixed it and doesn't impact on the UI.

Upvotes: 3

thumbmunkeys
thumbmunkeys

Reputation: 20764

It's most likely because you have somewhere a foreach loop on Conversations or another IEnumerable operation, that is executed, right when you move the listbox items around.

Try synchronizing access to Conversations

Upvotes: 0

Related Questions