Xamarin.Forms SignalR:更新无效:第 0 节中的行数无效

Xamarin.Forms SignalR: Invalid update: invalid number of rows in section 0

我有一个 Xamarin.Forms 应用程序,在我的崩溃日志中,我不断看到此错误的变体:

SIGABRT: Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (60) must be equal to the number of rows contained in that section before the update (60), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).

这个特定的列表视图是一个聊天组件,我正在使用 ObservableCollection 并在收到消息时使用 SignalR 添加消息条目。相关代码如下:

    public ObservableCollection<MessageModel> Messages {
        get {
            return _messages;
        }
        set {
            _messages = value;
            OnPropertyChanged();
        }
    }


        Messages = new ObservableCollection<MessageModel>();


        hubConnection.On<long, string, string, long, long>("postChat", (id, name, message, userId, eventId) => {               
            Messages.Add(new MessageModel() { Id = id, UserId = userId, User = name, Message = message, IsSystemMessage = false, IsOwnMessage = userId == currentUserId });
            this.MessageReceived.Invoke(this, new EventArgs());
        });

感觉可能是线程问题,因为聊天理论上可以同时进入,但我不知道去哪里看。这是完整的 StackTrace

CoreFoundation
__exceptionPreprocess
libobjc.A.dylib
objc_exception_throw
CoreFoundation
+[NSException raise:format:arguments:]
Foundation
-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
UIKitCore
-[UITableView _Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Rows_In_Section:]
UIKitCore
-[UITableView _endCellAnimationsWithContext:]
UIKitCore
-[UITableView endUpdatesWithContext:]
BehaviorLive.iOS
wrapper_managed_to_native_ObjCRuntime_Messaging_objc_msgSend_intptr_intptr_11
BehaviorLive.iOS
UITableView.g.cs:292
BehaviorLive.iOS
Xamarin_Forms_Platform_iOS_ListViewRenderer__c__DisplayClass54_0__InsertRowsb__0 (D:\a\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:638)
BehaviorLive.iOS
Xamarin_Forms_Platform_iOS_ListViewRenderer_InsertRows_int_int_int (D:\a\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:642)
BehaviorLive.iOS
Xamarin_Forms_Platform_iOS_ListViewRenderer_UpdateItems_System_Collections_Specialized_NotifyCollectionChangedEventArgs_int_bool (D:\a\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:588)
BehaviorLive.iOS
Xamarin_Forms_Platform_iOS_ListViewRenderer_OnCollectionChanged_object_System_Collections_Specialized_NotifyCollectionChangedEventArgs (D:\a\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:386)
BehaviorLive.iOS
Xamarin_Forms_Internals_TemplatedItemsList_2_TView_REF_TItem_REF_OnCollectionChanged_System_Collections_Specialized_NotifyCollectionChangedEventArgs (D:\a\s\Xamarin.Forms.Core\TemplatedItemsList.cs:771)
BehaviorLive.iOS
Xamarin_Forms_Internals_TemplatedItemsList_2_TView_REF_TItem_REF_OnProxyCollectionChanged_object_System_Collections_Specialized_NotifyCollectionChangedEventArgs (D:\a\s\Xamarin.Forms.Core\TemplatedItemsList.cs:972)
BehaviorLive.iOS
Xamarin_Forms_ListProxy_OnCollectionChanged_System_Collections_Specialized_NotifyCollectionChangedEventArgs (D:\a\s\Xamarin.Forms.Core\ListProxy.cs:232)
BehaviorLive.iOS
Xamarin_Forms_ListProxy__c__DisplayClass34_0__OnCollectionChangedb__0 (D:\a\s\Xamarin.Forms.Core\ListProxy.cs:208)
BehaviorLive.iOS
NSAction.cs:152
BehaviorLive.iOS
wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr
BehaviorLive.iOS
mono_jit_runtime_invoke mini-runtime.c:3164
BehaviorLive.iOS
mono_runtime_invoke_checked object.c:3052
BehaviorLive.iOS
mono_runtime_invoke object.c:3107
BehaviorLive.iOS
native_to_managed_trampoline_11(objc_object*, objc_selector*, _MonoMethod**, unsigned int) registrar.m:400
BehaviorLive.iOS
-[__MonoMac_NSAsyncActionDispatcher xamarinApplySelector] registrar.m:8726
Foundation
__NSThreadPerformPerform
CoreFoundation
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
CoreFoundation
__CFRunLoopDoSource0
CoreFoundation
__CFRunLoopDoSources0
CoreFoundation
__CFRunLoopRun
CoreFoundation
CFRunLoopRunSpecific
GraphicsServices
GSEventRunModal
UIKitCore
-[UIApplication _run]
UIKitCore
UIApplicationMain
BehaviorLive.iOS
wrapper_managed_to_native_UIKit_UIApplication_UIApplicationMain_int_string___intptr_intptr
BehaviorLive.iOS
UIApplication.cs:86
BehaviorLive.iOS
UIApplication.cs:65
BehaviorLive.iOS
BehaviorLive_iOS_Application_Main_string__ <unknown>:1
BehaviorLive.iOS
wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr
BehaviorLive.iOS
mono_jit_runtime_invoke mini-runtime.c:3164
BehaviorLive.iOS
mono_runtime_invoke_checked object.c:3052
BehaviorLive.iOS
mono_runtime_exec_main_checked object.c:0
BehaviorLive.iOS
mono_jit_exec driver.c:1383
BehaviorLive.iOS
xamarin_main monotouch-main.m:493
BehaviorLive.iOS
main main.m:292
libdyld.dylib
start

当您访问绑定到 UI 视图的 ObservableCollection 时,确保您在 MainThread 上。

  • 在 Debug 测试期间测试 MainThread.IsMainThread,如果不在该线程上则抛出异常(但您认为所有调用代码都已在该线程上)。

  • Device.BeginInvokeOnMainThread 中包装代码。这样做可以确保您不会在 UI 更新过程中更改集合:

.

Device.BeginInvokeOnMainThread( () => {
    .. do something with `Messages` collection ..
});

注意:BeginInvokeOnMainThread 运行 是独立的,因此您不能依赖它在接下来的任何代码之前“完成”。

如果这种“即发即弃”不是 sufficient/appropriate,那么您将需要改用任务延续。或执行等效的手动操作 - 我手边没有示例,但原则是您 运行 在主线程上,然后在完成该工作时调用一个 Action。