myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » GUI: WPF und XAML » Wie mit ComboBoxen DataGrid filtern?
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Wie mit ComboBoxen DataGrid filtern?

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 113
Entwicklungsumgebung: Visual Studio 2013


GeneVorph ist offline

Wie mit ComboBoxen DataGrid filtern?

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

vor der Frage ganz kurz zum Vorhaben:

ich möchte ein DataGrid erstellen, dessen Datendarstellung von zwei ComboBoxes abhängt. Diese sollen als Filter fungieren. Im Anhang dazu ein Bild, das den Sachverhalt deutlich zeigen dürfte.
Mein Model bildet ‚Students‘ ab (Name, Vorname, Klasse, Bildungsgang).

In meinem ViewModel befindet sich eine ObservableCollection<Student> DefaultFilter.
Binde ich die ItemsSource meines DataGrids auf diese Collection, erhalte ich vier Spalten (mit den Headern PreName, LastName, ClassLabel, EdcType) und die zugehörigen Daten. Soweit – so gut.

Jetzt zur Frage:
Im Bild seht ihr zwei ComboBoxes. In der linken, „Schüler“, gibt es die Auswahlmöglichkeit „Alle Schüler“, bzw. es besteht noch die Möglichkeit die Klassen A1 und B1 auszuwählen.
In der ComboBox rechts, „Bildungsgänge“ gibt es die Möglichkeit „Alle BGs“, sowie L, G und H.
Das DataGrid solle also in der Lage sein, die Daten je nach Auswahl in den ComboBoxen zu präsentieren (Etwa „Alle Schüler“ + „H“ oder „A1“ + „L“).

Wie sollte ich geschickterweise konzeptionell vorgehen?

Meine Idee dazu:
Ich erstelle eine Pre-Filter-Collection, in der alle Properties von Student abgebildet werden. Dann setze ich die ItemsSource des DataGrids im Code auf diese Collection. Allerdings dürfte das MVVM verletzen.

Daher könnte ich die Pre-Filter-Collection einfach anstelle des Default-Filters setzen:

DefaultFilter.Clear();
DefaultFilter = PreFilterCollection;

Mein Problem damit: Die Header im DataGrid zeigen immer den Propertynamen. Um hier sinnvolle Bezeichnungen zu haben, muss ich im XAML ein Template im DataGridTemplateColumn.Header anlegen; nur funktioniert dann meine Idee mit der Pre-Filter-Collection nicht mehr, da die Columns dann ja vordefiniert sind und nicht mehr dynamisch generiert werden.
Für alle Hinweise, wie ich mich dieser Aufgabe nähern kann, schon mal vielen Dank!

Gruß
Vorph

GeneVorph hat dieses Bild (verkleinerte Version) angehängt:
sample.png
Volle Bildgröße

Neuer Beitrag 15.02.2020 14:43 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.470
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Du bindest einfach zwei VM-Eigenschaften an die SelectedItem Eigenschaft der beiden ComboBoxen und in der an das DataGrid gebundenen Eigenschaft ObservableCollection<Student> Students wertest du die beiden anderen VM-Eigenschaften aus und gibst entsprechend eine gefilterte Liste zurück.

Du kannst dir auch mal  WPF MVVM Datagrid with Filtering sowie  List Filtering in WPF with M-V-VM anschauen bzw.  Multi-filtered WPF DataGrid with MVVM durchlesen. Dort wird jedesmal eine CollectionViewSource zusätzlich benutzt.
Neuer Beitrag 15.02.2020 15:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 113
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat:
Du bindest einfach zwei VM-Eigenschaften an die SelectedItem Eigenschaft der beiden ComboBoxen und in der an das DataGrid gebundenen Eigenschaft ObservableCollection<Student> Students wertest du die beiden anderen VM-Eigenschaften aus und gibst entsprechend eine gefilterte Liste zurück.

OK, das entspricht im Grunde mienem Ansatz. Die ersten beiden Links dazu sind leider etwas kurz - der Codeproject-Artikel thematisiert aber genau mein Anliegen.

Ich werde jetzt noch einiges zur Filterimplementierung und CollectionViewSource zu recherchieren haben; konnte dazu jetzt auch erst den Codeproject-Artikel überfliegen. Ein generelles Problem scheint mir aber erhalten zu bleiben:

