Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception on Update or Remove in ObservableDictionary after upgrading to 0.8 #1

Open
verybadsoldier opened this issue Sep 24, 2018 · 6 comments
Labels

Comments

@verybadsoldier
Copy link

Hello gentlemen,

I have been using this cool library for quite some time without problems with version 0.7.0. Yesterday I updated via nuget to version 0.8.114 and I am seeing some exceptions now.

I am using ObservableDictionary in a WPF-Application bound by XAML to a ListView. So when I add items to the ObservableDictionary then they show up in the ListView. This still works fine.

The problem is:
As soon as I try to update or remove an item in the dictionary then I see an exception.

For debugging purpose I checked out the project from Github and I am on this commit: a37aee7771a2a92f8e6865d5d5cc0901aa0d506d

This is the exception on update:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.'

   at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at MS.Internal.Data.EnumerableCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
   at JB.Collections.Reactive.ObservableDictionary`2.<>c__DisplayClass125_0.<RaiseCollectionChanged>b__0() in C:\Users\Robin\Projects\JB.Common\JB.Common.Collections.Reactive\ObservableDictionary.cs:line 1660
   at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
   at System.Reactive.Concurrency.CurrentThreadScheduler.Schedule[TState](TState state, TimeSpan dueTime, Func`3 action)
   at JB.Collections.Reactive.ObservableDictionary`2.RaiseCollectionChanged(IObservableDictionaryChange`2 observableDictionaryChange) in C:\Users\Robin\Projects\JB.Common\JB.Common.Collections.Reactive\ObservableDictionary.cs:line 1656
   at JB.Collections.Reactive.ObservableDictionary`2.NotifyObserversAboutDictionaryChanges(IObservableDictionaryChange`2 observableDictionaryChange) in C:\Users\Robin\Projects\JB.Common\JB.Common.Collections.Reactive\ObservableDictionary.cs:line 840
   at JB.Collections.Reactive.ObservableDictionary`2.OnValuePropertyChanged(Object sender, PropertyChangedEventArgs e) in C:\Users\Robin\Projects\JB.Common\JB.Common.Collections.Reactive\ObservableDictionary.cs:line 704
   at MetaQrawler.ViewModel.TickViewModel.OnPropertyChanged(String propertyName) in C:\Users\Robin\Projects\assembla-vbs\MetaQrawler\MetaQrawler\ViewModel\TickViewModel.cs:line 195
   at MetaQrawler.ViewModel.TickViewModel.set_Last(Decimal value) in C:\Users\Robin\Projects\assembla-vbs\MetaQrawler\MetaQrawler\ViewModel\TickViewModel.cs:line 139
   at MetaQrawler.ViewModel.TickViewModel.Update(Tick q) in C:\Users\Robin\Projects\assembla-vbs\MetaQrawler\MetaQrawler\ViewModel\TickViewModel.cs:line 115
   at MetaQrawler.ViewModel.QuoteSinkViewModel.<>c__DisplayClass27_0.<DispatchTickExec>b__0() in C:\Users\Robin\Projects\assembla-vbs\MetaQrawler\MetaQrawler\ViewModel\QuoteSinkViewModel.cs:line 187
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(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 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at MetaQrawler.App.Main()

This is for the remove operation:
System.InvalidOperationException: 'Collection Remove event must specify item position.'

   at MS.Internal.Data.EnumerableCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
   at JB.Collections.Reactive.ObservableDictionary`2.<>c__DisplayClass125_0.<RaiseCollectionChanged>b__0() in C:\Users\Robin\Projects\JB.Common\JB.Common.Collections.Reactive\ObservableDictionary.cs:line 1660

I tried to find out what the problem is and I think the WPF UI has subscribed changes of the ObservableDictionary. Now when an item changes the ObservableDictionary generates a NotifyCollectionChangedEventArgs which triggers the exception. Seems like the object is somehow unexpected for the framework.

@joergbattermann
Copy link
Owner

Hey there! Thanks for reporting the problem.. but that's strange.. the ObservableDictionary class hasn't changed since March 2016 (and the line mentioned)... hrm. Same for the extension method used.. that last one converts the events to NotifyCollectionChangedEvent(Args) via this method.. so either of the two is doing something 'wrong' / different what WPF expects.

Digging a little around Stephen Clearly explains a little more in-depth what properties for the event args must/should be set to which value(s).

I can't fix this at the moment myself (and none of my active projects currently use the ObservableDictionary so no immediate client need, too), but if you want to take a stab at it and send a PR over, it would be highly welcome!

@verybadsoldier
Copy link
Author

Thanks for quick reply! Yeah, I also stumbled upon that article from Stephen Clearly but it didn't help me much so far.
Release 0.7 is from December 2015, no? So since then some things changed, I think (according to the GitHub log). Could you please tell me the exact commit that belongs to version 0.7 on nuget? I tried one but that did not work at all it seems.
I could at least try to trial&error my way through the Github history until I find the culprit :)

btw:
You have a cool project here and I am totally baffled that there is not a single fork here on Github and also not a single star?! And I just opened the very first issue here ever?

@joergbattermann
Copy link
Owner

Here's the version details and commit sha for 0.7.0 (at the top): https://ci.appveyor.com/project/jbattermann/jb-common/build/41/artifacts

A lot changed from there on, yeah and while there are tests (https://github.com/jbattermann/JB.Common/tree/d8013fe8c2339ce697ea7e30b81dbe762581ac16/JB.Common.Collections.Reactive.Tests ... the ObservableDictionary* ones), this one apparently slipped through or WPF assumes something I did not anticipate :-/

@verybadsoldier
Copy link
Author

Ok thanks alot! I have that 0.7 version compilable and working here now so I should be able to find the breaking commit (at least by trial&error) after some time ^^

@verybadsoldier
Copy link
Author

I can say this is the last working commit:
5568f561e4f0c26354bdd37c6704632e8f398fbc

The follow-up commit shows the error (at least when updating items):
ca127d893d5614b15a9ca2859b6cd9eec98f040d

@verybadsoldier
Copy link
Author

verybadsoldier commented Sep 24, 2018

Hm, interesting: it stops working as soon as I put this line in in the ctor of ObservableDictionary:
IsThrowingUnhandledObserverExceptions = true; which was introduced by the bogus commit.

I think the exception also occurs in the working version but it just got swallowed. When putting IsThrowingUnhandledObserverExceptions to true then it gets rethrown so I see the error.

In the current master version the mechanism has changed it seems (can't find IsThrowingUnhandledObserverExceptions anymore) so I cannot check against current version.


Yes interesting, even 0.7 constantly throws this exception for me, but it gets caught so you usually don't notice:
image


EDIT:
Adding the second parameter to this line (like in master):
return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, observableCollectionChange.Item, observableCollectionChange.Item);

fixes the exception kinda but then I get the exception mentioned in my first post System.ArgumentOutOfRangeException).


I really think there is something broken while emitting those NotifyCollectionChangedEventArgs but I don't understand what it is... :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants