I am working currently on a chat program and when I display the chat history of two people, I want to scroll to the last message/end of the Vertical Stack Layout --> I do it with the .ScrollToAsync Function.
If I click one of the User Buttons, then the History gets loaded from a local storing method. After that the program creates a label for every message and adds it to the scrollable vertical stack layout. After that it should scroll to the end of the vertical stack layout. With the following code snippet:
await Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false);
The complete method is here:
private async void OnCounterClicked(object sender, EventArgs e)
{
if (m_currentLabels != null)
{
foreach(Label label in m_currentLabels)
{
TextField.Remove(label);
}
}
m_currentLabels = new List<Label>();
Button button =(Button) sender;
string str = button.Text;
Guid userId = m_userDictionary[str];
List<Guid> guids = new List<Guid>();
guids.Add(userId);
m_currChannelPartners = guids;
List<MessageModel> localMessages = m_eChatBusiness.GetMessages(MessageModel.Yourself.ID, guids);
foreach(MessageModel message in localMessages)
{
Label messageLabel = new Label();
messageLabel.Text = $"{message.Created} {message.Message} | {GetStatus(message)}";
messageLabel.TextColor = Color.Parse("White");
messageLabel.HorizontalTextAlignment = message.Position == "End"? TextAlignment.End:TextAlignment.Start;
m_currentLabels.Add(messageLabel);
TextField.Add(messageLabel);
}
await Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false);
}
Scroller is the ScrollView and the TextField is the vertical stack layout.
The weird thing is: It works, when I click the button a second time. I tried to guess, but since I call the asynchronous function at the end of the method, the TextField should be fully initialized or not?
I hope you can help me!
Don't have enough rep to comment, but wanted to reply to the "workaround" that uses a timer. (https://stackoverflow.com/a/72893292/22299956)
The counter clicked void is async - so as rightly pointed out in the answer, the code needs to be invoked on the main thread, however you don't need a timer to do this. You can use:
Dispatcher.Dispatch(() => Scroller.ScrollToAsync(...));
Dispatcher is a property on BindableObject - so your page, control etc.