Laden...

[gelöst] Generic List - Dynamische Suche/Filter

Erstellt von trib vor 11 Jahren Letzter Beitrag vor 11 Jahren 5.563 Views
T
trib Themenstarter:in
708 Beiträge seit 2008
vor 11 Jahren
[gelöst] Generic List - Dynamische Suche/Filter

Hallo zusammen,

des öfteren bin ich auf das Problem gestoßen, dass ich ein DGV und ein Databinding habe und mit einer List<T> fülle.
Nun möchte ich natürlich auch eine Filter- & Suchfunktion integrieren.

Die Möglichkeit die BindingSource mit Find oder Filter zu verwenden schlägt fehl, da es sich nicht um eine iBindingList handelt.

Nun kann ich natürlich

myFooList.Find(item => item.Name.Contains("Test123"));

benutzen. Der Nachteil ist allerdings, dass ich dies nun für jede Spalte im DGV einzeln machen darf.
Bisher habe ich auf meiner Suche nach einer einigermaßen eleganten Lösung nichts adequates gefunden.

Es sei noch gesagt, dass ich die Liste aus einem Webservice erhalte und daher etwas eingeschränkt bin.

Gruß,
trib

[EDIT] gelöst

731 Beiträge seit 2006
vor 11 Jahren

Hi trib,

was spricht denn dagegen einfach eine BindingList zu nehmen? 😃

MfG
wax

S
178 Beiträge seit 2009
vor 11 Jahren

Eine normale BindingLst kannst du im DGV aber nicht sortieren. Hatte vor kurzem das selbe Problem.
Für das Sortieren über das Datagrid brauchst du eine SortableBindingLIst wie z.B. Hier:
Sortable BindingList

Für das Filtern würde ich mir mal folgendes anschauen, das erzeugt dynamisch eine Filteroberfläche mit allen Spalten.

Dynamic DataGridView filtering in C#

Das jeweilige Filtern habe ich dann für alle Spalten jeweils einzeln gemacht.

 userList =
                                    new SortableBindingList<Benutzer>(
                                        userList.Where(x => x.Name1.ToUpperInvariant().StartsWith(
                                            f1.Value.ToUpperInvariant())));
                                dgvData.DataSource = userList;

Da hatte ich auch keine gescheite Lösung für gefunden.

Hoffe das bringt dich vielleicht schonmal etwas weiter.

//Edit: Link korrigiert

T
trib Themenstarter:in
708 Beiträge seit 2008
vor 11 Jahren

Hallo Wax,

das umstellen der List bewirkt leider auch, dass Funktionen wie AddRange, Find oder FindAll nicht mehr vorhanden sind. Anderer Typ, andere Funktionen 😦

Hallo Siedlerchr,

der Link funktioniert leider immer noch nicht 😉
Denke du meinst das hier: Dynamic Filtering in C
Damit hatte ich auch meine liebe Mühe, da dem DataGridView das "verkehrte" Binding zu Grunde liegt und dann beim Auseinandernehmen der Header und Zellen mehrere Konvertierungsfehler geworfen hat. Weiß natürlich nicht mehr alle im einzelnen, aber das hatte auch meist damit zu tun, dass es auch keine iBindingList ist, oder der Typ hinter dem DataBinding keine DataTable war...

Das ähnelt dann meiner aktuellen Lösung:


private void fooDataGridView_KeyDown(object sender, KeyEventArgs e)
        {
                    switch (fooDataGridView.Columns[currentColumn].DataPropertyName)
                    {
                        case "Customer_No":                            
                            InputValue = Input(fooDataGridView.Columns[currentColumn].HeaderText, cellValue);
                            fooBindingSource.DataSource = fooList.FindAll(sq => sq.Customer_No == InputValue);
                            break;                        
                        case "No":
                            InputValue = Input(fooDataGridView.Columns[currentColumn].HeaderText, cellValue);
                            fooBindingSource.DataSource = fooList.FindAll(sq => sq.No == InputValue);
                            break;
[...]
                                            }
}

Wobei "Input" ein Fenster anzeigt um einen Text einzugeben.

S
178 Beiträge seit 2009
vor 11 Jahren

Hallo,

ich verwende bei mir folgende SortableBindingList

SortableBindingLIst

Interessant dabei dürfte für dich der Abschnitt hier sein:

private void CreateOrderByMethod(PropertyDescriptor prop, 
                 string orderByMethodName, string cacheKey) {

        /*
         Create a generic method implementation for IEnumerable<T>.
         Cache it.
        */

        var sourceParameter = Expression.Parameter(typeof(List<T>), "source");
        var lambdaParameter = Expression.Parameter(typeof(T), "lambdaParameter");
        var accesedMember = typeof(T).GetProperty(prop.Name);
        var propertySelectorLambda =
            Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter, 
                              accesedMember), lambdaParameter);
        var orderByMethod = typeof(Enumerable).GetMethods()
                                      .Where(a => a.Name == orderByMethodName &&
                                                   a.GetParameters().Length == 2)
                                      .Single()
                                      .MakeGenericMethod(typeof(T), prop.PropertyType);

        var orderByExpression = Expression.Lambda<Func<List<T>, IEnumerable<T>>>(
                                    Expression.Call(orderByMethod,
                                            new Expression[] { sourceParameter, 
                                                               propertySelectorLambda }),
                                            sourceParameter);

        cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile());
    }

In a Nutshell

If, for instance, you create a MySortableBindingList<Sale> and sort on the Customer property, an expression that conceptually looks something like Enumerable.OrderBy<Sale>(originalList, a => a.Customer) will be created and used to do the sorting.

Das könnte doch eigentlich genau das sein was du brauchst. Der Code erzeugt dynamisch eine Lambda Expression, wenn ich das richtig verstanden habe und sortiert dann damit.

F
10.010 Beiträge seit 2004
vor 11 Jahren

Naja, wenn du ein kleines bisschen hier gesucht hättest wäre dir bestimmt der Begriff IBindingListView über den weg gelaufen.

T
trib Themenstarter:in
708 Beiträge seit 2008
vor 11 Jahren

Naja, wenn du ein kleines bisschen hier gesucht hättest wäre dir bestimmt der Begriff IBindingListView über den weg gelaufen.

Hallo FZelle,

ich würde schon behaupten dass ich vorher ordentlich gesucht habe. Aber vielleicht ist man manchmal auch zu sehr auf eine Richtung fixiert...

Mit dem Stichwort in der Tasche und dem bereits gefundenen Filter, konnte ich nun eine (zugegebenermaßen etwas umfangreiche) Lösung finden.
Zum einen habe ich nun eine Klasse BindingListView von SourceForge und zum anderen den dynamicGridFilter

Nun übergebe ich der BindingSource des DGV nicht meine Liste, sondern konvertiere diese vorher:

BindingListView<foo> view = new BindingListView<foo>(fooList);
fooBindingSource.DataSource = view;

Dann kann ich auch einfach das DGV an den Filter übergeben 😃

Scheint in meinen ersten Tests alles nun problemlos zu funktionieren. Suchen und Filtern ist dann anhand der standard Bordmittel der BindingSource möglich.

Vielen Dank an alle, ihr habt mich in die richtige Richtung geschubst 😃