我正在使用Bot Framework V4.3,我想检索自适应卡提交值

时间:2019-05-17 06:15:02

标签: botframework

我正在使用Bot框架V4.3,我一直在瀑布对话框中使用自适应卡,以获取用户信息,我希望在用户单击“提交”按钮后获取值,并且我想返回上一步如果用户单击“后退”按钮。

这是我的自适应卡的样子

Adaptive card

我尝试了@mdrichardson在Stack Overflow中给出的解决方案 但是自适应卡会再次提示。

下面的代码帮助我们返回上一步,但如何将其实现到自适应卡的后退按钮上。

stepContext.ActiveDialog.State["stepIndex"] =(int)stepContext.ActiveDialog.State["stepIndex"] - 2;

将自适应卡添加到对话框。 我什至用TextPrompt代替ChoicePrompt

AddDialog(new ChoicePrompt("AdaptiveCardPrompt") { Style = ListStyle.None });

这就是我显示自适应卡的方式。我的自适应卡为Json格式

cardAttachment = CreateAdaptiveCardAttachment();

return await stepContext.PromptAsync("AdaptiveCardPrompt",
    new PromptOptions
    {
        Prompt = (Activity)MessageFactory.Attachment(new Attachment
        {
            ContentType = AdaptiveCard.ContentType,
            Content = cardAttachment.Content
        }),
    }, cancellationToken);

请帮助我解决此问题。预先谢谢你

编辑1 :@mdrichardson这是我设置对话框调用的方式

        public static async Task Run(this Dialog dialog, ITurnContext turnContext,IStatePropertyAccessor<DialogState> accessor, CancellationToken cancellationToken = default(CancellationToken))
        {
            var dialogSet = new DialogSet(accessor);
            dialogSet.Add(dialog);

            var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken);
            // Ensure that message is a postBack (like a submission from Adaptive Cards)
            if (dialogContext.Context.Activity.GetType().GetProperty("ChannelData") != null)
            {
                var channelData = JObject.Parse(dialogContext.Context.Activity.ChannelData.ToString());
                if (channelData.ContainsKey("postBack"))
                {
                    var postbackActivity = dialogContext.Context.Activity;
                    // Convert the user's Adaptive Card input into the input of a Text Prompt
                    // Must be sent as a string
                    postbackActivity.Text = postbackActivity.Value.ToString();
                    await dialogContext.Context.SendActivityAsync(postbackActivity);
                }
            }
            var results = await dialogContext.ContinueDialogAsync(cancellationToken);
            if (results.Status == DialogTurnStatus.Empty)
            {
                await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
            }
        }

OnTurnAsync方法中

 if (turnContext.Activity.Type == ActivityTypes.Message)
 {
      await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
 }

编辑2 :我修改了代码,可以转到下一个瀑布步骤。但是我在这里面临另一个问题。 下一个提示没有显示,但我可以在日志中看到它 这就是它在模拟器中的显示方式

Emulator View

一旦用户单击MoreInfoAsync方法中的按钮控件着陆点

 private async Task<DialogTurnResult> MoreInfoAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
 {
            var goback = JObject.Parse(stepContext.Result.ToString());
            stepContext.Values["AdaptiveCardDetails"] = stepContext.Result.ToString();

            if (goback.ContainsKey("goBack"))
            {
                return await stepContext.ReplaceDialogAsync(InitialDialogId);
            }
            // stepContext.ActiveDialog.State["stepIndex"] = (int)stepContext.ActiveDialog.State["stepIndex"] - 2;

            else
                return await stepContext.PromptAsync("MoreInfo", new PromptOptions { Prompt = MessageFactory.Text("Tell Me more.") }, cancellationToken);
 }

我想进入初始对话框,所以我正在使用ReplaceDialogAsync

MoreInfo对话框未显示在模拟器中,但显示在日志中

