web-dev-qa-db-fra.com

Bot Framework v4.0 comment exécuter l'étape précédente en cascade dans une boîte de dialogue

J'essaie de créer une boîte de dialogue dans laquelle je définis plusieurs étapes en cascade. Dans le cadre de cette boîte de dialogue, j'ai parfois besoin de revenir à l'étape précédente en cascade selon le choix de l'utilisateur. J'ai trouvé cette méthode:

 await stepContext.ReplaceDialogAsync("Name of the dialog");

cependant, cette méthode réexécute toute la boîte de dialogue et ce n'est pas ce dont j'ai besoin.

En fait, les étapes de cascade que j'ai créées sont trois:

  • ChoiceCallStepAsync: La première étape répertorie les 10 premiers appels de l'utilisateur avec les options pour afficher les étapes plus anciennes
  • ShowCallStepAsync: La deuxième étape affichera l'appel que l'utilisateur choisira ou retournera à la première étape si l'utilisateur a cliqué sur "afficher plus ancien"
  • EndDialog: la troisième étape mettra fin à la boîte de dialogue

Mon code est:

public class ListAllCallsDialog : ComponentDialog
    {

        // Dialog IDs
        private const string ProfileDialog = "ListAllCallsDialog";



        /// <summary>
        /// Initializes a new instance of the <see cref="ListAllCallsDialog"/> class.
        /// </summary>
        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> that enables logging and tracing.</param>
        public ListAllCallsDialog(ILoggerFactory loggerFactory)
            : base(nameof(ListAllCallsDialog))
        {
            // Add control flow dialogs
            var waterfallSteps = new WaterfallStep[]
            {
                   ListAllCallsDialogSteps.ChoiceCallStepAsync,
                   ListAllCallsDialogSteps.ShowCallStepAsync,
                   ListAllCallsDialogSteps.EndDialog,
            };
            AddDialog(new WaterfallDialog(ProfileDialog, waterfallSteps));
            AddDialog(new ChoicePrompt("cardPrompt"));
        }

        /// <summary>
        /// Contains the waterfall dialog steps for the main dialog.
        /// </summary>
        private static class ListAllCallsDialogSteps
        {
            static int callListDepth = 0;
            static List<string> Calls;
            public static async Task<DialogTurnResult> ChoiceCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                await stepContext.Context.SendActivityAsync(
                   "Right now i'm in list all calls dialog",
                   cancellationToken: cancellationToken);
                GetAllCalls();
                return await stepContext.PromptAsync("cardPrompt", GenerateOptions(stepContext.Context.Activity, callListDepth), cancellationToken);
            }

            public static async Task<DialogTurnResult> ShowCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                // Get the text from the activity to use to show the correct card
                var text = stepContext.Context.Activity.Text.ToLowerInvariant();
                if(text == "Show older")
                    //Go back to the first step
                else if(text == "Show earlier")
                    //Go back to the first step
                else
                    await stepContext.Context.SendActivityAsync(
                   "The call you choose is : " + text.ToString(),
                   cancellationToken: cancellationToken);
                   return await stepContext.ContinueDialogAsync();

            }

            public static async Task<DialogTurnResult> EndDialog(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                await stepContext.Context.SendActivityAsync(
               "Getting back to the parent Dialog",
               cancellationToken: cancellationToken);
                return await stepContext.EndDialogAsync(null, cancellationToken);
            }

            /// <summary>
            /// Creates options for a <see cref="ChoicePrompt"/> so the user may select an option.
            /// </summary>
            /// <param name="activity">The message activity the bot received.</param>
            /// <returns>A <see cref="PromptOptions"/> to be used in a Prompt.</returns>
            /// <remarks>Related type <see cref="Choice"/>.</remarks>
            private static PromptOptions GenerateOptions(Activity activity, int callListDepth)
            {
                // Create options for the Prompt
                var options = new PromptOptions()
                {
                    Prompt = activity.CreateReply("Please choose a call from the list below"),
                    Choices = new List<Choice>(),
                };


                for(int i=10*callListDepth; i <= 10 * (callListDepth + 1); i++)
                {
                    if (Calls.ElementAtOrDefault(i) != null)
                      options.Choices.Add(new Choice() { Value = Calls[i] });

                }
                options.Choices.Add(new Choice() { Value = "Show older" });
                if(callListDepth!=0)
                    options.Choices.Add(new Choice() { Value = "Show earlier" });
                return options;
            }
            private static void GetAllCalls()
            {

                //List of all calls found
                for (int i = 0; i < 30; i++)
                  Calls.Add("Call" + i.ToString());
            }

        }

}

Quelqu'un peut-il me montrer comment faire cela, s'il vous plaît?

9
Soufien Hajji

Je ne suis pas sûr, si c'est la bonne et efficace façon de le faire, mais vous pouvez expérimenter avec la propriété State de la context.ActiveDialog dans votre Task<DialogTurnResult> fonction.

context.ActiveDialog.State["stepIndex"] = (int)context.ActiveDialog.State["stepIndex"] -2;
10
Liam Kernighan

Les dialogues en cascade n'étaient pas conçus avec l'idée de `` reculer '' pour les traverser, bien que je puisse voir la nécessité éventuelle de le faire. La seule solution que j'ai trouvée est de briser votre cascade en petites "mini" cascades et de les emboîter dans une plus grande cascade.

        // define and add waterfall dialogs (main)
        WaterfallStep[] welcomeDialogSteps = new WaterfallStep[]
        {
            MainDialogSteps.PresentMenuAsync,
            MainDialogSteps.ProcessInputAsync,
            MainDialogSteps.RepeatMenuAsync,
        };

Puis dans MainDialogSteps.ProcessInputAsync:

        public static async Task<DialogTurnResult> ProcessInputAsync(
            WaterfallStepContext stepContext,
            CancellationToken cancellationToken)
        {
            var choice = (FoundChoice)stepContext.Result;
            var dialogId = Lists.WelcomeOptions[choice.Index].DialogName;

            return await stepContext.BeginDialogAsync(dialogId, null, cancellationToken);
        }

Cela permet aux utilisateurs de démarrer de nouvelles boîtes de dialogue toujours dans la pile de boîtes de dialogue principale. Une de mes options que j'ai offert était une invite d'une liste de numéros de téléphone:

        WaterfallStep[] phoneChoiceDialogSteps = new WaterfallStep[]
        {
            PhoneChoicePromptSteps.PromptForPhoneAsync,
            PhoneChoicePromptSteps.ConfirmPhoneAsync,
            PhoneChoicePromptSteps.ProcessInputAsync,
        };

        Add(new WaterfallDialog(Dialogs.PhonePrompt, phoneChoiceDialogSteps));

Et enfin, dans PhoneChoicePromptSteps.ProcessInputAsync, j'ai autorisé la sélection de `` non '' de la confirmation à ReplaceDialogAsync et réinitialisé efficacement cette petite cascade, sans affecter le reste de la cascade globale:

 public static async Task<DialogTurnResult> ProcessInputAsync(
            WaterfallStepContext stepContext,
            CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
            {
                await stepContext.Context.SendActivityAsync(
                    $"Calling {stepContext.Values[Outputs.PhoneNumber]}",
                    cancellationToken: cancellationToken);
                return await stepContext.EndDialogAsync(null, cancellationToken);
            }
            else
            {
                return await stepContext.ReplaceDialogAsync(Dialogs.PhonePrompt, null, cancellationToken);
            } 
        }

enter image description here

4
JJ_Wailes