Bot框架-如何创建可搜索列表

时间:2018-10-11 04:58:22

标签: botframework adaptive-cards adaptive-design

我可以理解,就其提供的控件而言,机器人框架尚未成熟, 我正在尝试向用户显示选项列表。当列表中包含更多元素时,将仅显示前5个元素以及一个用于查看更多内容的选项,该选项将显示所有带有搜索文本框的项目以避免滚动。 因此,我正在尝试实现可搜索列表。在bot框架中看过,但是Prompts和自适应卡不是很有用,或者如果我错过了某些东西,那么寻求帮助会很棒。

注意-我正在使用bot框架v3

谢谢

1 个答案:

答案 0 :(得分:0)

我把这放在一起。它执行的操作与您想要执行的操作相似。它使您可以将列表传递到其中,然后显示一个提示对话框,其中包含设置的多个选项,可让您选择新的搜索以及上一个和下一个。

[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;
    }
}