编辑3 :这是瀑布台阶的完整代码

          // This array defines how the Waterfall will execute.
                        var waterfallSteps = new WaterfallStep[]
                        {
                            ChoiceAsync,
                            CardAsync,
                            MoreInfoAsync,
                            ConfirmAsync
                        };
                        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
                        AddDialog(new ChoicePrompt("ChoiceType"));
                        AddDialog(new TextPrompt("AdaptiveCardPrompt"));
                        AddDialog(new TextPrompt("MoreInfo"));
                        InitialDialogId = nameof(WaterfallDialog);

            private async Task<DialogTurnResult> ChoiceAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                options = new PromptOptions()
                {
                    Prompt = MessageFactory.Text("Select the Choice"),
                    RetryPrompt = MessageFactory.Text("That was not a valid choice."),
                    Choices = GetChoices(),
                    Style = ListStyle.HeroCard
                };
                return await stepContext.PromptAsync("ChoiceType", options, cancellationToken);
            }


            private  async Task<DialogTurnResult> CardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {

                var cardAttachment = new Attachment();
                stepContext.Values["leaveType"] = stepContext.Result.ToString();
                cardAttachment = CreateAdaptiveCardAttachment();
                return await stepContext.PromptAsync("AdaptiveCardPrompt",
                new PromptOptions
                {
                     Prompt = (Activity)MessageFactory.Attachment(new Attachment
                     {
                         ContentType = AdaptiveCard.ContentType,
                         Content = cardAttachment.Content,
                     }),
                }, cancellationToken);
            }

            private async Task<DialogTurnResult> MoreInfoAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                var goback = JObject.Parse(stepContext.Result.ToString());
                stepContext.Values["AdaptiveCardDetails"] = stepContext.Result.ToString();

                if (goback.ContainsKey("goBack"))
                {
                    return await stepContext.ReplaceDialogAsync(InitialDialogId);
                }
                else return await stepContext.PromptAsync("MoreInfo", new PromptOptions { Prompt = MessageFactory.Text("Tell Me more.") }, cancellationToken);
            }

            private async Task<DialogTurnResult> ConfirmAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                stepContext.Values["MoreInfo"] = stepContext.Result;
                //As of now I wouldn't perform any task here so I'll end
                return await stepContext.EndDialogAsync();
            }

1 个答案:

答案 0 :(得分:0)

应对再次提示

问题出在您的OnTurnAsync()方法上:

 if (turnContext.Activity.Type == ActivityTypes.Message)
 {
      await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
 }

每次用户发送消息时,都会导致运行对话框的新实例。由于自适应卡输入是作为回发消息(仍然是消息)发送的,因此它将使对话框再次运行,从而再次提示用户。

如果您要从OnTurnAsync()OnMessageAsync()运行对话框,则应该执行以下两项操作:

  1. 使用if / switch语句。例如,如果消息包含“帮助”,请运行“帮助对话框”,或者

  2. 启动一个对话框,该对话框保存用户响应并根据需要跳过步骤。您可以在Core Bot's Booking Dialog中看到一个示例。请注意,它如何在每一步中使用诸如bookingDetails.TravelDate = (string)stepContext.Result;之类的内容来保存用户响应,并在提示诸如if (bookingDetails.TravelDate == null)之类的提示之前检查它是否存在于上一步中。对于您来说,您可以存储userProfile.AdaptiveCardDetails之类的东西。

返回按钮

要使后退按钮正常工作,假设您的自适应卡中的后退按钮看起来像这样:

{
    "type": "Action.Submit",
    "title": "Back",
    "data": {
        "goBack": "true",
    }
},

当用户单击“返回”时,该机器人将收到带有以下内容的活动:

enter image description here

由于用户想返回而您不需要数据,因此您可以执行以下操作:

// Ensure that message is a postBack (like a submission from Adaptive Cards)
if (dc.Context.Activity.GetType().GetProperty("ChannelData") != null)
{
    var channelData = JObject.Parse(dc.Context.Activity.ChannelData.ToString());
    if (channelData.ContainsKey("postBack") && turnContext.Activity.Value.GetType().GetProperty("goBack"))
    {
        dc.Context.Activity.Text = "Back";
    }
}

,然后在“对话”步骤中:

if (stepContext.Result == "Back")
{
    stepContext.ActiveDialog.State["stepIndex"] = (int)stepContext.ActiveDialog.State["stepIndex"] - 2;
}