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

C# 如何防止在FormFlow中重新验证时显示原始提示?,c#,botframework,formflow,C#,Botframework,Formflow,BuildForm方法 publicstaticiformbuildform() { 返回新的FormBuilder() .字段(新字段反射器(名称(查询)) .SetValidate(应答查询) .SetPrompt(新的PrompAttribute(“好的,告诉我你的问题是什么。输入\“返回\”返回产品选择)。) ) .Build(); } 验证方法 私有静态异步任务应答查询(FAQ会话状态、对象值) { var result=new ValidateResult(); //这里有些代码

BuildForm方法

publicstaticiformbuildform()
{
返回新的FormBuilder()
.字段(新字段反射器(名称(查询))
.SetValidate(应答查询)
.SetPrompt(新的PrompAttribute(“好的,告诉我你的问题是什么。输入\“返回\”返回产品选择)。)
)
.Build();
}
验证方法

私有静态异步任务应答查询(FAQ会话状态、对象值)
{
var result=new ValidateResult();
//这里有些代码
if(testCase==false)
{
result.isValid=false;
result.Feedback=“重试”;
}
其他的
{
result.isValid=true;
}
返回结果;
}
当验证字段上的输入无效时,我的验证方法返回反馈“重试”文本。但是,它同时返回原始提示和反馈文本

问题

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

虽然FormFlow提供了很多可定制性,但其背后的主要思想是为您自动化所有内容,这往往表明至少有些内容是非常强大的内置功能

我知道您要做的是在“重试”时禁用字段提示,也就是说,如果用户已经显示字段提示,并且他们输入了无效的内容,则不应再次显示提示。我可以从中看出,FormFlow并没有真正为“重试”提供特例,而字段未知时的提示行为是内置的。然而,你仍然可以做一些事情

FormFlow提供了一种(基本上没有文档记录的)方法来取代所谓的“提示器”。您可以使用这种方法来完成这项工作,这种方法需要花费大量的时间。作为新提示器的起点,您可以在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确定用户输入无效时,关闭开关是一个简单的问题,但是什么时候开关会重新打开?如果用户输入“back”,您希望再次显示提示,该怎么办

虽然您可能会找到更准确地表示“重试时禁用提示”逻辑的方法,但我提出的最简单的解决方案是跟踪生成的最后一条消息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;
    }
}
[可序列化]
公开课常见问题解答对话
{
公共字符串查询{get;set;}
私有字符串LastMessage{get;set;}
private const string TRY_reach=“TRY reach”;
公共静态表单BuildForm()
{
返回新的FormBuilder()
//这是使用Field()方法的另一种方法,但其工作原理相同。
.字段(查询名称),
“好的,告诉我你的问题是什么。输入\“返回\”返回产品选择。”,
验证:AnswerInquiryAsync)
.提示器(提示同步)
.Build();
}
专用静态异步任务AnswerInquiryAsync(FAQ会话状态,对象值)
{
var result=new ValidateResult();
bool testCase=Equals(值,“true”);//输入“true”继续进行测试。
if(testCase==false)
{
result.IsValid=false;
//常量应与在代码中多次出现的字符串一起使用。
结果反馈=再试一次;
}
其他的
{
result.IsValid=true;
//必须提供一个值,否则将不填充该字段。
结果:价值=价值;
}
返回结果;
}
/// 
///下面是我们用于PromptAsyncDelegate的方法。
/// 
专用静态异步任务PromptAsync(IDialogContext上下文,FormPrompt prompt,
常见问题解答(会话状态,IField字段)
{
var preamble=context.MakeMessage();
var promptMessage=context.MakeMessage();
if(prompt.GenerateMessages(序言、promptMessage))
{
等待上下文。后同步(序言);
}
//这里是我们对默认提示器进行更改的地方。
如果(state.LastMessage!=重试)
{
wait context.PostAsync(promptMessage);
}
state.LastMessage=promptMessage.Text;
返回提示;
}
}

如何删除字段重新验证时的原始提示?
即使验证字段无效,也不想再次显示提示?@FeiHan是,因为我给出了
结果。反馈=“重试”
_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;
};
[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;
    }
}