如何在Microsoft Bot Framework v4中用户选择后禁用/隐藏Adaptive Cards
解决方案:Adaptive Card选择完成后禁用/隐藏卡片(Bot Framework v4 + Adaptive Card 1.2)
方法1:通过消息更新替换为已禁用的Adaptive Card
核心思路是用户提交选择后,后端生成一个禁用所有交互控件的卡片版本,调用Bot Framework的消息更新接口替换原卡片,从根源上避免重复操作。
实现步骤(C#示例)
- 发送原卡片时记录消息ID,存入会话状态方便后续更新
- 用户提交选择后,标记会话状态为已完成
- 生成禁用版卡片(给所有交互控件设置
IsDisabled = true,或替换为结果提示文本) - 调用
UpdateActivityAsync替换原消息
// 定义原交互卡片 var originalCard = new AdaptiveCard(new AdaptiveSchemaVersion(1, 2)) { Body = { new AdaptiveTextBlock("请选择一个选项:") }, Actions = { new AdaptiveSubmitAction { Title = "选项A", Data = new { Choice = "A" }, Id = "actionA" }, new AdaptiveSubmitAction { Title = "选项B", Data = new { Choice = "B" }, Id = "actionB" } } }; // 发送卡片并记录消息ID var response = await turnContext.SendActivityAsync(MessageFactory.Attachment(new Attachment { ContentType = AdaptiveCard.ContentType, Content = originalCard })); await _conversationState.CreateProperty<string>("CardActivityId").SetAsync(turnContext, response.Id); // 处理用户提交的选择 var submittedData = turnContext.Activity.Value as JObject; if (submittedData != null) { // 标记选择已完成 await _conversationState.CreateProperty<bool>("ChoiceCompleted").SetAsync(turnContext, true); // 生成禁用版卡片 var disabledCard = new AdaptiveCard(new AdaptiveSchemaVersion(1, 2)) { Body = { new AdaptiveTextBlock($"你已选择:{submittedData["Choice"]}") }, Actions = { new AdaptiveSubmitAction { Title = "选项A", Data = new { Choice = "A" }, Id = "actionA", IsDisabled = true }, new AdaptiveSubmitAction { Title = "选项B", Data = new { Choice = "B" }, Id = "actionB", IsDisabled = true } } }; // 获取原消息ID并更新 var cardActivityId = await _conversationState.CreateProperty<string>("CardActivityId").GetAsync(turnContext, () => string.Empty); if (!string.IsNullOrEmpty(cardActivityId)) { await turnContext.UpdateActivityAsync(MessageFactory.Attachment(new Attachment { ContentType = AdaptiveCard.ContentType, Content = disabledCard }, id: cardActivityId)); } }
方法2:利用Adaptive Card可见性规则隐藏控件
Adaptive Card 1.2支持visibility属性,可通过状态变量动态隐藏交互控件。需在卡片中绑定状态参数,后端提交后传递状态更新卡片。
示例卡片JSON(可转译为C#对象)
{ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.2", "body": [ { "type": "TextBlock", "text": "${ChoiceCompleted ? '选择已完成' : '请选择一个选项:'}" }, { "type": "ChoiceSet", "id": "UserChoice", "choices": [{"title": "选项A", "value": "A"}, {"title": "选项B", "value": "B"}], "isVisible": "${!ChoiceCompleted}" } ], "actions": [ { "type": "Action.Submit", "title": "提交", "isVisible": "${!ChoiceCompleted}", "data": { "Action": "SubmitChoice" } } ] }
后端处理提交后,将ChoiceCompleted设为true并更新卡片,前端会自动隐藏交互控件。
方法3:会话状态校验,忽略重复提交
通过会话状态记录用户是否已完成选择,即使用户回滚提交,后端直接忽略重复请求。
实现代码(C#示例)
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default) { if (turnContext.Activity.Type == ActivityTypes.Message && turnContext.Activity.Value != null) { // 检查是否已完成选择 var isCompleted = await _conversationState.CreateProperty<bool>("ChoiceCompleted").GetAsync(turnContext, () => false); if (isCompleted) { await turnContext.SendActivityAsync("你已完成选择,无需重复操作。"); return; } // 处理正常选择逻辑 var submittedData = turnContext.Activity.Value as JObject; // ... 业务逻辑处理 ... // 标记选择完成 await _conversationState.CreateProperty<bool>("ChoiceCompleted").SetAsync(turnContext, true); } // 其他逻辑处理 await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken); }
注意事项
- 方法1是最稳妥的方案,直接替换原消息,用户回滚后看到的就是禁用状态的卡片
- 需确保客户端(如Teams、Web Chat)支持Adaptive Card 1.2的
isDisabled和visibility属性 - 若在Teams环境使用,需注意Teams对Adaptive Card的部分属性有特殊兼容性限制,需提前测试
内容的提问来源于stack exchange,提问作者Perry Vo
相关产品推荐
相关产品推荐

