【问题标题】:C# Listbox Filter with Linq fulltext search query带有 Linq 全文搜索查询的 C# 列表框过滤器
【发布时间】:2013-08-03 14:16:59
【问题描述】:

我有以下问题。我有一个绑定到ObservableCollectionWPF 列表框。现在我想用全文字符串过滤框中的项目。

我通过在 ObservableCollection 上运行 linq 查询并将列表绑定到查询结果来做到这一点。它通常有效,但有些行为我无法解释。

列表条目示例: CMSRC_XXX_ADDR, CMDST_XXX_ADDR, TXDAT_DMA_ST_ADDR, ...

有效的搜索查询: 地址,XXX,XX,地址,CM

无效的搜索查询: CMS、CMSR、...

当我输入CM 时,它仍然显示CMSRC_XXX_ADDR 条目。当我输入CMS 时,CMSRC_XXX_ADDR 不再显示。

有人知道为什么吗?我希望我的问题很清楚。感谢您的帮助。

问候 多米尼克

        string txtOrig = text;
        string lower = txtOrig.ToLower();
        string normalize = txtOrig.Normalize();

        var bitfieldsfiltered = from bit in bitfields
                                let name = bit.name_
                                where
                                name.ToLower().StartsWith(lower)
                                || name.StartsWith(txtOrig)
                                || name.Normalize().StartsWith(normalize)
                                || name.ToLower().Contains(lower)
                                || name.Contains(txtOrig)
                                || name.Normalize().Contains(normalize)
                                || name.ToLower().EndsWith(lower)
                                || name.EndsWith(txtOrig)
                                || name.Normalize().EndsWith(normalize)
                                || name.ToLower().Equals(lower)
                                || name.Equals(txtOrig)
                                || name.Normalize().Equals(normalize)
                                select bit;
         list_box.ItemsSource = bitfields;

更新:错误不存在。标签中的数据不是列表框中的数据。由于 RecognizesAccessKey,缺少下划线。

【问题讨论】:

  • 哇!为什么不使用 StringComparison 枚举之一?它可以将您的逻辑简化约 66%,并使其更易于调试。只是好奇?
  • @GarryVass 因为他可能不知道这样的枚举。
  • @user2591237,如果您重新调整您的问题范围以包括您乐于接受逻辑/效率改进?
  • @GarryVass 是的,我会接受每一项改进。我不需要它那样做。它只需要工作。问候
  • 我将上传一些代码,以降低查询的复杂性并更轻松地实施诊断,以确保您的查询以您想要的方式执行。

标签: c# wpf linq search listbox


【解决方案1】:

有几件事可以解决这个问题。首先,转到您的解决方案并“添加”->“新项目”->“测试”->“单元测试项目”。这是 Vs2012,在 Vs2010 中菜单会略有不同。

测试项目初始化后,执行“添加”->“新项目”->“类”。然后将以下代码粘贴到该类中...

[TestClass]
public class MyQueryUnitTests
{
    [TestMethod]
    public void TestMethod1()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("ADDR");
        Assert.IsTrue(result.Count==3);
    }
    [TestMethod]
    public void TestMethod2()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("XXX");
        Assert.IsTrue(result.Count == 2);
    }
    [TestMethod]
    public void TestMethod3()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("CMS");
        Assert.IsTrue(result.Count==1);
    }
    [TestMethod]
    public void TestMethod4()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("CMSR");
        Assert.IsTrue(result.Count == 1);
    }
    [TestMethod]
    public void TestMethod5()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("CM");
        Assert.IsTrue(result.Count == 2);
    }
    [TestMethod]
    public void TestMethod6()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("DUMMY");
        Assert.IsTrue(result.Count == 2);
    }
    [TestMethod]
    public void TestMethod7()
    {
        BitQuery bitQuery = new BitQuery();
        var result = bitQuery.Query("");
        Assert.IsTrue(result.Count == 5);
    }
}
public class BitQuery
{
    public ObservableCollection<bit> bitfields = new ObservableCollection<bit>();
    public BitQuery()
    {
        bitfields.Add(new bit { name_ = "CMSRC_XXX_ADDR" });
        bitfields.Add(new bit { name_ = "CMDST_XXX_ADDR" });
        bitfields.Add(new bit { name_ = "TXDAT_DMA_ST_ADDR" });
        bitfields.Add(new bit { name_ = "WWWW_DUMMY" });
        bitfields.Add(new bit { name_ = "ABCDE_DUMMY" });
    }
    public List<bit> Query (string text)
    {
        string txtOrig = text;
        string lower = txtOrig.ToLower();
        string normalize = txtOrig.Normalize();
        var bitfieldsfiltered = from bit in bitfields
                                let name = bit.name_
                                where IsMatch(txtOrig, name)
                                select bit;
        return bitfieldsfiltered.ToList();
    }
    private bool IsMatch(string txtOrig, string name)
    {
        if (name.StartsWith(txtOrig, StringComparison.InvariantCultureIgnoreCase)) return true;
        if (name.IndexOf(txtOrig, 0, StringComparison.OrdinalIgnoreCase) >= 0) return true;
        return false;
    }
}
public class bit
{
    public string name_ { get; set; }
    public override string ToString()
    {
        return name_;
    }
}

