Bot Framework瀑布对话框Hero card封装的Choice prompt在Teams移动端失效
问题根因
该现象由Teams桌面端与移动端对MessageBack类型卡片按钮的回传逻辑差异导致:
- 桌面端点击
MessageBack按钮时,会自动将按钮的Text属性值填充到请求的Activity.Text字段,ChoicePrompt默认读取该字段和预设的Choices列表做匹配,所以流程可以正常走通。 - 移动端点击
MessageBack按钮时,只会将按钮的Value属性值填充到请求的Activity.Value字段,不会填充Activity.Text,而ChoicePrompt默认仅识别Activity.Text的内容,找不到匹配选项时会持续等待有效输入,因此出现点击无反应、无报错的情况。
解决方案
你可以根据需求选择以下任意一种方案修复:
方案1:修改ChoicePrompt识别逻辑(改动最小,保留原有流程)
在定义ChoicePrompt实例时,重写其识别逻辑,让它同时支持匹配Activity.Value和Activity.Text的内容:
var choicePrompt = new ChoicePrompt(nameof(ChoicePrompt)) { Recognizer = async (turnContext, cancellationToken) => { var result = new RecognizerResult<FoundChoice>(); // 优先读取移动端回传的Value,再兜底桌面端的Text var input = turnContext.Activity.Value?.ToString() ?? turnContext.Activity.Text; if (string.IsNullOrWhiteSpace(input)) return result; // 和预设的选项做匹配,可根据需求调整匹配规则 var validOptions = new List<string> { "650", "600", "Cancel" }; var matchedOption = validOptions.FirstOrDefault(opt => opt.Equals(input.Trim(), StringComparison.OrdinalIgnoreCase)); if (matchedOption != null) { result.Succeeded = true; result.Value = new FoundChoice { Value = matchedOption }; } return result; } };
同时给卡片按钮添加Teams专属配置,提升移动端兼容性:
card.Buttons.Add(new CardAction() { Type = ActionTypes.MessageBack, Title = "Option 1", Text = "650", DisplayText = "Option 1", Value = "650", // 新增Teams专属配置,确保移动端正常触发交互 ChannelData = new { Teams = new { AllowMessageInteraction = true } } });
方案2:手动处理按钮回传值(更灵活,适配复杂场景)
如果后续需要在Value中传结构化的隐藏数据,可放弃ChoicePrompt的自动识别能力,自己在瀑布流步骤中处理回传值:
- 首先修改发卡片的步骤,不再调用
PromptAsync,直接发送卡片后等待用户操作:
private async Task<DialogTurnResult> ChoiceStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { await stepContext.Context.SendActivityAsync(new Activity { Type = ActivityTypes.Typing }, cancellationToken); await stepContext.Context.SendActivityAsync(ChoiceToCard(), cancellationToken); return await stepContext.NextAsync(cancellationToken: cancellationToken); }
- 新增下一个瀑布流步骤,手动读取回传的选项值:
private async Task<DialogTurnResult> AfterChoiceStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var activity = stepContext.Context.Activity; var selectedValue = activity.Value?.ToString() ?? activity.Text; // 手动处理选择逻辑 if (selectedValue == "Cancel") { // 取消流程逻辑 return await stepContext.EndDialogAsync("user_cancel", cancellationToken); } if (new List<string> { "650", "600" }.Contains(selectedValue)) { // 正常选择逻辑,将选中的ID传给后续步骤 return await stepContext.EndDialogAsync(selectedValue, cancellationToken); } // 非法输入的重试逻辑 await stepContext.Context.SendActivityAsync("请点击卡片上的按钮选择有效选项", cancellationToken); return await stepContext.ReplaceDialogAsync(nameof(YourWaterfallDialog), cancellationToken: cancellationToken); }
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

