Botframework V4:即使其他对话框处于活动状态,活动对话框的ID也不会更改 [英] Botframework V4: ID of active dialog not changing even when other dialogs are active

查看:71
本文介绍了Botframework V4:即使其他对话框处于活动状态,活动对话框的ID也不会更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要根据活动对话框的ID来做一个条件.

I need to do a condition depending on the Id of the active dialog something like this.

var dc = await _dialogs.CreateContextAsync(turnContext);
if (dc.ActiveDialog != null && dc.ActiveDialog.id == "SkipLuisDialog")
{
    var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}

当我像这样检查OnTurnAsync()上的活动对话框时:

When i check my active dialog on OnTurnAsync() like this:

            if (dc.ActiveDialog != null)
            {
                await dc.Context.SendActivityAsync(dc.ActiveDialog.Id.ToString());
            }   

它总是说"mainDialog",这是我的主对话框的ID.即使在"FAQDialog"或"complaintDialog"上输入即时消息,活动对话框的ID也始终为"mainDialog".为什么在FAQ对话框中的im时活动对话框ID不会更改为"FAQDialog",而在投诉对话框中的im则为什么活动对话框ID不会更改为"complaintDialog"?

It always say "mainDialog" which is the ID of my main dialog. Even when im on the "FAQDialog" or "complaintDialog" the active dialog ID is always "mainDialog". Why is the active dialog Id not changing to "FAQDialog" when im in the FAQ dialog or to "complaintDialog" when im in the complaint dialog?

我的主对话框和其他对话框在另一个类中. 这就是我在OnTurnAsync()上调用mainDialog的方式:

My main dialog and other dialogs are in another class. This is how i call the mainDialog on OnTurnAsync():

  if (!dc.Context.Responded)
            {
                switch (dialogResult.Status)
                {
                    case DialogTurnStatus.Empty:

                        switch (topIntent) // topIntent // text
                        {
                            case GetStartedIntent:
                                await dc.BeginDialogAsync(MainDialogId);
                                break;                          

                            case NoneIntent: 
                            default:
                                await dc.Context.SendActivityAsync("I didn't understand what you just said to me.");
                                break;
                        }

                        break;

                    case DialogTurnStatus.Waiting:
                        // The active dialog is waiting for a response from the user, so do nothing.
                        break;

                    case DialogTurnStatus.Complete:
                        await dc.EndDialogAsync();
                        break;

                    default:
                        await dc.CancelAllDialogsAsync();
                        break;
                }
            }

主对话框:

namespace CoreBot.Dialogs

{ 公共类MainDialog:ComponentDialog { 私有常量字符串InitialId ="mainDialog"; 私有常量字符串TextPromptId ="textPrompt";

{ public class MainDialog : ComponentDialog { private const string InitialId = "mainDialog"; private const string TextPromptId = "textPrompt";

    private const string ComplaintDialogId = "complaintDialog";
    private const string FAQDialogId = "FAQDialog";

    public MainDialog(string dialogId) : base(dialogId)
    {
        WaterfallStep[] waterfallSteps = new WaterfallStep[]
        {
            FirstStepAsync,
            SecondStepAsync,
            ThirdStepAsync,

        };
        AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
        AddDialog(new FAQDialog(FAQDialogId));
        AddDialog(new FileComplaintDialog(ComplaintDialogId));
        AddDialog(new TextPrompt(TextPromptId));
    }

    private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.PromptAsync(
            TextPromptId,
            new PromptOptions
            {
                Prompt = new Activity
                {
                    Type = ActivityTypes.Message,
                    Text = $"What can i do for you?",
                    SuggestedActions = new SuggestedActions()
                    {
                        Actions = new List<CardAction>()
                        {
                                new CardAction() { Title = "Frequently Asked Questions", Type = ActionTypes.ImBack, Value = "Frequently Asked Questions" },
                                new CardAction() { Title = "File a Complaint Ticket", Type = ActionTypes.ImBack, Value = "File a Complaint Ticket" },
                        },
                    },
                },
            });
    }

    private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        var response = stepContext.Result.ToString().ToLower();

        string[] FAQArray = { "frequently asked questions", "question", "ask question" };
        string[] ComplaintsArray = { "file a complaint ticket", "complaint", "file a complaint" };

        if (FAQArray.Contains(response))
        {
            return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);
        }

        if (ComplaintsArray.Contains(response))
        {
            await stepContext.EndDialogAsync();
            return await stepContext.BeginDialogAsync(ComplaintDialogId, cancellationToken: cancellationToken);
        }

        return await stepContext.NextAsync();
    }

    private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.ReplaceDialogAsync(InitialId);
    }

}

}

主对话框调用2个对话框.这就是其中之一.

The Main Dialog calls 2 dialogs. This is one of them.

    namespace CoreBot.Dialogs
{
    public class FAQDialog : ComponentDialog
    {
        private const string InitialId = "FAQDialog";
        private const string ChoicePromptId = "choicePrompt";
        private const string TextPromptId = "textPrompt";
        private const string ConfirmPromptId = "confirmPrompt";

