使用Linq全文搜索查询的C#Listbox过滤器

时间:2013-08-02 10:28:56

标签: c# wpf linq search listbox

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

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

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

搜索有效的查询 ADDR,XXX,XX,ADD,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,缺少下划线。

2 个答案:

答案 0 :(得分:0)

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

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集合吗?

答案 1 :(得分:0)

可以采取一些措施来解决此问题。首先,转到您的解决方案并“添加” - > “新项目” - > “测试” - > “单元测试项目”。这是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”查询现在正在运行,你有一些单元测试,你可以引入其他条件,并确信整个过程都有效。