然后告诉 Visual Studio 运行单元测试。 VS 将打开一个以各种颜色亮起的窗口并运行测试。

所有测试都表明您描述的问题已得到解决,您正在恢复预期的结果!

立即感兴趣的是用简单的方法替换冗长的“OR”子句...

    private bool IsMatch(string txtOrig, string name)
    {
        if (name.StartsWith(txtOrig, StringComparison.InvariantCultureIgnoreCase)) return true;
        if (name.IndexOf(txtOrig, 0, StringComparison.OrdinalIgnoreCase) >= 0) return true;
        return false;
    }

---本质上做同样的事情。注意:您将需要添加更多单元测试以涵盖所有各种条件。一旦您非常确信您的查询是健壮且始终准确的,您就可以将其重新插入到您的列表框中。

另一个值得考虑的变化是这条线......

return bitfieldsfiltered.ToList();

这会获取 LINQ 结果并“将其锁定”。在您的原始代码中,您将其保留为未评估的查询(这可能会或可能不会影响此特定情况,但如果您在用户界面上展示某些内容,最好将其锁定)。

因此,您的“CMS”和“CMSR”查询现在正在运行,并且您有一些单元测试,您可以在其中引入额外的条件并确信整个事情可以正常工作。

【讨论】:

  • 非常感谢!我想投票,但我还没有 15 个声望。
  • 您不需要代表在答案上放置“接受”(即投票显示下方的复选标记)。这样做会表明您对答案感到满意,并且还会让我对您以后发布的任何问题保持警惕。
【解决方案2】:

您的代码效率非常低,并且您多次检查同一件事。你可以打电话

name.ToLower().Contains(lower)

而不是

name.ToLower().Contains(lower)

name.ToLower().StartsWith(lower)

name.ToLower().Equals(lower)

name.ToLower().EndsWith(lower)

尝试将整个 where 子句替换为:

where name.ToLower().Contains(lower) || name.Normalize().Contains(normalize)

或者甚至是这样:

where name.ToLower().Contains(lower)

那么你应该会得到更好的结果。

更新>>>

当我需要过滤一个集合时,我会使用一个额外的集合,以便我的原始集合保持不变。看起来您正在过滤到 bitfieldsfiltered 集合,但随后将您的 bitfields 集合用作 ListBox.ItemsSource 值...您不应该显示 bitfieldsfiltered 集合吗?

【讨论】:

  • 他描述的错误来自哪里?或者这是否修复了错误?
  • @Sheridan 非常感谢您的帮助。这正是我最初做的方式。但这并不能修复错误,并且再次发生相同的错误。这就是为什么 a 添加了很多 OR 条件。
  • @sheridan 你是对的!这只是我的示例代码中的一个错误。不在我的真实代码中。不过非常感谢!我发现了错误。由于 wpf 标签未显示下划线,因此列表框中还有其他数据未显示。
  • 很高兴您解决了问题。请为您的问题添加一个答案,总结您的修复,然后将其标记为正确?谢谢。
猜你喜欢
  • 2015-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
相关资源
最近更新 更多