将消息从自定义提示转发到另一个对话框

Forward message to another dialog from custom prompt

我正在使用 this 自定义 class 来制作自定义提示。

我修改了 tryParse 方法。如果用户不选择任何选项,我想将消息转发到第一个对话框。

代码:

   var promptOptions = new CancelablePromptOptions<string>(MyDictionary.ChooseOneOfTheFollowingOptions, cancelPrompt: "cancel", options: MyHelper.GetOptios(), promptStyler: PromptStyler);
            CancelablePromptChoice<string>.Choice(context, OptionSelected, promptOptions);

我正在尝试覆盖 CancelablePromptOptions 中的 TryParse 函数 class :

   protected override bool TryParse(IMessageActivity message, out T result)
        {
            if (IsCancel(message.Text))
            {
                result = default(T);
                return true;
            }

            bool b =  base.TryParse(message, out result);
            if (!b)
                Conversation.SendAsync(message, () => new MyFirstDialog());
                return base.TryParse(message, out result);
        }

注意代码中的 MyFirstDialog。我想用当前消息重新创建第一个对话框。

目标:如果用户选择了一些存储更多选项的对话框,并且如果第一个 "choose" 无效,我想重新创建 MyFirstDialog。

有什么想法吗?

编辑:

MyFirstDialog 是我从消息控制器调用的第一个 IDialog。

await Conversation.SendAsync(activity, () => new MyFirstDialog());

我正在从 MyFirstDialog 调用当前 IDialog:

context.Call(new CurrentDialog(), CurrentDialog.HandleOptions);

这里是一个关于如何返回初始对话的示例,从最低级别开始。

CancelablePromptChoice代码:

在这里你让基本实现做 "TryParse",但如果它不匹配你会处理它(通过 return 为真并保持值),避免重试

protected override bool TryParse(IMessageActivity message, out T result)
{
    if (IsCancel(message.Text))
    {
        result = default(T);
        return true;
    }

    var parsingTriedSucceeded = base.TryParse(message, out result);

    // here you know if you found one of the options or not, and if not you override
    if (!parsingTriedSucceeded)
    {
        result = (T)Convert.ChangeType(message.Text, typeof(T));
        return true;
    }
    else
    {
        return parsingTriedSucceeded;
    }
}

CurrentDialog代码:

在此代码中,您将在 OptionSelected 中处理您的默认 (T) 回复(这是在您的提示后恢复此对话框时调用的方法)。通过执行 context.Done<string>(null); 您将结束此对话框并返回 MyFirstDialog

[Serializable]
public class CurrentDialog : IDialog<string>
{
    public async Task StartAsync(IDialogContext context)
    {
        var promptOptions = new CancelablePromptOptions<string>(MyDictionary.ChooseOneOfTheFollowingOptions, cancelPrompt: "cancel", options: MyHelper.GetOptions(), promptStyler: PromptStyler);
        CancelablePromptChoice<string>.Choice(context, OptionSelected, promptOptions);
    }

    private async Task OptionSelected(IDialogContext context, IAwaitable<string> result)
    {
        var chose = await result;
        string answer = chose.ToString();

        switch (answer)
        {
            case HelpEnumerator.Agenda:
                await EventHelper.GetEventAgenda(context);
                context.Done<string>(null);
                break;
            case HelpEnumerator.Register:
                context.Call(new RegistrationDialog(), RegistrationDialog.Resume);
                context.Done<string>(null);
                break;
            case HelpEnumerator.Speakers:
                await EventHelper.GetSpeakers(context);
                context.Done<string>(null);
                break;
            case HelpEnumerator.Tickets:
                await EventHelper.GetTickets(context);
                context.Done<string>(null);
                break;
            default:
                context.Done(answer);
                break;  
        }
    }
}

MyFirstDialog代码:

所以最后在您的 MyFirstDialog 中,您必须使用 resume 方法从 CurrentDialog 处理这个 return:

// Somewhere in your logic...
context.Call(new CurrentDialog(), ResumeAfterCurrentDialog);

// On your class:
private async Task ResumeAfterCurrentDialog(IDialogContext context, IAwaitable<string> result)
{
    // You are entering here after "context.Done(...)" in the CurrentDialog. To know the "result" value, take a look at what in the OptionSelected in CurrentDialog => it can be null for the options of the list, or the value in "answer" if it's not one of the options
    // So we only have to test if it's not null, and then send the message again to the bot by using the "context.Activity" value

    var resultText = await result;

    if (resultText != null)
    {
        // Send the message again. It's already the message stored in context.Activity ;)
        IMessageActivity msg = (IMessageActivity)context.Activity;
        await this.MessageReceivedAsync(context, new AwaitableFromItem<IMessageActivity>(msg));
    }
}