Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
MVVM-ListBox mit TextBox-Inhalt durchsuchen/Filtern
Nexmo
myCSharp.de - Member



Dabei seit:
Beiträge: 36
Herkunft: Eggenstein-Leopoldshafen

Themenstarter:

MVVM-ListBox mit TextBox-Inhalt durchsuchen/Filtern

beantworten | zitieren | melden

Guten Morgen zusammen.
Ich hänge nun seit ein paar Tagen vor folgendem Problem:

ich habe eine ObservableCollection<Klasse> name welche ich als ItemSource an eine ListBox gebunden habe.

nun möchte ich über eine TextBox diese Liste Filtern.

Im Netz habe ich da verschiedene Ansätze schon gefunden, leider jedoch alle nur als CodeBehind, oder als Win-Form-style.
beides bringt mich jedoch nicht weiter.

Die ObservableCollection wird aus einer Datenbank heraus gefüllt.

mein Ansatz war jetzt mit ICollectionView zu arbeiten, jedoch funktioniert das leider nicht wie gewünscht.

Könnte mir da bitte jemand weiterhelfen?

Auszug aus dem XAML

 <GroupBox Header="Suchen" Grid.Row="0" Margin="5,5,5,5" Background="AliceBlue">
                <TextBox TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,0,0,0" Width="200" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}"/>
            </GroupBox>
            <GroupBox Header="Gefundene Personen" Grid.Row="1" Margin="5,5,5,5">
                <ListBox Margin="5,5,5,5" ItemsSource="{Binding Personendaten}" SelectedItem="{Binding PersData}"  >


Auszug aus dem MainWindowViewModel


