FormFlow为字符串字段定义选项 [英] FormFlow define options for string field

查看:88
本文介绍了FormFlow为字符串字段定义选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Bot框架,并且正在尝试使用FormFlow动态定义表单.我对一个特定领域有疑问:

I am using bot framework and I am trying to define a form dynamically using FormFlow. I have a problem with one specific field:

.Field(new FieldReflector<IssueFormModel>(nameof(IssueResultModel.ProductPlatform))
                .SetType(typeof(string))
                .SetDefine(async (issue, field) =>
                {
                    if (issue.ProductName != null)
                    {
                        foreach (var platform in productsWithPlatforms[issue.ProductName])
                        {
                            field.AddDescription(platform, platform).AddTerms(platform, platform);
                        }
                    }

                    return await Task.FromResult(true);
                })
                .SetPrompt(new PromptAttribute("Which platform of {ProductName}{||}?"))
                .SetAllowsMultiple(false)
                .SetValidate(async (state, value) => await ValidateProductPlatform(value, state)))

问题在于 ProductPlatform 依赖于 ProductName ,因此它是一个字符串.可以正常运行,但是,通过这种方式,该漫游器不会显示可能的平台的选项(尽管 SetPrompt 中有{||}).

The problem is that ProductPlatform depends on ProductName, therefore it is a string. This works fine, however, this way, the bot does not show the options of possible platforms (although there is {||} in SetPrompt).

当我将type设置为null SetType(null)时,该机器人现在将可能的平台显示为按钮,但是,当用户决定键入错误的平台而不是单击正确的平台时,它将永远不会进入 ValidateProductPlatform 一个(我想验证本身已经在 SetDefine 级别上完成).我需要通过 ValidateProductPlatform 验证用户输入的唯一原因是,我想在3次失败尝试后取消表单.

When I set type to null SetType(null), the bot now shows possible platforms as buttons, however, it never goes to ValidateProductPlatform when user decides to type a wrong platform instead of clicking on the correct one (I guess the validation itself is done already on SetDefine level). The only reason I need to validate user input through ValidateProductPlatform is that I want to cancel the form after 3 unsuccessful attempts.

那么,有什么方法可以实现这一目标?: 用户具有基于ProductName的ProductPlaftorm选项(作为按钮),但没有单击,而是(可能)键入了错误的平台,并且在3次错误尝试后,表单结束了.

So, is there any way to achieve this?: User has options (as buttons) for ProductPlaftorm based on ProductName, but instead of clicking, they (might) type a wrong platform, and after 3 wrong attempts, the form ends.

PS:我看到了 Microsoft Bot:如何在表单流中捕获太多尝试?,但是由于在我的情况下(SetType(null)时) SetValidate 似乎被忽略了,因此我无法使用它

PS: I saw Microsoft Bot : How to capture Too Many Attempts in Form Flow? but I am not able to use it since it appears as if SetValidate was ignored in my case (when SetType(null))

推荐答案

创建同时使用按钮和自定义验证方法(在文本输入和按钮按下时)的提示器的一种技术是在表单上插入提示器替代. 对于您的特定用例,这看起来类似于以下代码块(此实现会覆盖ProductPlatform字段上的原始提示,以便向卡上添加按钮菜单):

One technique to create a prompter that utilizes both buttons and a custom validation method (on text entry and button press) is to insert a prompter override on your form. This will look something like the following block of code for your particular use case (this implementation overrides the original prompt on the ProductPlatform field in order to add a menu of buttons to the card):

form.Prompter(async (context, prompt, state, field) =>
{
    //this part is added in on top of the original implementation of form.Prompter
    if (field.Name == nameof(IssueFormModel.ProductPlatform) && prompt.Buttons.Count == 0)
    {
        foreach (var fieldValue in field.Values)
        {
            var asString = fieldValue as string;
            prompt.Buttons.Add(new DescribeAttribute(asString, title: asString));
        }
    }
    //this check prevents prompts that are sent through from ValidateResult without a FeedbackCard from crashing the bot.
    if (prompt.Description != null) {
        var preamble = context.MakeMessage();
        var promptMessage = context.MakeMessage();
        if (prompt.GenerateMessages(preamble, promptMessage))
        {
            await context.PostAsync(preamble);
        }
        await context.PostAsync(promptMessage);
    }
    return prompt;
});

这意味着构建表单的整个方法应如下所示:

This means the whole of the method in which you build your Form should look something like this:

private IForm<IssueFormModel> BuildProductForm()
{
    var form = new FormBuilder<IssueFormModel>()
       .Field(new FieldReflector<IssueFormModel>(nameof(IssueFormModel.ProductName))
             .SetPrompt(new PromptAttribute("Type either product1 or product2"))
             .SetValidate(async (state, value) => await ValidateProductName(value, state)))
       .Field(new FieldReflector<IssueFormModel>(nameof(IssueFormModel.ProductPlatform))
             .SetType(typeof(string))
             .SetDefine(async (issue, field) =>
             {
                 if (issue.ProductName != null)
                 {
                     foreach (var platform in productsWithPlatforms[issue.ProductName])
                     {
                         field.AddDescription(platform, platform).AddTerms(platform, platform);
                     }
                 }

                 return await Task.FromResult(true);
             })
             .SetPrompt(new PromptAttribute("Which platform of {ProductName}{||}?"))
             .SetAllowsMultiple(false)
             .SetValidate(async (state, value) => await ValidateProductPlatform(value, state)))
       .AddRemainingFields()
       .Confirm(prompt: "Is this your issue? {*}{||}");

    form.Prompter(async (context, prompt, state, field) =>
    {
        if (field.Name == nameof(IssueFormModel.ProductPlatform) && prompt.Buttons.Count == 0)
        {
            foreach (var fieldValue in field.Values)
            {
                var asString = fieldValue as string;
                prompt.Buttons.Add(new DescribeAttribute(asString, title: asString));
            }
        }
        if (prompt.Description != null) {
            var preamble = context.MakeMessage();
            var promptMessage = context.MakeMessage();
            if (prompt.GenerateMessages(preamble, promptMessage))
            {
                await context.PostAsync(preamble);
            }
            await context.PostAsync(promptMessage);
        }
        return prompt;
    });

    return form.Build();

}

此处的主要更改是在FormBuilder的最后一次调用之后插入form.Prompter,而不是立即返回新表单.覆盖的提示使用字符串"类型调用您的自定义验证,并且您应该能够使用其中不成功的条目执行所需的操作.

The main changes here are inserting the form.Prompter after the last call on the FormBuilder and not returning the new form immediately. The overridden prompt uses a type "string" which calls your custom validation, and you should be able to do what you'd like with unsuccessful entries among whatever else there.

这篇关于FormFlow为字符串字段定义选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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