我正在尝试创建一个对话框,在其中定义多个瀑布步骤。在此对话框的上下文中,有时我需要根据用户的选择返回到上一个瀑布步骤。我找到了这种方法:
await stepContext.ReplaceDialogAsync("Name of the dialog");
但是,此方法重新执行整个对话框,这不是我所需要的。
实际上,我创建的瀑布步骤是三个:
我的代码是:
public class ListAllCallsDialog : ComponentDialog
{
// Dialog IDs
private const string ProfileDialog = "ListAllCallsDialog";
/// <summary>
/// Initializes a new instance of the <see cref="ListAllCallsDialog"/> class.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> that enables logging and tracing.</param>
public ListAllCallsDialog(ILoggerFactory loggerFactory)
: base(nameof(ListAllCallsDialog))
{
// Add control flow dialogs
var waterfallSteps = new WaterfallStep[]
{
ListAllCallsDialogSteps.ChoiceCallStepAsync,
ListAllCallsDialogSteps.ShowCallStepAsync,
ListAllCallsDialogSteps.EndDialog,
};
AddDialog(new WaterfallDialog(ProfileDialog, waterfallSteps));
AddDialog(new ChoicePrompt("cardPrompt"));
}
/// <summary>
/// Contains the waterfall dialog steps for the main dialog.
/// </summary>
private static class ListAllCallsDialogSteps
{
static int callListDepth = 0;
static List<string> Calls;
public static async Task<DialogTurnResult> ChoiceCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
await stepContext.Context.SendActivityAsync(
"Right now i'm in list all calls dialog",
cancellationToken: cancellationToken);
GetAllCalls();
return await stepContext.PromptAsync("cardPrompt", GenerateOptions(stepContext.Context.Activity, callListDepth), cancellationToken);
}
public static async Task<DialogTurnResult> ShowCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Get the text from the activity to use to show the correct card
var text = stepContext.Context.Activity.Text.ToLowerInvariant();
if(text == "Show older")
//Go back to the first step
else if(text == "Show earlier")
//Go back to the first step
else
await stepContext.Context.SendActivityAsync(
"The call you choose is : " + text.ToString(),
cancellationToken: cancellationToken);
return await stepContext.ContinueDialogAsync();
}
public static async Task<DialogTurnResult> EndDialog(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
await stepContext.Context.SendActivityAsync(
"Getting back to the parent Dialog",
cancellationToken: cancellationToken);
return await stepContext.EndDialogAsync(null, cancellationToken);
}
/// <summary>
/// Creates options for a <see cref="ChoicePrompt"/> so the user may select an option.
/// </summary>
/// <param name="activity">The message activity the bot received.</param>
/// <returns>A <see cref="PromptOptions"/> to be used in a prompt.</returns>
/// <remarks>Related type <see cref="Choice"/>.</remarks>
private static PromptOptions GenerateOptions(Activity activity, int callListDepth)
{
// Create options for the prompt
var options = new PromptOptions()
{
Prompt = activity.CreateReply("Please choose a call from the list below"),
Choices = new List<Choice>(),
};
for(int i=10*callListDepth; i <= 10 * (callListDepth + 1); i++)
{
if (Calls.ElementAtOrDefault(i) != null)
options.Choices.Add(new Choice() { Value = Calls[i] });
}
options.Choices.Add(new Choice() { Value = "Show older" });
if(callListDepth!=0)
options.Choices.Add(new Choice() { Value = "Show earlier" });
return options;
}
private static void GetAllCalls()
{
//List of all calls found
for (int i = 0; i < 30; i++)
Calls.Add("Call" + i.ToString());
}
}
}
请问有人可以告诉我该怎么做吗?
答案 0 :(得分:5)
我不确定这是否是正确且有效的方法,但是您可以在State
函数中尝试使用context.ActiveDialog
的{{1}}属性。
Task<DialogTurnResult>
答案 1 :(得分:2)
瀑布对话框的设计并不是“倒退”来遍历它们,尽管我认为可能需要这样做。我发现的唯一解决方案是将瀑布分成较小的“微型”瀑布,然后将其嵌套到一个较大的瀑布中。
// define and add waterfall dialogs (main)
WaterfallStep[] welcomeDialogSteps = new WaterfallStep[]
{
MainDialogSteps.PresentMenuAsync,
MainDialogSteps.ProcessInputAsync,
MainDialogSteps.RepeatMenuAsync,
};
然后在MainDialogSteps.ProcessInputAsync中:
public static async Task<DialogTurnResult> ProcessInputAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
var choice = (FoundChoice)stepContext.Result;
var dialogId = Lists.WelcomeOptions[choice.Index].DialogName;
return await stepContext.BeginDialogAsync(dialogId, null, cancellationToken);
}
这允许用户仍在主对话框堆栈内启动新对话框。我提供的选项之一是提示输入电话号码:
WaterfallStep[] phoneChoiceDialogSteps = new WaterfallStep[]
{
PhoneChoicePromptSteps.PromptForPhoneAsync,
PhoneChoicePromptSteps.ConfirmPhoneAsync,
PhoneChoicePromptSteps.ProcessInputAsync,
};
Add(new WaterfallDialog(Dialogs.PhonePrompt, phoneChoiceDialogSteps));
最后,在PhoneChoicePromptSteps.ProcessInputAsync中,我允许从Confirm到ReplaceDialogAsync的选择中选择“否”,并有效地重置此较小的瀑布,而不会影响整个瀑布的其余部分:
public static async Task<DialogTurnResult> ProcessInputAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
if ((bool)stepContext.Result)
{
await stepContext.Context.SendActivityAsync(
$"Calling {stepContext.Values[Outputs.PhoneNumber]}",
cancellationToken: cancellationToken);
return await stepContext.EndDialogAsync(null, cancellationToken);
}
else
{
return await stepContext.ReplaceDialogAsync(Dialogs.PhonePrompt, null, cancellationToken);
}
}
答案 2 :(得分:0)
您可以在方法“ ReplaceDialogAsync”中使用option参数,并通过方法“ NextAsync”跳过步骤。
例如在瀑布步骤中(在构造函数中定义):
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
IntroStepAsync,
ActStepAsync,
FinalStepAsync
}));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
如果要从最后一步(FinalStepAsync)转到第二步(在我的情况下为ActStepAsync),当我要替换对话框时,可以使用在Dialog中创建的标签:
private const string FLAG = "MY_FLAG";
从最后一步调用方法 时,我会这样做:
return await stepContext.ReplaceDialogAsync(InitialDialogId, FLAG, cancellationToken);
因此,如果上下文具有标记:
,那么我只需要在第一步中检查选项 。 // Use the text provided in FinalStepAsync or the default if it is the first time.
var messageText = stepContext.Options?.ToString() ?? "welcome-message";
if (messageText.Equals(FLAG_REPROMPT))
{
return await stepContext.NextAsync(null,cancellationToken);
}
此您在第二步