Bot 框架 - 如何创建可搜索列表
Bot framework - How can I create a Searchable List
我能理解bot框架在提供的控件方面还不成熟,
我正在尝试向用户显示选项列表。当列表有更多元素时,将仅显示前 5 个元素以及查看更多元素的选项,这将显示所有带有搜索文本框的项目以避免滚动。
因此,我正在尝试实现一个可搜索列表。查看了 bot 框架,但提示和自适应卡片不是很有用,或者如果我遗漏了一些东西,那么获得一些帮助会很棒。
注意 - 我使用的是机器人框架 v3
谢谢
我把这个放在一起了。它做的事情类似于你想做的事情。它允许您将列表传递给它,然后它会显示一个提示对话框,其中包含一组选项,让您选择新的搜索以及下一个和上一个。
[Serializable]
public class OptionsDialog<T> : IDialog<OptionsResult<T>>
where T : class
{
private const string CurrentPage = "currentPage";
private readonly IList<T> _items;
private readonly Func<T, string> _descriptionFunc;
private readonly Func<T, IReadOnlyList<string>> _synonymFunc;
private readonly string _prompt;
private int current = 0;
/// <summary>
///
/// </summary>
/// <param name="items">Must be a distinct list</param>
/// <param name="descriptionFunction">Function to get the description for an option</param>
/// <param name="synonymFunction">Function to get the synonyms for an option</param>
/// <param name="prompt">Prompt for the options</param>
public OptionsDialog(IList<T> items, Func<T, string> descriptionFunction, Func<T, IReadOnlyList<string>> synonymFunction, string prompt)
{
_items = items;
_descriptionFunc = descriptionFunction;
_synonymFunc = synonymFunction;
_prompt = prompt;
}
public Task StartAsync(IDialogContext context)
{
if (_items.Count() == 0)
{
context.Done(new OptionsResult<T>(null, false));
}
else if (_items.Count() == 1)
{
context.Done(new OptionsResult<T>(_items.First(), false));
}
else
{
SendContactOptions(context, _items);
}
return Task.CompletedTask;
}
private void SendContactOptions(IDialogContext context, IList<T> items)
{
int maxContacts = int.Parse(ConfigurationManager.AppSettings["MaxContactsShown"]);
bool addNext = false;
bool addPrevious = false;
if (items.Count > maxContacts)
{
if (current > 0)
{
addPrevious = true;
}
if (items.Skip(current * maxContacts).Count() > maxContacts)
{
addNext = true;
}
items = items.Skip(current * maxContacts)
.Take(maxContacts)
.ToList();
}
List<string> descriptions;
Dictionary<string, IReadOnlyList<string>> choices;
descriptions = items.Select(item => _descriptionFunc(item)).ToList();
choices = items.ToDictionary<T, string,
IReadOnlyList<string>>(item => item.ToString(), item => _synonymFunc(item));
if (addNext)
{
descriptions.Add("More");
choices.Add("More", new List<string>() { "Next" });
}
if (addPrevious)
{
descriptions.Add("Previous");
choices.Add("Previous", new List<string>() { "Previous", "Last", "Back" });
}
descriptions.Add("New Search");
descriptions.Add("Cancel");
choices.Add("New Search", new List<string>() { "None", "None of these", "Next Search", "Search Again", "Search" });
choices.Add("Cancel", new List<string>() { "Stop", "Quit" });
IPromptOptions<string> promptOptions = new PromptOptionsWithSynonyms<string>(_prompt, choices: choices, descriptions: descriptions,
tooManyAttempts: DialogHelper.TooManyAttemptsText);
PromptDialog.Choice(context, SelectItemAsync, promptOptions);
}
private async Task SelectItemAsync(IDialogContext context, IAwaitable<object> result)
{
try
{
string contactName = await result as string;
if (contactName == "Cancel")
{
context.Done(new OptionsResult<T>(null, false, true));
}
else if (contactName == "New Search")
{
context.Done(new OptionsResult<T>(null, true));
}
else if (contactName == "More")
{
current++;
SendContactOptions(context, _items);
}
else if (contactName == "Previous")
{
current--;
SendContactOptions(context, _items);
}
else
{
T resultItem = _items.FirstOrDefault(c => c.ToString().ToLower() == contactName.ToLower());
if (resultItem != null)
{
DialogHelper.DeleteConversationItem(context, "searchContacts");
context.Done(new OptionsResult<T>(resultItem, false));
}
else
{
context.Done(new OptionsResult<T>(null, false));
}
}
}
catch (TooManyAttemptsException)
{
context.Done(new OptionsResult<T>(null, false));
}
}
}
[Serializable]
public class OptionsResult<T>
where T : class
{
/// <summary>
/// Result of the options
/// </summary>
public T Result { get; set; }
/// <summary>
/// Whether the parent dialog needs to search again
/// </summary>
public bool SearchAgain { get; set; }
public bool IsCancelled { get; set; }
public OptionsResult(T result, bool searchAgain, bool cancelled = false)
{
Result = result;
SearchAgain = searchAgain;
IsCancelled = cancelled;
}
}
我能理解bot框架在提供的控件方面还不成熟, 我正在尝试向用户显示选项列表。当列表有更多元素时,将仅显示前 5 个元素以及查看更多元素的选项,这将显示所有带有搜索文本框的项目以避免滚动。 因此,我正在尝试实现一个可搜索列表。查看了 bot 框架,但提示和自适应卡片不是很有用,或者如果我遗漏了一些东西,那么获得一些帮助会很棒。
注意 - 我使用的是机器人框架 v3
谢谢
我把这个放在一起了。它做的事情类似于你想做的事情。它允许您将列表传递给它,然后它会显示一个提示对话框,其中包含一组选项,让您选择新的搜索以及下一个和上一个。
[Serializable]
public class OptionsDialog<T> : IDialog<OptionsResult<T>>
where T : class
{
private const string CurrentPage = "currentPage";
private readonly IList<T> _items;
private readonly Func<T, string> _descriptionFunc;
private readonly Func<T, IReadOnlyList<string>> _synonymFunc;
private readonly string _prompt;
private int current = 0;
/// <summary>
///
/// </summary>
/// <param name="items">Must be a distinct list</param>
/// <param name="descriptionFunction">Function to get the description for an option</param>
/// <param name="synonymFunction">Function to get the synonyms for an option</param>
/// <param name="prompt">Prompt for the options</param>
public OptionsDialog(IList<T> items, Func<T, string> descriptionFunction, Func<T, IReadOnlyList<string>> synonymFunction, string prompt)
{
_items = items;
_descriptionFunc = descriptionFunction;
_synonymFunc = synonymFunction;
_prompt = prompt;
}
public Task StartAsync(IDialogContext context)
{
if (_items.Count() == 0)
{
context.Done(new OptionsResult<T>(null, false));
}
else if (_items.Count() == 1)
{
context.Done(new OptionsResult<T>(_items.First(), false));
}
else
{
SendContactOptions(context, _items);
}
return Task.CompletedTask;
}
private void SendContactOptions(IDialogContext context, IList<T> items)
{
int maxContacts = int.Parse(ConfigurationManager.AppSettings["MaxContactsShown"]);
bool addNext = false;
bool addPrevious = false;
if (items.Count > maxContacts)
{
if (current > 0)
{
addPrevious = true;
}
if (items.Skip(current * maxContacts).Count() > maxContacts)
{
addNext = true;
}
items = items.Skip(current * maxContacts)
.Take(maxContacts)
.ToList();
}
List<string> descriptions;
Dictionary<string, IReadOnlyList<string>> choices;
descriptions = items.Select(item => _descriptionFunc(item)).ToList();
choices = items.ToDictionary<T, string,
IReadOnlyList<string>>(item => item.ToString(), item => _synonymFunc(item));
if (addNext)
{
descriptions.Add("More");
choices.Add("More", new List<string>() { "Next" });
}
if (addPrevious)
{
descriptions.Add("Previous");
choices.Add("Previous", new List<string>() { "Previous", "Last", "Back" });
}
descriptions.Add("New Search");
descriptions.Add("Cancel");
choices.Add("New Search", new List<string>() { "None", "None of these", "Next Search", "Search Again", "Search" });
choices.Add("Cancel", new List<string>() { "Stop", "Quit" });
IPromptOptions<string> promptOptions = new PromptOptionsWithSynonyms<string>(_prompt, choices: choices, descriptions: descriptions,
tooManyAttempts: DialogHelper.TooManyAttemptsText);
PromptDialog.Choice(context, SelectItemAsync, promptOptions);
}
private async Task SelectItemAsync(IDialogContext context, IAwaitable<object> result)
{
try
{
string contactName = await result as string;
if (contactName == "Cancel")
{
context.Done(new OptionsResult<T>(null, false, true));
}
else if (contactName == "New Search")
{
context.Done(new OptionsResult<T>(null, true));
}
else if (contactName == "More")
{
current++;
SendContactOptions(context, _items);
}
else if (contactName == "Previous")
{
current--;
SendContactOptions(context, _items);
}
else
{
T resultItem = _items.FirstOrDefault(c => c.ToString().ToLower() == contactName.ToLower());
if (resultItem != null)
{
DialogHelper.DeleteConversationItem(context, "searchContacts");
context.Done(new OptionsResult<T>(resultItem, false));
}
else
{
context.Done(new OptionsResult<T>(null, false));
}
}
}
catch (TooManyAttemptsException)
{
context.Done(new OptionsResult<T>(null, false));
}
}
}
[Serializable]
public class OptionsResult<T>
where T : class
{
/// <summary>
/// Result of the options
/// </summary>
public T Result { get; set; }
/// <summary>
/// Whether the parent dialog needs to search again
/// </summary>
public bool SearchAgain { get; set; }
public bool IsCancelled { get; set; }
public OptionsResult(T result, bool searchAgain, bool cancelled = false)
{
Result = result;
SearchAgain = searchAgain;
IsCancelled = cancelled;
}
}