1
votes

In my Xamarin Forms app I have a chat page with a ListView listing the chat items.

This is the chat page viewmodel:

public class IndexViewModel : BaseViewModel
{
    public ObservableCollection<Model.Chat> Items { get; set; }
    public Command LoadItemsCommand { get; set; }

    public IndexViewModel()
    {

        Items = new ObservableCollection<Model.Chat>();
        LoadItemsCommand = new Command( () => ReadTheList());

        MessagingCenter.Subscribe<RootPage, Model.Chat>(this, "NewMessage", (obj, item) =>
        {
            var chat = item as Model.Chat; // Inspecting this as a local variable during debugging looks fine
            // when an item is added like this the app freezes
            Items.Add(chat);
        });
    }

    void ReadTheList()
    {
        var items = repo.ChatList();
        Items.Clear();
        foreach (var item in items)
        {
            // when an item is added like this, all is fine
            Items.Add(item);
        }
    }

}

Whenever a new chat message arrives I want to scroll down to the last message (the newly added message). So I have added this delegate in my View:

viewModel.Items.CollectionChanged += (sender, e) => 
{
    if (viewModel.Items.Count == 0) return;
    Debug.WriteLine("I can always see this when a chat item is added to the collection");
    chatList.ScrollTo(viewModel.Items.Last(), ScrollToPosition.End, false);  // this is where the freeze happens
};

The last line of the delegate works fine when I add a list of items from local storage and the list scrolls to the bottom, but it freezes up my app when a newly received Chat item is added via a MessagingCenter subscription. This consistently happens when a new message arrives and the page is open and I am not interacting with anything on the page.

Can anyone help me debug this?

1
Have you tried just change ScrollTo call to Device.BeginInvokeOnMainThread(() => chatList.ScrollTo(viewModel.Items.Last(), ScrollToPosition.End, false));? - Diego Rafael Souza
@DiegoRafaelSouza good suggestion! That was exactly it. Can you please add this as an answer so I can mark it. - Jannie Theunissen

1 Answers

2
votes

When handling heavy background process like dealing with list search, do it on a thread apart to avoid this kind of issue.

Change your CllectionChanged handler to this:

viewModel.Items.CollectionChanged += (sender, e) => 
{
    if (viewModel.Items.Count == 0) return;
    Debug.WriteLine("I can always see this when a chat item is added to the collection");
    Device.BeginInvokeOnMainThread(() => 
        chatList.ScrollTo(viewModel.Items.Last(), ScrollToPosition.End, false));
};