如何防止原始提示在FormFlow中重新验证时显示?

时间:2018-08-14 10:24:02

标签: c# botframework formflow

  

BuildForm方法

        public static IForm<FAQConversation> BuildForm()
        {
            return new FormBuilder<FAQConversation>()
                .Field(new FieldReflector<FAQConversation>(nameof(Inquiry))
                    .SetValidate(AnswerInquiry)
                    .SetPrompt(new PromptAttribute("Okay, tell me what is your question. Enter \"back\" to go back to Products Selection."))
                    )
                .Build();
        }
  

验证方法

        private static async Task<ValidateResult> AnswerInquiry(FAQConversation state, object value)
        {
             var result = new ValidateResult();
             //somecode here
             if(testCase == false)
             {
                result.isValid = false;
                result.Feedback = "Try again";
             }
             else
             {
                result.isValid = true;
             }
             return result;
        }

当我的验证字段上的输入无效时,我的验证方法将返回反馈“重试”文本。但是,它会同时返回“原始提示”和“反馈”文本。

问题
如何删除重新验证字段的原始提示?

1 个答案:

答案 0 :(得分:1)

尽管FormFlow确实提供了很多可定制性,但其背后的主要思想是为您自动化所有操作,这往往表明至少某些功能是非常强大的。

我了解您要执行的操作是在“重试”时禁用字段提示,也就是说,如果用户已经显示了字段提示,而他们输入的内容无效,则不应再次显示提示。我可以在source code中看到,FormFlow并没有真正为“重试”提供特殊情况,而提示字段何时仍为未知状态的行为是其中的一种内置行为。但是,您仍然可以做些什么。

FormFlow提供了一种(基本上未记录在案的)方式来代替所谓的“提示”。您可以使用Prompter()方法,使用PromptAsyncDelegate方法。作为新提示的起点,您可以在FormBuilder源代码中找到默认提示:

_form._prompter = async (context, prompt, state, field) =>
{
    var preamble = context.MakeMessage();
    var promptMessage = context.MakeMessage();
    if (prompt.GenerateMessages(preamble, promptMessage))
    {
        await context.PostAsync(preamble);
    }
    await context.PostAsync(promptMessage);
    return prompt;
};

尽管默认提示器总是发布promptMessage,但是您的替换内容可以用if语句将该行括起来。剩下的问题是您的状况应该如何。我们已经确定FormFlow不包含任何重试概念,因此您必须以某种方式自己构建它。您可以在BooleanConversation的状态中包含一个布尔字段作为开关,或者甚至可以使用PrivateConversationData,因为提示器允许您访问DialogContext。您可能会认为,仅在显示一次提示时或在AnswerInquiryAsync确定用户输入无效时关闭开关,这很简单,但是什么时候才能重新打开开关呢?如果用户输入“返回”并且您希望再次显示该提示怎么办?

虽然您可能会找到某种方法来更准确地表示“禁用重试提示”的逻辑,但我想到的最简单的解决方案是跟踪最后生成的消息FormFlow,然后跳过随后出现的第一个消息“再试一次。”看起来像这样:

[Serializable]
public class FAQConversation
{
    public string Inquiry { get; set; }

    private string LastMessage { get; set; }

    private const string TRY_AGAIN = "Try again";

    public static IForm<FAQConversation> BuildForm()
    {
        return new FormBuilder<FAQConversation>()
            // This is an alternative way of using the Field() method but it works the same.
            .Field(nameof(Inquiry),
                "Okay, tell me what is your question. Enter \"back\" to go back to Products Selection.",
                validate: AnswerInquiryAsync)
            .Prompter(PromptAsync)
            .Build();
    }

    private static async Task<ValidateResult> AnswerInquiryAsync(FAQConversation state, object value)
    {
        var result = new ValidateResult();
        bool testCase = Equals(value, "true");  // Enter "true" to continue for testing purposes.

        if (testCase == false)
        {
            result.IsValid = false;
            // A constant should be used with strings that appear more than once in your code.
            result.Feedback = TRY_AGAIN;
        }
        else
        {
            result.IsValid = true;
            // A value must be provided or else the Field will not be populated.
            result.Value = value;
        }

        return result;
    }

    /// <summary>
    /// Here is the method we're using for the PromptAsyncDelegate.
    /// </summary>
    private static async Task<FormPrompt> PromptAsync(IDialogContext context, FormPrompt prompt,
        FAQConversation state, IField<FAQConversation> field)
    {
        var preamble = context.MakeMessage();
        var promptMessage = context.MakeMessage();

        if (prompt.GenerateMessages(preamble, promptMessage))
        {
            await context.PostAsync(preamble);
        }

        // Here is where we've made a change to the default prompter.
        if (state.LastMessage != TRY_AGAIN)
        {
            await context.PostAsync(promptMessage);
        }

        state.LastMessage = promptMessage.Text;

        return prompt;
    }
}