C#列表框过滤器与Linq全文搜索查询
本文关键字:搜索 查询 文搜索 列表 过滤器 Linq | 更新日期: 2023-09-27 18:25:52
我有以下问题。我有一个绑定到ObservableCollection
的WPF
列表框。现在我想用一个完整的文本字符串过滤框中的项目。
我通过在ObservableCollection
上运行linq查询并将列表绑定到查询结果来实现这一点。它通常有效,但有些行为我无法解释。
列表的示例条目:CMSRC_XXX_adr、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的原因,缺少下划线。
可以做一些事情来修复这种行为。要开始,请转到您的解决方案并"添加"->"新项目"->"测试"->"单元测试项目"。这是Vs2012,在Vs2010中,菜单将略有不同。
测试项目初始化后,执行"Add"->"New Item"->"Class"。然后将以下代码粘贴到该类中。。。
[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"answers"CMSR"查询现在可以工作了,并且您有一些单元测试,在这些测试中,您可以引入额外的条件,并确信整个过程是有效的。
您的代码效率非常低,而且您要多次检查同一件事。你可以直接打电话给
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
集合吗?