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



BuildForm Method

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;
}

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

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

虽然FormFlow确实提供了很多可定制性,但它背后的主要思想是为您自动化一切,这往往表明至少有些东西是内置的。

我知道您要做的是在"重试"时禁用字段提示,也就是说,如果用户已经看到字段提示并且他们输入了无效的内容,则不应再次向他们显示提示。我可以在源代码中看到,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不包含任何重试的概念,因此您必须以某种方式自己构建它。您可以在FAQConversation的状态中包含布尔字段作为开关,或者甚至可以使用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;
}
}

相关内容

  • 没有找到相关文章

最新更新