- je nach Setting der ComboBoxen werden bestimmte Inhalte angezeigt/nicht angezeigt. In meinem Fall heißt das: Für cB1 "Klasse A1" und cB2 "L" soll das DAtaGrid alle Schüler anzeigen, die zur Klasse A1 gehören und im Bildungsgang L sind. Die Logik dazu zu implementieren ist nicht schwer, ich frage mich derzeit nur, wie ich das DAtaGrid dazu bekomme mir die Daten so anzuzeigen, wie sie angezeigt werden sollen, da ich - sofern ich mit Templates arbeiten möchte - AutoGenerateColumns auf "false" setzen muss.

Das fängt bei den Headern schon an: ich bräuchte schon sinnvolle Namen, statt "PreName" eben 'Vorname", statt 'Art" 'Bildende Kunst" (Leerzeichen im String). Normalerweise handele ich das über Templates, allerdings (nach meinem Kenntnisstand) würde das bedeuten, dass ich AutoGenerateColumns auf "false" setzen muss, was wiederum bedeutet, dass ich mir bereits vor der Runtime überlegen müsste, wie mein DAtaGrid aussieht - was aber irgendwie doch der Idee von Filtern entgegengesetzt ist, weil je nach Usecase mein Gird anders strukturiert ist.

Oder offenbaren sich hier Defizite meinerseits, was das Templating von DataGrids angeht? Momentan bin ich nämlich auf dem Stand, das durch DataGridColumnTemplates z. B. jede einzelne Column, die später im DG enthalten sein wird, manuell festgelegt wird.

Danke nochmals für die Links,
Gruß
Vorph
Neuer Beitrag 15.02.2020 20:17 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 113
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

OK, ich dachte mir schon, das das eine größere Baustelle wird.
Ich versuche mich gerade mit CollectionViewSource anzufreunden, bekomme aber auch einen einfachen Aufbau nicht hin. Hier mal mein Versuch:

Ich habe ein simples Datagrid auf dem MainWindow, ein MainViewModel und mein Student-Model.

MainWindow XAML

XML-Code:
<Window x:Class="DataGrid_Templating.MainWindow"
      ...
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
       ...

    <Window.DataContext
>
        <viewModels:MainViewModel/>
    </Window.DataContext>

    <Window.Resources>
        <CollectionViewSource x:Key="XFirstFilter" Source="{Binding FirstFilter}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Binding LastName" Direction="Ascending"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>
   ...
        <DataGrid Grid.Row="1" Grid.Column="1" AutoGenerateColumns="True" ItemsSource="{Binding Source={StaticResource XFirstFilter}}">
        </DataGrid>
    </Grid>
</Window>

Hier mein MainViewModel:

C#-Code:
public class MainViewModel
    {
..
        public ObservableCollection<Student> FirstFilter { get; set; } = new ObservableCollection<Student>();

        public MainViewModel()
        {
            CreateSome();
            PopulateFilter();
        }

        private void PopulateFilter()
        {
            foreach(Student s in MyStudents)
            {
                Student f = new Student();

                f.LastName = s.LastName;
                f.PreName = s.PreName;
                f.ClassLabel = s.ClassLabel;
                f.EducationalType = s.EducationalType;
                f.SubjectAverage = s.Subjects.AverageGrade;

                FirstFilter.Add(f);
            }
        }

        private void CreateSome()
        {
            Student s1 = new Student();
            s1.LastName = "Hubbes";
            ...

            Student s3 = new Student();

            MyStudents.Add(s1);
            MyStudents.Add(s2);
            MyStudents.Add(s3);
            MyStudents.Add(s4);

        }
    }

Soweit ich das verstanden habe, kann ich prüfen, ob soweit alles funktioniert, indem ich in der Windows.Resources die ViewCollection implementiere und

XML-Code:
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Binding LastName" Direction="Ascending"/>
            </CollectionViewSource.SortDescriptions>

eine SortDescription hinzufüge. In meinem Fall binde ich auf das Property "LastName" und setze Direction = Ascending.
Leider passiert bei mir rein gar nichts: wenn ich die App starte, wird die Reihenfolge der Einträge unter LastName so dargestellt, wie sie der Collection hinzugefügt wurden. Erst wenn ich auf den Header klicke, werden sie sortiert (aber auch erst mal descending...). Also stimmt mein binding schon nicht. Nur: wo ist der Fehler?

