【问题标题】:Why is this recursive search returning unrelated results?为什么这个递归搜索返回不相关的结果?
【发布时间】:2019-01-14 22:42:07
【问题描述】:

我有一个WPF TreeView,其中填充了许多子控件。自己有孩子的都是TreeViewItems,没有孩子的都是Checkboxes。目前它有大约 1,600 个Checkbox 孩子和子孩子。我还有一个Textbox,它用于通过匹配checkboxesTags中的数据来搜索树。

以下代码在将密钥键入Textbox 时过滤TreeView。如果在 Textbox 为空时触发此事件,则会运行不同的算法,该算法会显示所有子代并折叠 TreeViewItems 的子代。

我的问题有两个部分,为什么过滤方法不能正常工作?它允许不满足搜索词的结果。

其次,如何优化搜索功能?它目前将我的 UI 线程锁定了几秒钟,而 ShowAndCollapse 算法似乎没有。

// 'MainTree' is my TreeView being searched through

private void SearchTermTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = (TextBox)sender;

    if (textBox.Text.Length == 0)
    {
        ShowAndCollapse(MainTree);
    }
    else
    {
        Filter(MainTree, textBox.Text);
    }
}

private void ShowAndCollapse(ItemsControl parent)
{
    foreach (Control control in parent.Items)
    {
        control.Visibility = Visibility.Visible;

        if (control is TreeViewItem treeViewItem)
        {
            ShowAndCollapse(treeViewItem);

            treeViewItem.IsExpanded = false;
        }
    }
}

private void Filter(ItemsControl parent, string searchTerm)
{
    foreach (Control child in parent.Items)
    {
        if (child is TreeViewItem treeViewItem)
        {
            Filter(treeViewItem, searchTerm);

            if (IsEmpty(treeViewItem))
            {
                treeViewItem.IsExpanded = false;
                treeViewItem.Visibility = Visibility.Collapsed;
            }
            else
            {
                treeViewItem.IsExpanded = true;
                treeViewItem.Visibility = Visibility.Visible;
            }
        }
        else if (child is CheckBox checkBox)
        {
            foreach (string term in searchTerm.ToLower().Split(' '))
            {
                if (!checkBox.Tag.ToString().ToLower().Contains(term))
                {
                    checkBox.Visibility = Visibility.Collapsed;
                    return;
                }
            }
            checkBox.Visibility = Visibility.Visible;
        }
        else
            throw new Exception("Unexpected child type!");
    }
}

private bool IsEmpty(TreeViewItem treeViewItem)
{
    foreach (Control item in treeViewItem.Items)
    {
        if (item.Visibility == Visibility.Visible)
        {
            return false;
        }
    }
    return true;
}

谢谢!

【问题讨论】:

  • 1.我认为您的方法 Filter 中的 return 语句可能是问题所在,可能的解决方法是在 if 语句中使用 break 并将 checkbox.Visibility = Visibility.Visible 移动到 for 循环上方。 2.要优化方法,请考虑使用async - await
  • 啊-是的,就是这样-谢谢
  • 不客气。根据网站指南,我发布了我的评论作为答案,因为它解决了您的问题。如果您对它感到满意,请将其标记为已接受的答案。
  • 感谢您的支持和接受的答案。

标签: c# wpf recursion search


【解决方案1】:
  1. 我认为您的方法 Filter 中的 return 语句可能是问题所在,可能的解决方法是在 if statement 中使用 break 并将 checkbox.Visibility = Visibility.Visible 移动到 for 循环上方。

  2. 要优化该方法,请考虑使用 async - await 或按照 Abion47 的建议对基础数据源进行过滤和排序。

【讨论】:

  • 他的代码似乎没有做任何本质上异步的事情,所以我看不出async/await 有什么帮助。 (更不用说尝试将async/await 合并到递归方法中是一件很痛苦的事情。)
  • @Abion47 他想知道如何释放 UI 线程(他的问题的第 2 部分),所以我建议 async/await
  • 除了他的大部分函数处理大量控制属性的分配,而且这些分配必须在 UI 线程上运行。为了让它工作,它们都必须被Dispatches 包围,这无论如何都会把很多工作放回UI线程上。为了真正优化这段代码,他应该对底层数据源进行排序和过滤,然后触发视图的刷新(坦率地说,这就是他应该做的事情)。
  • @Abion47 - 你是说我应该处理一个新的树视图数据列表,然后删除所有现有的孩子,然后重新填充它。如果我要与 1,600 多个孩子打交道,这种构造不会对性能和内存产生很大影响吗?
  • @TobySmith WPF 的整个想法是数据绑定。如果你做得对,你就不应该手动创建节点根本。一次完成所有这些听起来可能会产生很多开销,但请记住,控件的属性更改无论如何都会触发该控件的重绘。至少通过在具有非 UI 数据的单独线程上执行大部分逻辑,您可以限制 WPF 在将工作交回 UI 线程时必须使用的控件数量。 (WPF 转储所有 UI 数据并重新开始比遍历每个控件并单独配置设置更容易。)
猜你喜欢
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 2014-05-09
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
相关资源
最近更新 更多