Probleme mit RowFilter - Übergabe an eine Funktion

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Probleme mit RowFilter - Übergabe an eine Funktion

    Guten Abend liebe Leute,

    ich bin mit meinem (Beginner-)Latein am Ende und benötige einen Schubs in die richtige Richtung. Habe drei Bücher und dieses Forum bereits durchforstet, jedoch ohne mein Problem gefunden zu haben. Deswegen erlaube ich mir ein neues Thema anzulegen.

    Grundlage ist eine DataTable ("Adressen") mit allen notwendigen DataView, BindingSource usw. Darauf wende ich bereits erfolgreich den folgenden Suchfilter an:

    Private Sub TextBox_Suchen_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Suchen.TextChanged
    > DataView_Adressen.RowFilter = "Name LIKE '" + sender.Text + "%' OR Vorname LIKE'" + sender.Text + "%'"
    End Sub

    Soweit, so gut. Das kann aber jeder und es ist mir zu weing!

    Nun möchte ich den Filter "tolerant" gestalten. Dazu habe ich eine Annäherungsfunktion gemäß dem "Damerau-Levenshtein" -Vorbild, welche zwei Strings miteinander vergleicht. Diese funktioniert gut und gibt mir einen Integer (also die Differenz der beiden zu vergleichenden Strings) zurück.

    Bei der Umsetzung scheitere ich jedoch wehement daran, der Funktion innerhalb der Filteranweisung den String (der aktuellen Zelle) zu übergeben! Dazu muss jeweils der Wert der aktuellen Spalte "Name" an die Funktion übergeben. Nur wie ist die große Frage?

    Folgender Versuch geht natürlich nicht und soll der Anschauung dienen:

    Private Sub TextBox_Suchen_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Suchen.TextChanged
    > DataView_Adressen.RowFilter = MyDamerauLevenshteinDistance(DataView_Adressen("Name").ToString, sender.Text) <= 2
    End Sub

    Erwarte ich zu viel vom RowFilter, oder bin bloß ich überfordert? ?(

    Ciao, Stephan

    Stephan schrieb:

    Erwarte ich zu viel vom RowFilter
    Definitiv ja.
    RowFilter ist eine kleine, nicht erweiterbare AbfrageSprache - die Doku findtste hier: Link1
    Da sind alle Operatoren aufgeführt, von einem Levenshtein-Operator steht da nichts.



    Weiters widersetzt sich die Levenshtein-Logik selbst einer Filterungs-Einstellung, also es kann aus prinzipiellen Gründen keine "Levenshtein-Filterung" geben:
    Bei einem Filter trifft eine Bedingung auf ein Element zu oder trifft nicht zu.
    Bei Levenshtein gibts das garnet, sondern jedes Element bekommt einen Kennwert zugeordnet.

    Eine Bedingung könnte man erst draus machen, wenn man zB einen Schwellwert festlegt für den Kennwert - dann kann wieder gesagt wern: "Es trifft zu, dass dieses Element den Schwellwert überschreitet (oder nicht)".
    Aber schön wird sowas nicht.



    Ich hab mich mal mit Levenshtein auseinandergesetzt, und dabei habe ich die Ergebnis-Ausgabe nach anderer Logik verfasst: Nämlich ich habe keinen Filter, der Elemente ausfiltert, sondern ich sortiere die Elemente nur nach Levenshtein-Rang.
    Wie gesagt: Solch ist kein Filter, und schon deswegen wirste da mit RowFilter nix reissen können.

    (ich fund Levenshtein übrigens ziemlich miserabel, und habe eine um Welten bessere Methode erfunden, um Text-Ähnlichkeiten zu bestimmen - gugge hier wenn wolle: Link2)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Okay, erstmal besten Dank für die Aufklärung. Dann werde ich wohl doch nicht aus dem Fenster springen müssen. ;)

    ErfinderDesRades schrieb:

    Weiters widersetzt sich die Levenshtein-Logik selbst einer Filterungs-Einstellung, also es kann aus prinzipiellen Gründen keine "Levenshtein-Filterung" geben:
    Bei einem Filter trifft eine Bedingung auf ein Element zu oder trifft nicht zu.
    Bei Levenshtein gibts das garnet, sondern jedes Element bekommt einen Kennwert zugeordnet.


    Als Umsteiger von Delphi auf VB hatte ich gehofft die dort bereits funktionierende Filterung in gleicher Weise übernehmen zu können. Denn dort lüppt et als einfacher Filter, sodass es nicht grundsätzlich ausgeschlossen ist so vorzugehen. Die Funktion an sich gibt einen Integer wieder, der als Bedingung verwendet werden könnte. Sei es drum. Ich schau mir mal die Links an. Vielleicht ist da was bei. Jedenfalls auf den ersten Blick scheint mir das der gleiche Ansatz.

    Btw geht es ursprünglich nicht um die Funktion, sondern nur darum, wie ich den String/Wert an diese übergeben kann.

    Ciao, Stephan
    *unnötiges Vollzitat entfernt*

    Der RowFilter mach ja nix anderes, als simpel jede Row in der Table auf eine Bedingung zu prüfen. Dazu wird nur die Column (bei mir "Name") der Table angegeben, aus der sich eine der beiden Bedingungen (für jede Row neu) ergibt. Die weitere Bedingung(en) werden dann vorgegeben (zum Beispiel LIKE). Anstatt nun den jeweiligen Wert aus der Spalte "Name" direkt zu vergleichen - wie es bei "Name LIKE 'Meier'" geschieht - soll der Wert aus der Zelle an die Funktion übergeben werden. Die Prüfung der Bedingung erfolgt mit dem Resultat aus der Funktion und nicht mit derm Wert aus der Tabelle. Hoffe das ist nicht zu wirr ausgedrückt.

    Mein Problem ist also, dass ich nicht in der Lage bin den Wert zu übergeben. Dabei dachte ich, es sei eine einfache Syntax, welche mir nur nicht einfallen will.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Stephan schrieb:

    Der RowFilter mach ja nix anderes,...

    Was meinst du mit "der RowFilter"?
    RowFilter ist eine Property der DataView-Klasse, und ist vom Typ String.
    Ein String aber macht garnix.

    Auch deine weiteren Sätze ergeben keinen Sinn - sorry, dassich das so ungeblümt sage.
    Die "Column wird angegeben"?? - was meinst du damit - hast du mal ein Code-Beispiel?
    Und daraus ergibt sich eine der beiden Bedingungen? - habich was verpasst, von welchen beiden Bedingungen reden wir?
    Ich nutze den DataRowFilter, der in der Tat als Typ Sting angegeben wird.

    Mit Bedingungen meine ich die beiden Angaben vor und hinter dem Operator - bei mir "Name" und "sender.Text". Wobei "Name" kein String ist, sondern der Verweis auf die Tabelle, also die Bezeichnung der Column.

    Der Inhalt des Strings ist zuerst die Angabe der Column im DataView (im Beispiel "Name"),
    dann die Anweisung wie vorgegangen wird (Operator "LIKE")
    sowie abschließend die Angabe des Vergleichswertes ("String") um die Formel zu beenden.

    VB.NET-Quellcode

    1. [color=#0000CD]Private Sub TextBox_Suchen_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Suchen.TextChanged
    2. DataView_Adressen.RowFilter = "Name LIKE '" + sender.Text + "'"
    3. End Sub[/color]
    Ah - also die "Bedingungen" sind in Wahrheit nur eine Bedingung, und ist formuliert in RowFilter-Syntax (wir erinnern uns an post#2: "RowFilter ist eine kleine, nicht erweiterbare AbfrageSprache".
    Die Bedingung lautet - je nach was in sender.Text drinne steht - zB "Name Like 'Meier'".
    Ja, das ist alles.
    Und dein weiteres aus post#5

    Stephan schrieb:

    Anstatt nun den jeweiligen Wert aus der Spalte "Name" direkt zu vergleichen - wie es bei "Name LIKE 'Meier'" geschieht - soll der Wert aus der Zelle an die Funktion übergeben werden. Die Prüfung der Bedingung erfolgt mit dem Resultat aus der Funktion und nicht mit derm Wert aus der Tabelle.
    ergibt numa keinen Sinn.
    Aus welcher Zelle soll welcher Wert an welche Funktion übergeben werden????
    DataView hat keine Zelle, und hat keine Funktion.


    DataView hat die Property RowFilter, und die ist vom Typ String, und ist eine kleine, nicht erweiterbare Abfrage-Sprache.
    D.h.: in dem String kannst du Abfragen formulieren, solange du dich an die vorgegebene Syntax hälst.
    Die vorgegebene Syntax ist dokumentiert in - wir erinnern uns an post#2 - : Link1
    So geht das, und alles andere - was immer es auch sein mag (ich hab es nicht richtig verstanden, in post#1 gings iwie um Levenshtein) - geht nicht.

    Punkt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Es gibt eine Möglichkeit, spezielle DataViews zu erzeugen, deren Filterung mit Linq funktioniert: LinqToDataset
    Da hat man den Filter unter vb.net-Code-Kontrolle, und nicht sone Spezial embedded - Mini-Query-Sprache.
    Aber wie gesagt - wir erinnern uns an post#2 - Levenshtein definiert keinen Filter, sondern definiert allenfalls eine Sortier-Reihenfolge.
    (Das könnte man allerdings als Linq-Ausdruck formulieren - Stichwort OrderBy.)

    Das hat aber auch so seine Tücken - weil ist nicht kompatibel mit DataView.Sort, DataView.Filter.
    Oder anners: Bei sonem Linq-DataView kannste die Dataview.Sort- oder Filter-Property nicht nutzen.

    ErfinderDesRades schrieb:

    ist nicht kompatibel mit DataView.Sort, DataView.Filter
    Da stellen sich mir 3 Fragen:
    1. Meinst Du mit DataView.Filter DataView.RowFilter? Auf Anhieb hätte ich natürlich gesagt, dass Du das nicht meinst, da Du schon mehrfach in anderen Threads geschrieben hast: »Hätte ich das gemeint, hätte ich das auch geschrieben.« Meine Frage kommt deshalb auf, weil ich auf Anhieb im MSDN nix entsprechendes fand.
    2. Phantasielosigkeit: Hattest Du schon Stellen, an denen Du das gern kombiniert hättest? Erst schön mit LinqToDataSet filtern und dann unschön mit nem Stringausdruck (.RowFilter) weiterfiltern?
    3. Da folgende Sachen bei mir wie erwartet funktionieren, scheinst Du noch was zu meinen, was ich noch nicht erfasst habe (obwohl ich sie bisher selbst nicht gebraucht habe). Stellt sich die Frage: Was funktioniert nicht, was Du meinstest.

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. Tds.Companies.AddCompaniesRow("BMW")
    3. Tds.Cars.AddCarsRow("BMW", "Z3", 100, Tds.Companies.Last)
    4. Tds.Cars.AddCarsRow("BMW", "Z5", 140, Tds.Companies.Last)
    5. Tds.Cars.AddCarsRow("BMW", "Z4", 120, Tds.Companies.Last)
    6. Tds.Companies.AddCompaniesRow("VW")
    7. Tds.Cars.AddCarsRow("Golf 3", "GTI", 130, Tds.Companies.Last)
    8. Tds.Cars.AddCarsRow("Golf 4", "GTI", 150, Tds.Companies.Last)
    9. Tds.Cars.AddCarsRow("Polo", "86C", 45, Tds.Companies.Last)
    10. End Sub
    11. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    12. DataGridView1.DataSource = Tds.Cars.Where(Function(x) x.CompaniesRow.Name = "BMW").AsDataView
    13. Dim DgvDv = DirectCast(DataGridView1.DataSource, DataView)
    14. DgvDv.RowFilter = "PS > 100"
    15. End Sub
    16. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    17. DataGridView1.DataSource = Tds.Cars.Where(Function(x) x.CompaniesRow.Name = "VW").AsDataView
    18. Dim DgvDv = DirectCast(DataGridView1.DataSource, DataView)
    19. DgvDv.Sort = "PS"
    20. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    jo - sorry - es geht tatsächlich um die RowFilter-Property.

    Ansonsten werkel ich ja nie mit DataViews, sondern immer mit BindingSources - wie sie mir halt im Designer hin-generiert werden.
    Und bei BindingSource kann man halt im Designer Filter (diesmal wirklich ! ;) ) einstellen bzw Sort.
    Was ich auch nett finde, dass man im DGV einfach auch einen Spaltenheader klickst, und dann wird danach sortiert, bzw die Sortierrichtung umgedreht.
    Oder auch das Zusammenstöpseln von BindingSources, um bestimmte Views zu erzeugen: vier Views-Videos

    Also manche Dinge, die ganz ohne Code funktionieren, sind mit der Linq-DataView-Technologie nicht kompatibel.