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!
CodePudding user response:
I found a workaround for that problem, with the help of my chief:
You have to enable a timer object, which gets a function, which is calling the desired function Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false) inside the mainThread (because otherwise an exception is thrown). Important is the Infinite Timeout, so that the action only executes one time.
Here is the code, if somebody has the same Problem:
Timer timer = new Timer((object obj) => {
MainThread.BeginInvokeOnMainThread(() => Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false));
}, null, 100, Timeout.Infinite);
The 100 are the time how long the timer objects waits, before execution. The really good thing now is, that the UI is not blocked anymore!