ScrollToAsync .Net Maui 仅在我第二次按下按钮时有效

问题描述 投票:0回答:2

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

希望你能帮助我!

c# asynchronous events maui
2个回答
2
投票

在我的主管的帮助下,我找到了解决该问题的方法:

您必须启用一个计时器对象,该对象获取一个函数,该函数在 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 不再被阻塞!


0
投票

没有足够的代表发表评论,但想回复使用计时器的“解决方法”。

计数器单击的 void 是异步的 - 因此,正如答案中正确指出的那样,需要在主线程上调用代码,但是您不需要计时器来执行此操作。您可以使用:

Dispatcher.Dispatch(() => Scroller.ScrollToAsync(...));

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

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

© www.soinside.com 2019 - 2024. All rights reserved.