基于 Command Palette 扩展开发的 Adaptive Cards 使用指南
Adaptive Cards 是微软推出的一种开放的卡片交换格式,允许开发者用统一的 JSON 格式描述 UI,然后由不同的宿主应用渲染成原生 UI。
- Schema 版本: 1.6
- 渲染器: WinUI3 AdaptiveCards Renderer
- 文档: adaptivecards.io
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
// 卡片内容元素
],
"actions": [
// 操作按钮
]
}容器用于将多个元素组合在一起,可以设置背景样式。
{
"type": "Container",
"style": "emphasis", // default, emphasis, good, attention, warning, accent
"bleed": true, // 是否扩展到卡片边缘
"items": [
// 子元素
]
}style 可选值:
| 值 | 说明 |
|---|---|
default |
默认样式 |
emphasis |
强调样式(灰色背景) |
good |
成功样式(绿色调) |
attention |
警告样式(红色调) |
warning |
提示样式(黄色调) |
accent |
强调样式(主题色) |
用于创建多列布局。
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto", // auto, stretch, 或具体像素值 "50px"
"verticalContentAlignment": "center", // top, center, bottom
"items": [
// 列内容
]
},
{
"type": "Column",
"width": "stretch",
"items": [
// 另一列内容
]
}
]
}width 可选值:
| 值 | 说明 |
|---|---|
auto |
根据内容自动调整 |
stretch |
填充剩余空间 |
"50px" |
固定像素宽度 |
1, 2 |
权重比例 |
用于显示键值对形式的信息。
{
"type": "FactSet",
"facts": [
{
"title": "用户名:",
"value": "john@example.com"
},
{
"title": "创建日期:",
"value": "2024-01-15"
}
]
}{
"type": "TextBlock",
"text": "标题文本",
"size": "large", // small, default, medium, large, extraLarge
"weight": "bolder", // lighter, default, bolder
"color": "accent", // default, dark, light, accent, good, warning, attention
"wrap": true, // 是否自动换行
"isSubtle": true, // 是否使用柔和颜色
"style": "heading", // default, heading(无障碍标记)
"horizontalAlignment": "center" // left, center, right
}size 可选值:
| 值 | 说明 |
|---|---|
small |
12px |
default |
14px |
medium |
14px |
large |
20px |
extraLarge |
26px |
{
"type": "Image",
"url": "https://example.com/image.png",
"size": "small", // auto, stretch, small, medium, large
"style": "person", // default, person(圆形裁剪)
"altText": "图像描述",
"width": "50px", // 指定宽度
"height": "50px" // 指定高度
}{
"type": "RichTextBlock",
"inlines": [
{
"type": "TextRun",
"text": "普通文本 "
},
{
"type": "TextRun",
"text": "粗体文本",
"weight": "bolder"
},
{
"type": "TextRun",
"text": " 斜体文本",
"italic": true
}
]
}{
"type": "Input.Text",
"id": "inputId", // 必须,用于获取输入值
"label": "输入标签", // 显示在输入框上方
"placeholder": "请输入...",
"style": "text", // text, tel, url, email, password
"isRequired": true, // 是否必填
"errorMessage": "此字段必填",
"isMultiline": false, // 是否多行
"maxLength": 100, // 最大字符数
"regex": "^[a-zA-Z]+$", // 正则验证(1.3+)
"spacing": "medium" // 间距
}style 可选值:
| 值 | 说明 |
|---|---|
text |
普通文本 |
password |
密码(显示为圆点) |
tel |
电话号码 |
url |
URL 地址 |
email |
电子邮箱 |
{
"type": "Input.Number",
"id": "ageInput",
"label": "年龄",
"placeholder": "请输入年龄",
"min": 0,
"max": 150,
"value": 25
}{
"type": "Input.Date",
"id": "birthDate",
"label": "出生日期",
"min": "1900-01-01",
"max": "2024-12-31",
"value": "2000-01-01"
}{
"type": "Input.Time",
"id": "meetingTime",
"label": "会议时间",
"min": "09:00",
"max": "18:00",
"value": "14:00"
}{
"type": "Input.Toggle",
"id": "acceptTerms",
"title": "我同意服务条款",
"label": "请确认:",
"valueOn": "true",
"valueOff": "false",
"value": "false",
"isRequired": true
}{
"type": "Input.ChoiceSet",
"id": "colorChoice",
"label": "选择颜色",
"style": "compact", // compact(下拉), expanded(展开), filtered(可搜索)
"isMultiSelect": false,
"value": "1", // 默认选中值
"choices": [
{
"title": "红色",
"value": "1"
},
{
"title": "绿色",
"value": "2"
},
{
"title": "蓝色",
"value": "3"
}
]
}style 可选值:
| 值 | 说明 |
|---|---|
compact |
下拉列表 |
expanded |
展开的单选/复选框 |
filtered |
可搜索的下拉列表(1.5+) |
{
"type": "Action.Submit",
"title": "提交",
"style": "positive", // default, positive, destructive
"tooltip": "点击提交表单",
"iconUrl": "https://example.com/icon.png",
"data": {
"action": "submit",
"extraData": "value"
}
}style 可选值:
| 值 | 说明 |
|---|---|
default |
默认样式 |
positive |
积极/确认样式(通常为绿色) |
destructive |
危险/删除样式(通常为红色) |
{
"type": "Action.OpenUrl",
"title": "打开网站",
"url": "https://example.com"
}{
"type": "Action.ShowCard",
"title": "显示更多",
"card": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.6",
"body": [
{
"type": "Input.Text",
"id": "comment",
"label": "评论",
"isMultiline": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "提交评论"
}
]
}
}{
"type": "Action.ToggleVisibility",
"title": "显示/隐藏详情",
"targetElements": [
"detailsContainer"
]
}配合使用的元素:
{
"type": "Container",
"id": "detailsContainer",
"isVisible": false,
"items": [
// 详情内容
]
}{
"type": "TextBlock",
"text": "文本",
"spacing": "medium" // none, small, default, medium, large, extraLarge, padding
}| 值 | 像素值 |
|---|---|
none |
0 |
small |
4px |
default |
8px |
medium |
20px |
large |
30px |
extraLarge |
40px |
{
"type": "TextBlock",
"text": "分隔线上方",
"separator": true
}{
"type": "Container",
"height": "stretch" // auto, stretch
}{
"type": "Input.Text",
"id": "name",
"label": "姓名",
"isRequired": true,
"errorMessage": "姓名是必填项"
}{
"type": "Input.Text",
"id": "email",
"label": "邮箱",
"regex": "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$",
"errorMessage": "请输入有效的邮箱地址"
}{
"type": "Action.Submit",
"title": "提交",
"associatedInputs": "auto" // auto, none
}在 Command Palette 扩展中,使用 FormContent 类来创建表单:
internal sealed partial class MyForm : FormContent
{
public MyForm()
{
TemplateJson = """
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
{
"type": "Input.Text",
"id": "myInput",
"label": "输入",
"isRequired": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "提交",
"style": "positive"
}
]
}
""";
}
public override CommandResult SubmitForm(string payload)
{
var formInput = JsonNode.Parse(payload)?.AsObject();
if (formInput == null)
{
return CommandResult.GoBack();
}
var myValue = formInput["myInput"]?.GetValue<string>();
// 处理表单数据...
return CommandResult.Dismiss();
}
}使用 DataJson 进行数据绑定:
TemplateJson = """
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "欢迎,${userName}!"
}
]
}
""";
DataJson = """
{
"userName": "张三"
}
""";在 Command Palette 中,当表单只有一个输入框时,按回车键会自动触发 Action.Submit。这是由 AdaptiveCards WinUI3 渲染器提供的功能。
注意:如果表单有多个输入框,回车键会在输入框之间移动焦点,需要点击按钮或 Tab 到按钮后按回车才能提交。
// ✅ 推荐:使用 Container 和 ColumnSet 组织布局
{
"type": "Container",
"style": "emphasis",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{ "type": "Image", "url": "...", "size": "small" }
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{ "type": "TextBlock", "text": "标题", "weight": "bolder" }
]
}
]
}
]
}// ✅ 推荐:始终为必填字段提供错误消息
{
"type": "Input.Text",
"id": "password",
"label": "密码",
"style": "password",
"isRequired": true,
"errorMessage": "密码是必填项"
}// ✅ 推荐:使用 label 而不是单独的 TextBlock
{
"type": "Input.Text",
"id": "name",
"label": "姓名" // 自带无障碍支持
}
// ❌ 不推荐:使用单独的 TextBlock
{
"type": "TextBlock",
"text": "姓名"
},
{
"type": "Input.Text",
"id": "name"
}// ✅ 推荐:使用语义化的按钮样式
{
"type": "Action.Submit",
"title": "保存",
"style": "positive" // 确认操作用 positive
},
{
"type": "Action.Submit",
"title": "删除",
"style": "destructive" // 危险操作用 destructive
}A: 在 Command Palette 中,单输入框表单会自动支持回车提交。对于多输入框表单,需要用户 Tab 到按钮后按回车,或直接点击按钮。
A: 修改 TemplateJson 或 DataJson 属性后,调用 OnPropertyChanged 通知更新:
DataJson = newData;
OnPropertyChanged(nameof(DataJson));A: 确保图片 URL 可访问,且 HTTPS 协议。也可以使用 data URI:
{
"type": "Image",
"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..."
}A: 在 SubmitForm 中使用第二个参数 data:
public override ICommandResult SubmitForm(string inputs, string data)
{
var inputData = JsonNode.Parse(inputs)?.AsObject(); // 用户输入
var actionData = JsonNode.Parse(data)?.AsObject(); // Action.Submit 的 data
var action = actionData?["action"]?.GetValue<string>();
// ...
}