1

次の問題があります。にWPFバインドされているリストボックスがありますObservableCollection。ここで、ボックス内のアイテムを完全なテキスト文字列でフィルター処理したいと考えています。

で linq クエリを実行しObservableCollection、リストをクエリの結果にバインドします。一般的には機能しますが、説明できない動作がいくつかあります。

リストのエントリの例: 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 のため、アンダースコアがありませんでした。

4

2 に答える 2

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か?

于 2013-08-02T13:52:22.780 に答える
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」クエリは現在機能しており、追加の条件を導入して全体が機能することを確認できるいくつかの単体テストがあります。

于 2013-08-05T09:28:46.080 に答える