首页 > 解决方案 > 在 Task.Delay() 中将元素添加到 XAML 页面

问题描述

我正在构建一个聊天机器人应用程序,其中包含用于传入和传出消息的聊天气泡。对于传入的消息,我给它一个Task.Delay(),现在我想ActivityIndicator在消息弹出之前给它一个(即我想在消息被延迟时显示活动指示器)。我已将活动指示器添加到传入消息控件的 XAML;
传入消息项控件

<ViewCell
    x:Class="BluePillApp.Controls.IncomingMessageItemControl"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:pancake="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
    mc:Ignorable="d">


    <Grid x:Name="Gridoo">
        <pancake:PancakeView
            Margin="10,10,80,10"
            Padding="15"
            BackgroundColor="#53ffc6"
            CornerRadius="20,20,0,20"
            HasShadow="False"
            HorizontalOptions="StartAndExpand">

            <Label
                FontSize="Medium"
                Text="{Binding Text}"
                TextColor="#1a1a1a" />
        </pancake:PancakeView>

        <ActivityIndicator IsRunning="True" IsVisible="True" />
    </Grid>
</ViewCell>

问题是,在 ChatbotMessagingPage 中,按下发送按钮,然后在收到回复/传入消息之前发送传出消息,我已经在 MVVM 中这样做了;
ChatbotMessagingPageViewModel

//This gets the chatbots response for each message
            chatbot.MainUser.ResponseReceived += async (sender, args) =>
            {
                await Task.Delay(1500);
                Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
            };
        }

        #region CLASS METHODS
        /// <summary>
        /// This function sends a message
        /// </summary>
        public void Send()
        {
            if (!string.IsNullOrEmpty(TextToSend))
            {
                var msgModel = new ChatMessageModel() { Text = TextToSend, User = App.User };

                //This adds a new message to the messages collection
                Messages.Add(msgModel);

                var result = chatbot.Evaluate(TextToSend);
                result.Invoke();

                //Removes the text in the Entry after message is sent
                TextToSend = string.Empty;
            }
        }

每次我按下发送按钮时,ActivityIndi​​cator 都会与 IncomingMessage 一起出现,我希望 ActivityIndi​​cator 先出现,而 IncomingMessage 会被延迟。

标签: asynchronousxamarin.formstask

解决方案


我猜那个视图单元格是消息气泡。

当你这样做时:

Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });

您的集合已更新,您的 ListView 或任何持有这些 ViewCelss 的东西也会更新。TheActivityIndicator是 the 的一部分,ViewCell因此它与消息同时出现。

[选项 1] 使用附加标志

您可以做的是创建一个标志IsBusyIsDelay其他东西并将 ActivityIndi​​cator 和 Label 的可见性绑定到它:

<Grid x:Name="Gridoo">
    <pancake:PancakeView
        Margin="10,10,80,10"
        Padding="15"
        BackgroundColor="#53ffc6"
        CornerRadius="20,20,0,20"
        HasShadow="False"
        HorizontalOptions="StartAndExpand">

        <Label
            FontSize="Medium"
            Text="{Binding Text}"
            TextColor="#1a1a1a"
            IsVisible="{Binding IsBusy, Converter={Helpers:InverseBoolConverter}}""> />
    </pancake:PancakeView>

    <ActivityIndicator x:Name="activityIndicator" IsRunning="True" IsVisible="{Binding IsBusy}" />
</Grid>

请注意,我使用 aIValueConverter来否定标签的值。如果您不熟悉它,请检查

剩下的就是在你的ViewModel:

IsBusy = true; // this will make the activity indicator visible, but not the Label
// Also note that you first need to add the message
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot }); 
await Task.Delay(1500);
IsBusy = false; // this will hige the activity indicator visible, and make Label visible

所以基本上逻辑如下:

  1. 您将消息添加到聊天中,但实际文本是隐藏的,而另一方面,活动指示器是可见的。
  2. 你应用延迟
  3. 延迟结束,您更改两个视图的可见性。

请注意,在我的示例中,我没有声明该标志的位置,因为我不确定其余代码的外观。它可以添加到 ChatMessageModel 中,或者ChatMessageViewModel因为您需要为每条消息添加一个标志。

[选项 2] IncomingMessageItemControl.xaml.cs

更好的解决方案可能是在控件后面的代码中处理它。问题是一样的,活动指示器和标签同时出现。

要解决此问题,您可以将延迟移入IncomingMessageItemControl.xaml.cs. 首先,您需要同时添加x:Name活动指示器和标签。

然后你可以这样做:

private async Task ChangeVisibilityAsync()
{
    Label.IsVisibe= false;
    ActivityIndicator.IsVisible = true;
    await Task.Delay(1500);
    Label.IsVisibe = true;
    ActivityIndicator.IsVisible = false;
}

推荐阅读