FormFlow: add multiple entities using recurring qu

2019-07-18 23:55发布

问题:

I've been playing around with the bot framework and creating a chat bot for fun that lets you detail the members of your family/pets.

Is there a way to recur over the same set of questions until the user is satisfied? Example code below:

    [Prompt("What is your family name?")]
    public string familyName{ get; set; }

    [Prompt("What is your postcode?")]
    public string postcode { get; set; }

    [Prompt("Would you like to add a family member? {||}")]
    public bool AddPerson { get; set; }

    [Prompt("What is their name?")]
    public string PersonName { get; set; }

    [Prompt("How old are they?")]
    public string PersonAge{ get; set; }

    [Prompt("How are they related to you?")]
    public string PersonRelation{ get; set; }

    [Prompt("Would you like to add another family member? {||}")]
    public bool addAnotherPerson { get; set; }

 public IForm<Family> BuildForm()
    {
        return new FormBuilder<GetQuoteDialog>()
            .Field(nameof(familyName))
            .Field(nameof(postcode))

            //Choose to add a person to the family
            .Field(nameof(AddPerson))

            //Details of that person.
            .Field(new FieldReflector<Family>(nameof(PersonName))
            .SetActive((state) => state.AddPerson== true))
            .Field(new FieldReflector<Family>(nameof({PersonAge))
            .SetActive((state) => state.AddPerson== true))
            .Field(new FieldReflector<Family>(nameof({PersonRelation))
            .SetActive((state) => state.AddPerson== true))

            //Prompts the user to add another if they wish
            //Recurs to the PersonName field and lets them go through the 
            //process of adding another member
            .Field(new FieldReflector<Family>(nameof({AddAnotherMember))
            .SetActive((state) => state.AddPerson== true))


            .Confirm("Is this your family? {*}")
            .Build();
    }
}

Does anyone have an idea on how to accomplish this?

I call the formflow like this:

public async Task confirmAdd(IDialogContext context, IAwaitable<bool> result)
    {
        if (await result)
        {
            // builds and calls the form from here
            var myform = new FormDialog<BuildFamily>(new BuildFamily(), BuildForm, FormOptions.PromptInStart, null);
            context.Call<BuildFamily>(myform, End);
        }
    }

    private async Task End(IDialogContext context, IAwaitable<BuildFamily> result)
    {
        BuildFamily data = null;
        try
        {
            data = await result;
            await context.PostAsync("Nice family you got there :)");
        }
        catch (OperationCanceledException)
        {
            await context.PostAsync("You canceled the form!");
            return;
        }
    }

回答1:

I'm not sure how to "recur over the same set of questions until the user is satisfied" within a FormFlow dialog. However, you can ask the user the question "Would you like to add more family members?" in the calling dialog, and achieve the same type of conversation flow. Remove the PostalCode and FamilyName type questions, and put them in a separate dialog. Then, in the add family members dialog do something like this:

[Serializable]
    public class AddFamilyMembersDialog : IDialog<object>
    {
        List<Family> _familyMembers = new List<Family>();

        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            return Task.CompletedTask;
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {
            PromptAddMembers(context);
        }

        private void PromptAddMembers(IDialogContext context)
        {
            PromptDialog.Text(context, AfterPromptAdd, "Would you like to add more family members?", null, 1);
        }

        private async Task AfterPromptAdd(IDialogContext context, IAwaitable<string> result)
        {
            var yesno = await result;

            if (yesno.ToLower() == "yes")
            {
                await context.Forward(FormDialog.FromForm(Family.BuildForm), AfterAdded, null, CancellationToken.None);
            }
            else
            {
                //_familyMembers contains everyone the user wanted to add
                context.Done(true);
            }
        }

        private async Task AfterAdded(IDialogContext context, IAwaitable<Family> result)
        {
            var member = await result;
            if (member != null)
                _familyMembers.Add(member);

            PromptAddMembers(context);
        }

        [Serializable]
        public class Family
        {
            [Prompt("What is their name?")]
            public string PersonName { get; set; }

            [Prompt("How old are they?")]
            public string PersonAge { get; set; }

            [Prompt("How are they related to you?")]
            public string PersonRelation { get; set; }

            public static IForm<Family> BuildForm()
            {
                return new FormBuilder<Family>()
                .AddRemainingFields()
                .Build();
            }
        }

    }