在 .Net Maui 中,ScrollToAsync 只有在我第二次按下按钮时才能正常工作。

3

我目前正在开发一个聊天程序,当我显示两个人的聊天历史记录时,我希望滚动到最后一条消息/垂直堆栈布局的结尾--> 我使用.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应该已经完全初始化了吧?

希望你能帮助我!


应该已经工作了 - 听起来像是Maui布局的一个错误。在Android上测试吗?等待下一个发布(本月晚些时候)- 开发人员不得不回滚最近引起多个布局错误的更改。 - ToolmakerSteve
@ToolmakerSteve 我目前正在使用Windows。那我就等等吧,谢谢。(反正这个工具还很新) - Roy Mustang
2个回答

2
我找到了一个解决方法,得到了我的主管的帮助:
您需要启用定时器对象,该对象获取一个函数,在主线程中调用所需的函数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不再被阻塞!


1
谢谢分享,这个方法对我很有用。我按照他们的文档操作,但是无法滚动。如果我只调用ScrollToAsync一次,它不起作用。如果我调用两次,那么它就不会滚动,但是一旦我手动滚动了,它就会滚动到底部。我从未想过要把它放入计时器中。再次感谢。 - b.pell

0
没有足够的声望来评论,但是想回复一下使用计时器的“解决方法”。
计数器点击无效是异步的 - 所以正如答案中指出的那样,代码需要在主线程上调用,但是你不需要计时器来做这个。你可以使用:
Dispatcher.Dispatch(() => Scroller.ScrollToAsync(...));

Dispatcher是BindableObject上的一个属性 - 所以你的页面、控件等等。

https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.controls.bindableobject.dispatcher?view=net-maui-7.0


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接