问题描述
TL&DR
ComponentDialog类的OnContinueDialogAsync方法,应允许中断对话框。但是,当我们有3个对话框时:MainDialog> SubDialogA> SubDialogAA,并且我们位于SubDialogAA内部,则中断命令将始终被MainDialog捕获。如何在SubDialogs(活动时)中捕获“较高”的中断,而又不从MainDialog中删除此逻辑?
更多详细信息
因此,根据本文: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-handle-user-interrupt?view=azure-bot-service-4.0&tabs=csharp我们应该使用包含中断处理的CancelAndHelpDialog类来处理中断,然后其他对话框应从该对话框派生。
下面是CancelAndHelpDialog
public class CancelAndHelpDialog : ComponentDialog
{
public InterruptionsHandleDialog (string id)
: base(id)
{
}
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc,CancellationToken cancellationToken = default)
{
var result = await InterruptAsync(innerDc,cancellationToken);
if (result != null)
{
return result;
}
return await base.OnContinueDialogAsync(innerDc,cancellationToken);
}
private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc,CancellationToken cancellationToken)
{
if (innerDc.Context.Activity.Type == ActivityTypes.Message)
{
var text = innerDc.Context.Activity.Text.ToLowerInvariant();
switch (text)
{
case "help":
case "?":
await innerDc.Context.SendActivityAsync("Help",cancellationToken: cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
case "cancel":
return await innerDc.CancelAllDialogsAsync(cancellationToken);
}
}
return null;
}
}
我们有3个对话框,每个对话框都来自CancelAndHelpDialog: 主对话框> SubDialogA> SubDialogAA(>表示此对话框使用BeginDialogAsync调用另一个对话框)
现在,我已经在所有三个对话框中测试了“帮助”,并且可以正常工作。但这是从MainDialog调用的,因为MainDialog中断处理捕获了消息。
但是,“ cancel”仅在MainDialog中可以正常工作,因为它将始终被捕获并取消MainDialog。
当我们处于SubDialogA或SubDialogAA中时,允许取消当前对话框(使用CancelAllDialogs)的一种优雅方法是什么?
此外,如果所有内容仍然被MainDialog捕获,那么SubDialogA和SubDialogAA是否有必要从CancelAndHelpDialog派生出来?
解决方法
发现,如果对话框处于活动状态,则DialogContext(innerDc)的Child属性等于null。这仅允许对活动对话框执行中断:
public class CancelAndHelpDialog : ComponentDialog
{
public InterruptionsHandleDialog (string id)
: base(id)
{
}
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc,CancellationToken cancellationToken = default)
{
var result = await InterruptAsync(innerDc,cancellationToken);
if (result != null)
{
return result;
}
return await base.OnContinueDialogAsync(innerDc,cancellationToken);
}
private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc,CancellationToken cancellationToken)
{
if (innerDc.Context.Activity.Type == ActivityTypes.Message && innerDc.Child == null)
{
var text = innerDc.Context.Activity.Text.ToLowerInvariant();
switch (text)
{
case "help":
case "?":
await innerDc.Context.SendActivityAsync("Help",cancellationToken: cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
case "cancel":
return await innerDc.CancelAllDialogsAsync(cancellationToken);
}
}
return null;
}
}