Xamarin.Forms Grouped List View fails on adding new groups in Android
Asked Answered
S

3

5

I am using Xamarin.Forms for developing mobile apps for Android and windows Phone.

I have a listview of messages which is bound to an ObservableCollection of groups. The list groups the messages by day then the messages show in order of the time - pretty standard stuff.

The problem I have now encountered is that in Android - using the Add function to add new groups to the ObservableCollection causes an unhandled exception to fire.

04-22 13:13:32.404 D/Mono (19971): DllImport attempting to load: '/system/lib/liblog.so'. 04-22 13:13:32.404 D/Mono (19971): DllImport loaded library '/system/lib/liblog.so'. 04-22 13:13:32.404 D/Mono (19971): DllImport searching in: '/system/lib/liblog.so' ('/system/lib/liblog.so'). 04-22 13:13:32.404 D/Mono (19971): Searching for '__android_log_print'. 04-22 13:13:32.414 D/Mono
(19971): Probing '__android_log_print'. 04-22 13:13:32.414 D/Mono
(19971): Found as '__android_log_print'. 04-22 13:13:32.434 I/MonoDroid(19971): UNHANDLED EXCEPTION: An unhandled exception occured.

04-22 13:13:32.444 I/MonoDroid(19971): System.ArgumentOutOfRangeException: Argument is out of range. 04-22 13:13:32.444 I/MonoDroid(19971): Parameter name: index 04-22 13:13:32.444 I/MonoDroid(19971): at System.Collections.Generic.List1<object>.get_Item (int) <0x0007c> 04-22 13:13:32.444 I/MonoDroid(19971): at Cadenza.Collections.OrderedDictionary2, Xamarin.Forms.Cell>>.get_Item (int) <0x00063>

This is not a problem in Windows.

I can get around this by using the AddRange function and simply adding the item I want to add to another "temporary list" first, then add that temporary list to the main Collection - This gets around it but seems a bit of a hack.

Another way would be to do this on the main thread:

Device.BeginInvokeOnMainThread(() =>
{
   // using of add function in this manner works.
});

Has anyone had a similar problem and have you found a solution to it?

Thanks,

Seto answered 22/4, 2015 at 1:19 Comment(0)
E
6

You're doing Add operations from a different threads. ObservableCollection is not thread safe.

Elburr answered 31/7, 2015 at 12:6 Comment(5)
Cheers solved this by suing the Device.BeginInvokeOnMainThread optionSeto
No problem. If it's working you can mark this question as answered. Thanks!Elburr
Hi @loan.burger, I got the same issue but still not fixed. Could you please show me where exactly I have to put BeginInvokeOnMainThread is?Orland
Hi @Orland you just call your .Add on your list in the Device.BeginInvokeOnMainThread(() =>{ YourList.Add(someItem); }); The reason this is needed is most likely that your adding to the list in a UI thread which blocks the UI thread and causes the app to crash because an ObservableCollection is not thread safe as Daniel explains above. Hope that helps otherwise as a new question and present your code so we can better assist you.Seto
Hi @loan.burger, it work. And after i try BindingBase.EnableCollectionSynchronization it much simpler and cleaner for me, and i will use it, thanksOrland
G
1

Building on @Daniel Luberda's answer, I too recommend using BindingBase.EnableCollectionSynchronization, because ObservableCollection is not thread safe.

I put together a blog post on the topic here: https://www.codetraveler.io/2019/08/27/using-observablecollection-in-a-multi-threaded-xamarin-forms-application/

BindingBase.EnableCollectionSynchronization Example

Note: Ensure that you initialize the ObservableCollection before calling EnableCollectionSynchronization

class MyViewModel
{
    public MyViewModel()
    {
        MyCollection = new ObservableCollection<MyModel>();
        Xamarin.Forms.BindingBase.EnableCollectionSynchronization(MyCollection, null, ObservableCollectionCallback);
    }

    public ObservableCollection<MyModel> MyCollection { get; }

    void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
    {
        lock (collection)
        {
            accessMethod?.Invoke();
        }
    }
}
Georgiannageorgianne answered 27/8, 2019 at 16:59 Comment(2)
Brandon - Have you tried this solution with a grouped ListView? I'm trying to at the moment and I still get the "index out of range" exception even when just adding items to the collection on the main thread. I have a class like... public class Grouping<K, T> : ObservableCollection<T> ... and my ListView bound to a grouped collection like.... ObservableCollection<Grouping<string, ListItemViewModel>> GroupedItems { get; set; }Subversive
Brandon, thanks for the suggestion. But however I try it, the callback function never seems to be accessed, regardless of which operations I perform on my collection. What is your recent experience? I am using Xamarin Forms 4.4 on UWP and Android.Porpoise
P
0
            Task loadLineItems = Task.Run( () =>
            {
                foreach (listEntity item in newList)
                {
                    this.ObservalCollectionFromVM.Add(item);
                }
            });
            loadLineItems.Wait();

or

            Task loadLineItems = Task.Run(async () =>
            {
                var list == await DependencyService.Get<IEntityService>().GetEntityListAsync();
                foreach (Entity item in list)
                {
                    this.ObservalCollectionFromVM.Add(item);
                }
            });
            loadLineItems.Wait();
Pellitory answered 27/1, 2021 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.