Gruß
Vorph
Neuer Beitrag 15.02.2020 22:43 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.470
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

So tief bin ich in WPF nicht (mehr) drin, aber ich habe mal einige weitere Links herausgesucht.

Zum einen zum Ändern der Headernamen bei AutoGenerateColumns = true:
-  How to: Customize Auto-Generated Columns in the DataGrid Control
-  How do you rename DataGrid columns when AutoGenerateColumns = True? (Stichwort: DisplayName) - Schau dir auch die MVVM-Lösung mit der "Behaviour Class" an.
-  WPF DataGrid - Auto Generate Columns

Und bzgl. CollectionViewSource.SortDescriptions:
-  Gewusst wie: Sortieren und Gruppieren von Daten mit einer Ansicht in XAML
-  CollectionViewSource not sorting

Kann es sein, daß das Wort Binding zu viel ist (bzw. ich bin mir sicher)?

XML-Code:
<CollectionViewSource.SortDescriptions>
    <scm:SortDescription PropertyName="LastName" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>

PS: Du solltest selber lernen, im Internet passende Links zu finden (am besten gleich auf englisch suchen).

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am 16.02.2020 10:26.

Neuer Beitrag 16.02.2020 10:23 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 113
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Vielen Dank, Th69!

Zitat:
PS: Du solltest selber lernen, im Internet passende Links zu finden (am besten gleich auf englisch suchen).

großes Grinsen Wenn du wüsstest, welch bitterböse Ironie damit verbunden ist! Ich habe zwei Tage zwischen vier und sechs Stunden nur Artikel gewälzt, die mich letzlich kaum weiterbrachten. Wie mal jemand so schön gesagt hat: "Programmieren lernt man alleine oder gar nicht!" Ich verstehe das immer besser: gerade bei WPF gibt es zig tausend Quellen und oft wird nur mal schnell was dahergezeigt, was mit MVVM nichts zu tun hat. Bleibt noch das Problem, dass ich oft "blindfischen" muss, weil ich gar nicht weiß, welchen Begriff ich nun suche^^ Aber: seit ein paar Monaten merke ich Vortschritte - es kann also nur besser werden großes Grinsen
Neuer Beitrag 16.02.2020 22:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.470
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Haben dir wenigstens meine Links dich weitergebracht (bzw. meine XAML-Änderung)?
Neuer Beitrag 17.02.2020 09:50 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 113
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ja, dein XAML war richtig - das "Binding" hatte ich gar nicht mehr bemerkt (auch so ein Effekt, wenn man stundenlang rumfurhwerkt); das muss natürlich weg und dann funktioniert es auch so, wie es sein soll.

Zu den Links:ausnahmsweise ist der microsoft.com-Artikel wirklich gut; die Sache mit den AutoGeneratedColumns habe ich jetzt einstweilen zurückgestellt, bis ich das mit dem Filtern besser verstanden habe (die Links aber gesichtet und gebookmarkt.
Ich hatte selbst bereits ein paar gefunden, die im Ansatz eine Erklärung geben - das Problem dabei war, dass ich erst jede Menge Refactoring betreiben musste, weil die Artikel aus Gründen der Einfachheit einfach alles in den codebehind klatschen.

Ich bin wieder zuversichtlich :) Also vielen Dank!

Gruß
Vorph
Neuer Beitrag 17.02.2020 14:23 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.299
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von GeneVorph:
Ich habe zwei Tage zwischen vier und sechs Stunden nur Artikel gewälzt, die mich letzlich kaum weiterbrachten.

Warum? Wie hast du die Artikel ausgewählt, und welche Informationen haben dir dabei gefehlt?

Zitat von GeneVorph:
ausnahmsweise ist der microsoft.com-Artikel wirklich gut

Wenn man einen neuen Framework oder ein neues Steuerelement ausprobieren will, dann ist die erste Anlaufstelle die Dokumentation dazu. Dort gibt es alles, was man zur Verwendung wissen muß. Wenn dann dort Begriffe stehen, die man nicht kennt, kann man gezielt danach suchen.
Neuer Beitrag 17.02.2020 19:22 Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 20.02.2020 18:34