        public FAQDialog(string dialogId) : base(dialogId)
        {
            WaterfallStep[] waterfallSteps = new WaterfallStep[]
            {
                FirstStepAsync,
                SecondStepAsync,
                ThirdStepAsync,
                FourthStepAsync,
            };
            AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
            AddDialog(new ChoicePrompt(ChoicePromptId));
            AddDialog(new ConfirmPrompt(ConfirmPromptId));
            AddDialog(new TextPrompt(TextPromptId));

        }
        private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var choices = new List<Choice>();
            choices.Add(new Choice { Value = "This is Sample Question 1", Synonyms = new List<string> { "Question 1" } });
            choices.Add(new Choice { Value = "This is Sample Question 2", Synonyms = new List<string> { "Question 2" } });

            return await stepContext.PromptAsync(
                ChoicePromptId,
                new PromptOptions
                {
                    Prompt = MessageFactory.Text($"Welcome to FAQ! Choose the number of the question or type your own question."),
                    Choices = choices,
                });
        }

        private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var choiceResult = (stepContext.Result as FoundChoice).Value.ToLower();


            switch (choiceResult)
            {
                case "this is sample question 1":
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Answer to question 1."));
                    break;

                case "this is sample question 2":
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Answer to question 2."));
                    break;

                default:
                    break;
            }

            return await stepContext.NextAsync();
        }

        private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await stepContext.PromptAsync(
                ConfirmPromptId,
                new PromptOptions
                {
                    Prompt = MessageFactory.Text($"Have another question?"),
                });

        }

        private static async Task<DialogTurnResult> FourthStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var confirmResult = (bool)stepContext.Result;

            if (confirmResult)
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Ask away!"));
                return await stepContext.ReplaceDialogAsync(InitialId);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Great!"));
                return await stepContext.EndDialogAsync();
            }
        }

    }
}

推荐答案

这是因为在MainDialog中调用了所有对话框.

This is because all of your dialogs are being called within MainDialog.

这里或多或少是怎么回事:

Here's more or less what's going on:

MyBot.cs(或任何主.cs文件)中,您会看到类似Dialogs = new DialogSet(_dialogStateAccessor)的内容,该内容会创建一个空对话框

In MyBot.cs (or whatever your main .cs file is), you have something like Dialogs = new DialogSet(_dialogStateAccessor) which creates an empty dialog stack:

 ___________

然后使用await dc.BeginDialogAsync(MainDialogId);之类的东西,它将MainDialog添加到对话框堆栈的顶部:

You then use something like await dc.BeginDialogAsync(MainDialogId);, which adds MainDialog to the top of your dialog stack:

 ______________
|  MainDialog  |
|______________|

如果在MainDialog之外调用return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);,则堆栈将如下所示:

If you call return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken); outside of your MainDialog, your stack will look something like this:

 ______________
|  FAQDialogId |
|______________|
 ______________
|  MainDialog  |
|______________|

但是,您是从MainDialog内部调用return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);的,因此它是自己的堆栈,因此FAQDialog是MainDialog中的活动对话框,但是您的Dialogs堆栈仍将MainDialog作为ActiveDialog.因此,您的堆栈或多或少是这样的:

However, you call return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken); from within MainDialog, which has it's own stack, so FAQDialog is the active dialog within MainDialog, but your Dialogs stack still has MainDialog as the ActiveDialog. So, your stack is more or less like this:

 _______________________
| ______________        |
| |__FAQDialog__|       |
|                       |
|            MainDialog |
|_______________________|

做自己想做的事

您有两种选择:

Doing What You Want

You have a couple of options:

1.从MainDialog外部调用所有其他对话框.

1. Call all of your other dialogs from outside of MainDialog.

如果您不打算返回MainDialog,则可以执行以下操作:

If you're not going to come back to MainDialog, you could do something like:

MainDialog中:

return await stepContext.EndDialogAsync("FAQDialog");

MyBot.cs中:

switch (dialogResult)
{
    case "FAQDialog":
        dc.BeginDialogAsync(FAQDialogId, cancellationToken);
        break;
    case "ComplaintDialog":
        dc.BeginDialogAsync(ComplaintDialogId, cancellationToken);
        break;
}

2.在ActiveDialog堆栈中挖出对话框的ID

if (dc.ActiveDialog != null && IsDialogInStack(dc.ActiveDialog, "SkipLuisDialog"))
{
    var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}

[...]

private bool IsDialogInStack(DialogInstance activeDialog, string searchId)
{
    if (activeDialog.Id == searchId)
    {
        return true;
    };
    foreach (KeyValuePair<string, object> item in activeDialog.State)
    {
        if (item.Key == "dialogs" && item.Value is DialogState)
        {
            DialogState dialogState = (DialogState)item.Value;
            foreach (DialogInstance dialog in dialogState.DialogStack)
            {
                return IsDialogInStack(dialog, searchId);
            }
        }
    }
    return false;
}

注意:我不是C#专家,也许可以有一种更好的方法来编码IsDialogInStack,但是上面的代码可以正常工作.

Note: I'm not a C# expert and there might be a better way to code IsDialogInStack, but the code above works fine.

这篇关于Botframework V4:即使其他对话框处于活动状态,活动对话框的ID也不会更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