将数组数据存储在卡中的简单示例
Simple example to store array data in card
我想了解如何使用自适应卡片 read/write 数据。我可以从提交操作中读取数据,并以文本形式回复,但不确定卡片中输入数据的显示方式。首先,我想将 shootValue 添加到一个数组中,我可以在卡片的整个生命周期中携带它。有人可以告诉我该怎么做吗?
这个问题的目的是了解如何保留卡片的现有回复。
就像在战舰中,我射击"A1",在输入框中输入它,提交,我想在卡片中看到"A1"。我添加 "A2",提交,然后我希望在发送给 Teams 的卡片中看到 "A1" 和 "A2"。我知道我需要在每次拍摄时从头开始重建卡片,这意味着,我需要以某种方式在每个动作中继续拍摄。
资料卡:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hello {name}"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "stretch",
"id": "",
"items": [
{
"type": "Container",
"items": [
{
"type": "Input.Text",
"placeholder": "Voorbeeld: A1",
"id": "id_shoot",
"$data": "shoot"
}
]
}
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": " {shoot}",
"horizontalAlignment": "Right",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotcoords"
}
],
"$data": "{shots}"
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": "{status}",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotstatuses"
}
],
"id": ""
}
]
},
{
"type": "ActionSet",
"id": "",
"actions": [
{
"type": "Action.Submit",
"title": "Shoot",
"id": "",
"style": "positive",
"data": {}
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
数据
{
"name": "Test shot",
"shoots": [
{
"shoot": "a1",
"status": "hit"
},
{
"shoot": "a2",
"status": "hit"
}
]
}
没有 "simple" 方法可以做到这一点,但有办法。答案将类似于 .
First, you'll need a way of saving state for your card so you can update the card's activity. In C# you can declare a state property accessor like this:
public IStatePropertyAccessor<Dictionary<string, (string ActivityId, List<string> Shots)>> BattleshipStateAccessor { get; internal set; }
Then you can instantiate it like this
BattleshipStateAccessor = _conversationState.CreateProperty<Dictionary<string, (string, List<string>)>>("battleshipState");
您在这里需要做出一些决定。首先,我选择将状态 属性 设为字典,这样我就可以跟踪多张卡片并仅更新被单击的特定卡片。如果你不关心那个,那么你不需要字典,你也不需要担心 "card ID's," 但至少保存一个 activity ID 是必要的,这样你就可以更新卡片。至于保存 "shots," 你在这里有几个选择。您可以通过更新每次拍摄的提交操作的数据来在客户端保存该状态,但我认为我最好将拍摄保存为机器人状态,因为我已经需要在机器人中保存 activity ID反正状态。然后是您应该保存关于每个镜头的哪些信息的问题。在这个例子中,我只保存了用户输入的镜头位置,而不是镜头的状态,因为我认为我可以随时重新计算状态。
我已将您的提交操作修改为如下所示:
{
"type": "Action.Submit",
"title": "Shoot",
"style": "positive",
"data": {
"behavior": "Shoot",
"cardId": ""
}
}
我在这里所做的是将两个属性添加到您的数据对象,这些数据将与文本输入的值一起发送到您的机器人。 "behavior" 属性 将帮助您的机器人路由到正确的功能,以防您的机器人使用可以以不同方式处理的多种类型的操作。 "cardId" 属性 只是一个占位符,您的机器人代码将在创建卡片时填写该占位符。我将这些属性的名称存储在常量 KEYBEHAVIOR
和 KEYCARDID
.
中
You'll want a consistent way to generate your card that you can use when you send the card initially and when you update the card.
internal static IMessageActivity CreateBattleshipCardActivity(
string cardId,
object data = null)
{
data = data ?? new
{
name = "Test shot",
shoots = new string[0],
};
JObject card = CreateAdaptiveCard("battleship", data);
foreach (var token in card.Descendants()
.Select(token => token as JProperty)
.Where(token => token?.Name == KEYCARDID))
{
token.Value = cardId;
}
return MessageFactory.Attachment(new Attachment(
AdaptiveCard.ContentType,
content: card));
}
CreateAdaptiveCard
函数从具有给定名称的文件加载 JSON 模板,使用给定数据对其进行转换,并将其反序列化为 JObject
.
Using this function, you can send the card initially like this in C#:
public async Task TestBattleshipAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
var cardId = Guid.NewGuid().ToString();
var reply = CreateBattleshipCardActivity(cardId);
var response = await turnContext.SendActivityAsync(reply, cancellationToken);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
dict[cardId] = (response.Id, new List<string>());
}
您可以像这样更新卡片以响应卡片的 "Shoot" 提交操作:
private async Task ShootAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
if (activity.ChannelId == Channels.Msteams)
{
var value = JObject.FromObject(activity.Value);
var cardId = Convert.ToString(value[BotUtil.KEYCARDID]);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
if (dict.TryGetValue(cardId, out var savedInfo))
{
savedInfo.Shots.Add(value["id_shoot"].ToString());
var data = new
{
name = "Test shot",
shoots = savedInfo.Shots.Select(shot => new
{
shoot = shot,
status = DetermineHit(shot),
}),
};
var update = CreateBattleshipCardActivity(cardId, data);
update.Id = savedInfo.ActivityId;
update.Conversation = activity.Conversation;
await turnContext.UpdateActivityAsync(update, cancellationToken);
}
}
}
我想了解如何使用自适应卡片 read/write 数据。我可以从提交操作中读取数据,并以文本形式回复,但不确定卡片中输入数据的显示方式。首先,我想将 shootValue 添加到一个数组中,我可以在卡片的整个生命周期中携带它。有人可以告诉我该怎么做吗?
这个问题的目的是了解如何保留卡片的现有回复。 就像在战舰中,我射击"A1",在输入框中输入它,提交,我想在卡片中看到"A1"。我添加 "A2",提交,然后我希望在发送给 Teams 的卡片中看到 "A1" 和 "A2"。我知道我需要在每次拍摄时从头开始重建卡片,这意味着,我需要以某种方式在每个动作中继续拍摄。
资料卡:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hello {name}"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "stretch",
"id": "",
"items": [
{
"type": "Container",
"items": [
{
"type": "Input.Text",
"placeholder": "Voorbeeld: A1",
"id": "id_shoot",
"$data": "shoot"
}
]
}
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": " {shoot}",
"horizontalAlignment": "Right",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotcoords"
}
],
"$data": "{shots}"
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": "{status}",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotstatuses"
}
],
"id": ""
}
]
},
{
"type": "ActionSet",
"id": "",
"actions": [
{
"type": "Action.Submit",
"title": "Shoot",
"id": "",
"style": "positive",
"data": {}
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
数据
{
"name": "Test shot",
"shoots": [
{
"shoot": "a1",
"status": "hit"
},
{
"shoot": "a2",
"status": "hit"
}
]
}
没有 "simple" 方法可以做到这一点,但有办法。答案将类似于
First, you'll need a way of saving state for your card so you can update the card's activity. In C# you can declare a state property accessor like this:
public IStatePropertyAccessor<Dictionary<string, (string ActivityId, List<string> Shots)>> BattleshipStateAccessor { get; internal set; }
Then you can instantiate it like this
BattleshipStateAccessor = _conversationState.CreateProperty<Dictionary<string, (string, List<string>)>>("battleshipState");
您在这里需要做出一些决定。首先,我选择将状态 属性 设为字典,这样我就可以跟踪多张卡片并仅更新被单击的特定卡片。如果你不关心那个,那么你不需要字典,你也不需要担心 "card ID's," 但至少保存一个 activity ID 是必要的,这样你就可以更新卡片。至于保存 "shots," 你在这里有几个选择。您可以通过更新每次拍摄的提交操作的数据来在客户端保存该状态,但我认为我最好将拍摄保存为机器人状态,因为我已经需要在机器人中保存 activity ID反正状态。然后是您应该保存关于每个镜头的哪些信息的问题。在这个例子中,我只保存了用户输入的镜头位置,而不是镜头的状态,因为我认为我可以随时重新计算状态。
我已将您的提交操作修改为如下所示:
{
"type": "Action.Submit",
"title": "Shoot",
"style": "positive",
"data": {
"behavior": "Shoot",
"cardId": ""
}
}
我在这里所做的是将两个属性添加到您的数据对象,这些数据将与文本输入的值一起发送到您的机器人。 "behavior" 属性 将帮助您的机器人路由到正确的功能,以防您的机器人使用可以以不同方式处理的多种类型的操作。 "cardId" 属性 只是一个占位符,您的机器人代码将在创建卡片时填写该占位符。我将这些属性的名称存储在常量 KEYBEHAVIOR
和 KEYCARDID
.
You'll want a consistent way to generate your card that you can use when you send the card initially and when you update the card.
internal static IMessageActivity CreateBattleshipCardActivity(
string cardId,
object data = null)
{
data = data ?? new
{
name = "Test shot",
shoots = new string[0],
};
JObject card = CreateAdaptiveCard("battleship", data);
foreach (var token in card.Descendants()
.Select(token => token as JProperty)
.Where(token => token?.Name == KEYCARDID))
{
token.Value = cardId;
}
return MessageFactory.Attachment(new Attachment(
AdaptiveCard.ContentType,
content: card));
}
CreateAdaptiveCard
函数从具有给定名称的文件加载 JSON 模板,使用给定数据对其进行转换,并将其反序列化为 JObject
.
Using this function, you can send the card initially like this in C#:
public async Task TestBattleshipAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
var cardId = Guid.NewGuid().ToString();
var reply = CreateBattleshipCardActivity(cardId);
var response = await turnContext.SendActivityAsync(reply, cancellationToken);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
dict[cardId] = (response.Id, new List<string>());
}
您可以像这样更新卡片以响应卡片的 "Shoot" 提交操作:
private async Task ShootAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
if (activity.ChannelId == Channels.Msteams)
{
var value = JObject.FromObject(activity.Value);
var cardId = Convert.ToString(value[BotUtil.KEYCARDID]);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
if (dict.TryGetValue(cardId, out var savedInfo))
{
savedInfo.Shots.Add(value["id_shoot"].ToString());
var data = new
{
name = "Test shot",
shoots = savedInfo.Shots.Select(shot => new
{
shoot = shot,
status = DetermineHit(shot),
}),
};
var update = CreateBattleshipCardActivity(cardId, data);
update.Id = savedInfo.ActivityId;
update.Conversation = activity.Conversation;
await turnContext.UpdateActivityAsync(update, cancellationToken);
}
}
}