using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace MVVM_Adressdatenbank
{
    class MainWindowViewModel : NotifyableBaseObject
    {

        public MainWindowViewModel()
        {
            this.Abfrage = new DelegateCommand((o) => { Personendaten.Clear(); Datenabfrage(); });
            this.weitereAbfrage = new(

                (o) => { Kontaktdaten.Clear(); KontaktDatenabfrage(PersData.ID); AdressDatenabfrage(PersData.ID); });
            this.Speichern = new DelegateCommand((o) => { Datenänderungspeichern(); });
            this.AdresseSpeichern = new((o) => { Adressänderungspeichern(); });

        }

        public bool HasNonZeroValue => PersData.Vorname != null;
        

        private ObservableCollection<PersonenDaten> personendaten = new ObservableCollection<PersonenDaten>();

        public ObservableCollection<PersonenDaten> Personendaten
        {
            get => personendaten;
            set
            {
                if (personendaten != value)
                {
                    personendaten = value;
                    RaisePropertyChanged();
                    
                }
            }
        }

        public ICollectionView phrasesView; 
        public void AnagramViewModel()
        {         
            phrasesView = CollectionViewSource.GetDefaultView(Personendaten);
            phrasesView.Filter = o => string.IsNullOrEmpty(Filter) || ((string)o).Contains(Filter);
        }
        string filter;
        public string Filter
        {
            get => filter;
            set
            {
                if (value!=filter)
                {
                    filter = value;
                    //RaisePropertyChanged();
                    RaisePropertyChanged(nameof(AnagramViewModel));
                }
            }
        }
       
       
        private ObservableCollection<KontaktDaten> kontaktdaten = new ObservableCollection<KontaktDaten>();
        public ObservableCollection<KontaktDaten> Kontaktdaten
        {
            get => kontaktdaten;
            set
            {
                if (kontaktdaten != value)
                {
                    kontaktdaten = value;
                    RaisePropertyChanged();
                   
                }
            }
        }

       

        KontaktDaten kontData = new KontaktDaten();
        public KontaktDaten KontData
        {
            get => kontData;
            set
            {
                if (kontData != value)
                {
                    kontData = value;
                    RaisePropertyChanged();
                }
            }
        }
        PersonenDaten persData = new PersonenDaten();
        public PersonenDaten PersData
        {
            get => persData;
            set
            {
                if (persData != value)
                {
                    persData = value;
                    RaisePropertyChanged();
                    RaisePropertyChanged(nameof(HasNonZeroValue));
                    
                    
                }
            }
        }

        public DelegateCommand Abfrage
        {
            get; set;
        }

        public DelegateCommand weitereAbfrage { get; set; }

        public DelegateCommand Speichern { get; set; }
        public DelegateCommand AdresseSpeichern { get; set; }

        public event EventHandler Safesucces;

        Datenbankzugriff zugriff = Datenbankzugriff.GetDBZugriff();

        private void Datenabfrage()
        {
            
            SqliteConnection connect = zugriff.connect();
            //string datenabfrage = "Select ID_Person, Vorname, Nachname, Geburtsdatum, Geburtsname FROM Person";
            string datenabfrage = "Select p.ID_Person, a.ID_Adresse, Vorname, Nachname, Geburtsname, Geburtsdatum, Straße, Hausnummer, Postleitzahl, Ort, Land, Typ_Name From Person p JOIN Person_Adresse pa ON " +
                "p.ID_Person = pa.ID_Person " +
                "JOIN Adresse a ON pa.ID_Adresse = a.ID_Adresse " +
                "JOIN Adress_Typ at ON pa.ID_Adress_Typ = at.ID_Adress_Typ ";
                
            SqliteCommand com = new(datenabfrage, connect);

            connect.Open();
            SqliteDataReader reader = com.ExecuteReader();
            if (reader.HasRows)
                while (reader.Read())
                {
                    Personendaten.Add(new PersonenDaten
                    {
                        ID = reader.GetString(reader.GetOrdinal("ID_Person")),
                        Vorname = reader.GetString(reader.GetOrdinal("Vorname")),
                        Nachname = reader.GetString(reader.GetOrdinal("Nachname")),
                        Geburtsdatum = reader.GetString(reader.GetOrdinal("Geburtsdatum")),
                        Geburtsname = reader.GetString(reader.GetOrdinal("Geburtsname")),
                        Straße = reader.GetString(reader.GetOrdinal("Straße")),
                        Hausnummer = reader.GetString(reader.GetOrdinal("Hausnummer")),
                        Plz = reader.GetString(reader.GetOrdinal("Postleitzahl")),
                        Ort = reader.GetString(reader.GetOrdinal("Ort")),
                        Land = reader.GetString(reader.GetOrdinal("Land")),
                        AdressTyp = reader.GetString(reader.GetOrdinal("Typ_Name")),
                        ID_Adresse=reader.GetString(reader.GetOrdinal("ID_Adresse"))
                    });


                
                }


            connect.Close();
        }

}

private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4182

beantworten | zitieren | melden

Du mußt dann für die ICollectionView eine eigene Eigenschaft erzeugen und diese dann an die ListBox binden (statt Personendaten). Und diese muß dann entweder die komplette Liste oder aber die gefilterten Daten liefern, je nach Filter.

PS: Der Name Personendaten ist ungünstig gewählt, da du ihn sowohl in der Einzahl als auch Mehrzahl (ObservableCollection<>) benutzt.
private Nachricht | Beiträge des Benutzers
Nexmo
myCSharp.de - Member



Dabei seit:
Beiträge: 36
Herkunft: Eggenstein-Leopoldshafen

Themenstarter:

beantworten | zitieren | melden

Zitat von Th69
Du mußt dann für die ICollectionView eine eigene Eigenschaft erzeugen und diese dann an die ListBox binden (statt Personendaten). Und diese muß dann entweder die komplette Liste oder aber die gefilterten Daten liefern, je nach Filter.

PS: Der Name Personendaten ist ungünstig gewählt, da du ihn sowohl in der Einzahl als auch Mehrzahl (ObservableCollection<>) benutzt.


Wo verwende ich denn den Namen in der Einzahl??

Personendaten ist nur der name der ObservableCollection, welche von der klasse PersonenDaten befüllt wird.( Groß/Kleinschreibung bitte beachten)


Sollte dass dann so aussehen??


public ObservableCollection<PersonenDaten> Newlist { get; private set; }

        public ICollectionView phrasesView; 
        public void AnagramViewModel()
        {
            Newlist = Personendaten;
            phrasesView = CollectionViewSource.GetDefaultView(Newlist);
            phrasesView.Filter = o => string.IsNullOrEmpty(Filter) || ((string)o).Contains(Filter);
        }
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4182

beantworten | zitieren | melden

Leg für ICollectionView phrasesView eine Eigenschaft an und binde daran.

Und bei Filter ist RaisePropertyChanged(nameof(AnagramViewModel)) zurzeit sinnlos, da dies keine Eigenschaft (sondern eine Methode) darstellt. Hier mußt du dann den Namen der obigen Eigenschaft setzen.

PS: Ich meinte den Klassennamen PersonenDaten sowie die Eigenschaften PersData und Personendaten. Es ist aus den Namen nicht ersichtlich, was sich auf eine Person oder auf mehrere bezieht (analog für KontaktDaten).
Edit: Dazu habe ich den englischen Artikel An opinionated guide to naming your code, aimed at new developers gefunden.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
Nexmo
myCSharp.de - Member



Dabei seit:
Beiträge: 36
Herkunft: Eggenstein-Leopoldshafen

Themenstarter:

beantworten | zitieren | melden

Zitat von Th69
Leg für ICollectionView phrasesView eine Eigenschaft an und binde daran.

Und bei Filter ist RaisePropertyChanged(nameof(AnagramViewModel)) zurzeit sinnlos, da dies keine Eigenschaft (sondern eine Methode) darstellt. Hier mußt du dann den Namen der obigen Eigenschaft setzen.

PS: Ich meinte den Klassennamen PersonenDaten sowie die Eigenschaften PersData und Personendaten. Es ist aus den Namen nicht ersichtlich, was sich auf eine Person oder auf mehrere bezieht (analog für KontaktDaten).
Edit: Dazu habe ich den englischen Artikel An opinionated guide to naming your code, aimed at new developers gefunden.


ah, ok.

also die Liste Personendaten bezieht sich auf eine Sammlung von Personen => PersData, welche durch die Klasse PersonenDaten bestimmt werden.

hab eben mal etwas umgestellt, da ich gemerkt habe, das AnagramViewModel der konstruktor war von dem Beispiel


 public MainWindowViewModel()
        {
            this.Abfrage = new DelegateCommand((o) =>
            { Personendaten.Clear(); Datenabfrage(); });
            this.weitereAbfrage = new((o) => { Kontaktdaten.Clear(); KontaktDatenabfrage(PersData.ID); AdressDatenabfrage(PersData.ID); });
            this.Speichern = new DelegateCommand((o) => { Datenänderungspeichern(); });
            this.AdresseSpeichern = new((o) => { Adressänderungspeichern(); });
            Newlist = Personendaten;
            phrasesView = CollectionViewSource.GetDefaultView(Newlist);
            phrasesView.Filter = o => string.IsNullOrEmpty(Filter) || ((string)o).Contains(Filter);
        }

......

  public ObservableCollection<PersonenDaten> Newlist
        {
            get ; set;
        }
    

    private ICollectionView phrasesView;

    string filter;
    public string Filter
    {
        get => filter;
        set
        {
            if (value != filter)
            {
                filter = value;
                phrasesView.Refresh();
                RaisePropertyChanged(nameof(Filter));
            }
        }
    }


leider hab ich da jetzt halt das problem, dass er mir den Fehler bringt, dass er den string bei ((string)o.)contains(Filter) nicht auflösen kann, da er keinen string hat, sondern nur die Objekte aus der Collection personendaten.

glaub muss mir da einen eigenen filter schreiben, kann das sein?
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4182

beantworten | zitieren | melden

Wenn sich dein Filter auf mehrere (bzw. alle) Eigenschaften von PersonenDaten beziehen soll, dann mußt du sie einzeln auflisten:


phrasesView.Filter = p => string.IsNullOrEmpty(Filter) || p..Vorname.Contains(Filter) || p.Nachname.Contains(Filter); // || ...
(alternativ ginge auch eine Hilfsmethode, welche mittels Reflection über alle Eigenschaften iteriert)

PS: Warum nennst du die Klasse nicht einfach Person? Und die Liste dann Personen (bzw. englisch Persons).
Die Mischung von Deutsch und Englisch ist auf Dauer nicht gut für ein Projekt...
private Nachricht | Beiträge des Benutzers
Nexmo
myCSharp.de - Member



Dabei seit:
Beiträge: 36
Herkunft: Eggenstein-Leopoldshafen

Themenstarter:

GELÖST

beantworten | zitieren | melden

Ich habe das Problem hinbekommen:


im Konstruktor kommt folgendes rein:


 Searchable = Personendatenliste;
            Listable = new CollectionViewSource();
            Listable.Source = this.Searchable;
            Listable.Filter += ApplyFilter;



 public ObservableCollection<PersonenDaten> Searchable { get; set; }
        internal CollectionViewSource Listable { get; set; }
        public ICollectionView GetListable { get => Listable.View; }

        private void ApplyFilter(object sender, FilterEventArgs e)
        {
            PersonenDaten search = (PersonenDaten)e.Item;
            if (string.IsNullOrEmpty(this.Filter) || this.Filter.Length == 0)
            { e.Accepted = true; }
            else
            {
                e.Accepted = search.Fullname.Contains(Filter);
                RaisePropertyChanged();
            }


        }

        private string filter;
        public string Filter
        {
            get => this.filter;
            set
            {
                if (value != filter)
                {
                    this.filter = value;
                    //RaisePropertyChanged();
                    Listable.View.Refresh();
                    RaisePropertyChanged(nameof(Filter));
                }
            }
        }


Danke an alle, die mir geholfen haben.
Gestern, private Nachricht | Beiträge des Benutzers