我目前正在开发一个聊天程序,当我显示两个人的聊天历史记录时,我想滚动到垂直堆栈布局的最后一条消息/末尾 --> 我使用 .ScrollToAsync 函数来实现。
如果我单击其中一个用户按钮,则会从本地存储方法加载历史记录。之后,程序为每条消息创建一个标签,并将其添加到可滚动的垂直堆栈布局中。之后,它应该滚动到垂直堆栈布局的末尾。使用以下代码片段:
await Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false);
完整的方法在这里:
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 是 ScrollView,TextField 是垂直堆栈布局。
奇怪的是:当我第二次单击按钮时,它起作用了。我试图猜测,但由于我在方法末尾调用了异步函数,因此 TextField 是否应该完全初始化?
希望你能帮助我!
在我的主管的帮助下,我找到了解决该问题的方法:
您必须启用一个计时器对象,该对象获取一个函数,该函数在 mainThread 内调用所需的函数 Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false) (因为否则会引发异常)。重要的是无限超时,因此该操作仅执行一次。
这是代码,如果有人有同样的问题:
Timer timer = new Timer((object obj) => {
MainThread.BeginInvokeOnMainThread(() => Scroller.ScrollToAsync(TextField, ScrollToPosition.End, false));
}, null, 100, Timeout.Infinite);
100 是计时器对象在执行之前等待的时间。现在真正好的事情是,UI 不再被阻塞!
没有足够的代表发表评论,但想回复使用计时器的“解决方法”。
计数器单击的 void 是异步的 - 因此,正如答案中正确指出的那样,需要在主线程上调用代码,但是您不需要计时器来执行此操作。您可以使用:
Dispatcher.Dispatch(() => Scroller.ScrollToAsync(...));
Dispatcher 是 BindableObject 的一个属性 - 所以你的页面、控件等。