Laden...

sqLite ausgabe in ListView nach MVVM-Pattern

Erstellt von gh0st93 vor 8 Jahren Letzter Beitrag vor 8 Jahren 5.059 Views
G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren
sqLite ausgabe in ListView nach MVVM-Pattern

Guten Abend liebe Code'er. 😃

Ich komme nun wieder mal mit einem kleinen Problem zu euch.

Ich hab eine "GAAANZ kleine" Anwendung erstellt, worin nur 2 Textboxe, eine ListView und ein Button sind.

In der ListView möchte ich mir die Daten aus der DB anzeigen lassen nach MVVM-Pattern allerdings stellte sich dies "noch für den anfang" schwieriger raus als gedacht.

Hier erstmal der Code.

In der MainWindow


        <ListView Grid.Row="1" ItemsSource="{Binding}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding Name}"/>
                    <GridViewColumn Header="Alter" Width="50" DisplayMemberBinding="{Binding Alter}"/>
                </GridView>
            </ListView.View>
        </ListView>

ViewModel

private MainModel _Model;

        #region INotifyPropertyChanged Member

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
        
        public MainViewModel()
        { }

        public MainViewModel(MainModel model)
        {
            _Model = model;
            _Name = _Model.Name;
            _Alter = _Model.Alter;
        }

        private string _Name;
        public string Name
        {
            get { return _Name; }
            set
            {
                if (_Name == value) return;
                _Name = value; NotifyPropertyChanged("Name");
            }
        }

        private int _Alter;
        public int Alter
        {
            get { return _Alter; }
            set
            {
                if (_Alter == value) return;
                _Alter = value; NotifyPropertyChanged("Alter");
            }
        }

Model

private Person p;

        public string Name { get; set; }
        public int Alter { get; set; }

        public MainModel()
        {
            Name = p.Name;
            Alter = p.Alter;
        }

Und im Ordner Model hab ich noch ein Unterordner "Entity" worin ich die DB verbindung aufbaue daten selectiere ect

Entity

 public string connectionString = @"Data Source=Datenbank.db;Version=3;";

        public string Name { get; set; }
        public int Alter { get; set; }

        public Person()
        {

            SQLiteConnection con = new SQLiteConnection(connectionString);
            con.Open();

            SQLiteCommand cmd = new SQLiteCommand("SELECT * FROM Tutorial WHERE Name = @Name AND Alter = @Alter", con);

            cmd.Parameters.AddWithValue("@Name", Name);
            cmd.Parameters.AddWithValue("@Alter", Alter);
            cmd.ExecuteNonQuery();
            cmd.Dispose();
            con.Close();

        }

Dies ist doch, MVVM-Gerecht, oder etwa nicht? ._.

und zu mein Problem, leider weiß ich nicht was genau ich hier falsch mache, wird mir in meiner Liste nix angezeigt?

Könnt ihr mir vielleicht ein Rat geben, worin ich nochmal genauer schauen soll oder wo mein fehler liegt?

H
523 Beiträge seit 2008
vor 8 Jahren

Hast Du den DataContext des Windows oder worin auch immer das ListView gehostet wird gesetzt?

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

Ja.

    
xmlns:ViewModels="clr-namespace:SQLiteTutorial.ViewModels" 

<Window.DataContext>
<ViewModels:MainViewModel/>
</Window.DataContext>
2.207 Beiträge seit 2011
vor 8 Jahren

ExecuteNonQuery gibt dir die Anzahl der betroffenen Zeilen zurück nach einem Update/Insert/Delete etc. Du machst aber ein Select. Da kann nichts zurück kommen. -->ExecuteReader. Ausserdem weist du dein Ergebnis, völlig unabhängig ob es falsch oder richtig ist, nirgends zu.

Deine ItemsSource sollte eine Liste sein auf dem ViewModel. Also biete eine Liste von Personen auf dem ViewModel an, und gib diese als ItemSource an bzw. binde darauf.

Dann könnte das Binding auf "Name" und "Alter" auch klappen 😉

Das hättest du aber leicht mit dem Debugger rausgefunden.

[Artikel] Debugger: Wie verwende ich den von Visual Studio?

Gruss

Coffeebean
PS: Arbeite besser mit Usings.

Z
11 Beiträge seit 2015
vor 8 Jahren

MVVM-Patterns lassen sich auch sehr komfortabel mit Caliburn.Micro umsetzen.

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

hallo nochmals, srry das ich den Thread mal wieder vorhole jedoch bleiben meine Daten dennoch leer? ._.

Habe den Code soweit verändert.
Model


 using (SQLiteConnection conn = new SQLiteConnection(connectionString))
            {
                try
                {
                    conn.Open();
                    SQLiteCommand cmd = new SQLiteCommand("SELECT Domain, Account, Password from passwords", conn);
                    SQLiteDataReader reader = cmd.ExecuteReader();

                    while (reader.Read())
                    {
                        Domain = reader["Domain"].ToString();
                        Account = reader["Account"].ToString();
                        passwort = reader["Password"].ToString();

                    }

                    reader.Close();
                    reader.Dispose();
                    cmd.Dispose();

                    conn.Close();
                    conn.Dispose();
                }
                catch (Exception ex)
                {

                    MessageBox.Show(ex.Message);

                }
            }

ViewModel


public List<passwordModel> PasswordList { get; set; }

        private passwordModel _Model;

        public passwordViewModel(passwordModel model)
        {

            _Model = model;
            _Password = _Model.passwort;
            _Domain = _Model.Domain;
            _Account = _Model.Account;

        }

        private string _Account;
        public string account
        {
            get { return _Account; }
            set
            {
                _Account = value;
            }
        }

        private string _Domain;
        public string domain
        {
            get { return _Domain; }
            set
            {
                _Domain = value;
            }
        }

        private string _Password;
        public string password
        { 
            get { return _Password; }
            set { _Password = value; }
        }

        public passwordViewModel()
        {
            PasswordList = new List<passwordModel>
            {
            
                new passwordModel
                {
                    
                    Domain = domain,
                    Account = account,
                    passwort = password,

                },
        
            };
        
        }

Meine Liste bleibt jedoch trotzdem leer?
Sieht vielleicht emand auf anhieb den fehler? 😒

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo gh0st93,

schau dir mal an was usings machen und benutze sie richtig (du rufst Dispose immernoch explizit auf).

Du musst auch irgendwo dein "passwordViewModel" erstellen. Der C'tor wird nirgends aufgerufen.
Aber mit MVVM hat das irgendwie wenig zu tun 😉

Lies dir nochmal ein Tutorial zu MVVM durch. Dazu auch [Artikel] Drei-Schichten-Architektur

Im Prinzip habe ich hier schon alles erklärt. Alles, was du tun musst, ist die Methode "GetListOfPersons()" so implementieren, dass die Infos aus der DB kommen statt, wie bei mir, hart gecodet.

Gruss

Coffeebean

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

Coffeebean:
Ja, nur leider weiß ich nicht, wie ich dies in die Liste einpacken soll. <.<
In der Liste die Daten selbst neu eintragen geht, dass bekomm ich hin jedoch
schon vorhandene Daten in die Liste übergeben, dass bekomm ich irgendwie nicht hin.

In meiner ViewModel
sind doch meine Variablen
_Password & _Domain & _Account
meine Daten aus der DB.

: Ich bräuchte halt ein Tutorial, was mir den Einsatz von MVVM mit einer Datenbank erläutert.
Im Netz finden sich nur Tutorials, worin die Daten selbst eingetragen werden.

F
10.010 Beiträge seit 2004
vor 8 Jahren

Das hat doch nun überhaupt nichts mit MVVM zu tun.

Du solltest dir endlich [Artikel] Drei-Schichten-Architektur anschauen.

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

vielen Dank schon mal für wie antworten.
Doch in wie fern hilft mir in einem praktischen Fehler als Anfänger ein theoretischer Thread?

Aber gut so komm ich leider nicht weiter.

Ich versetzte einfach alles wieder zum code-behind und versuch das pattern später wenn ich mehr praktische Erfahrung habe um.

Vielen Dank.

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo gh0st93,

naja, irgendwo bist du Entwickler 😃 Alles was du tun musst ist die eine Klasse zu schreiben, in der du deine DB-Abfragen machst.
Da füllst du mit dem Reader eine Liste ab und gibst die einfach zurück.

Das hat nichts mit dem Pattern zu tun, das hat FZelle schon richtig gesagt.

In deinem ViewModel ist nur die Liste deiner Klasse, die du binden willst. Und die Objekte in der Liste haben deine drei Properties, die du binden willst.

Deswegen gibst du ja im XAML die Liste als Itemsource an und kannst dann innerhalb der Listview auf die einzelnene Properties binden.

Gruss

Coffeebean

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

Coffeebean:
Klar, dass dies nichts mit mvvm zutun hat. Wie schon gesagt hatte ich nur Probleme in der Liste die Daten auf der DB anzugeben.
Da ich die Syntex nicht kenne wie die letzte definiert wird.
Hatte so eine Liste nie gebraucht und auch kein Ansatz gefunden wie ich das machen soll.
Konnte auch kein Beispiel im Netz finden.
Daher bringt mir ein Thread darüber wie ich meine schichten teile nicht hilfreich.
Wie gesagt ich pack alles wirst in den code-behind verzichte für s erste auf das pattern schau mir noch einige Grundlagen tut's an und eigne mir das mvvm zu einem späteren Zeitpunkt ein.

Trotzdem danke ich dich für wie Mühe.
Liebe grüsse.

F
10.010 Beiträge seit 2004
vor 8 Jahren

@gh0st93:
Wie willst du jemals vorwärts kommen wenn du nicht bereit bist die Grundlagen zu erlesen?
Meinst du die sind uns zugeflogen?
Nein, man muss lesen und lesen dann probieren ob man es richtig gemacht hat.

Aber wenn du das Prinzip aus [Artikel] Drei-Schichten-Architektur schon bei Codebehind nicht verstanden hast, dann wird es aber wirklich mal zeit.

  1. Datenbank Zugriffe haben im UI Layer und das ist Codebehind genauso wie MVVM nichts zu suchen.
    Das gehört in einen dafür zuständigen Dienst oder ein Repository.

  2. Diese Datenzugriffsschicht liefert dir das Model oder die Modelle.

  3. Deine VM bilden diese für die UI entweder über Properties ( bei Model ) oder über Listen von weiteren VM ab.

Das ist kein Hexenwerk, versteht man aber erst richtig wenn man bereit ist mal die Grundlagen zu erlesen.
Sonst bleibt man immer Anfänger.

Und was ist so schwer in deinem "while (reader.Read())" ein neues Object anzulegen und einer Liste Hinzuzufügen?
Also das sind nun wirklich Basics die nichts mit WPF oder UI überhaupt zu tun haben.

2.207 Beiträge seit 2011
vor 8 Jahren

Hatte so eine Liste nie gebraucht und auch kein Ansatz gefunden wie ich das machen soll.
Konnte auch kein Beispiel im Netz finden.

Bei aller Liebe: Das glaube ich dir nicht.

Google-Suche nach List c#

189 Beiträge seit 2014
vor 8 Jahren

Hallo gh0st93,

Klar, dass dies nichts mit mvvm zutun hat. Wie schon gesagt hatte ich nur Probleme in der Liste die Daten auf der DB anzugeben.
[...]
Wie gesagt ich pack alles wirst in den code-behind verzichte für s erste auf das pattern schau mir noch einige Grundlagen tut's an und eigne mir das mvvm zu einem späteren Zeitpunkt ein.

Das ist irgendwie sehr wiedersprüchlich.
An sich warst du am Anfang dieses Themas ja schon in die richtige Richtung unterwegs.
Bezüglich Listen: Schaue dir mal OpenBook C# Kapitel 9 mit Schwerpunkt Kapitel 9.9 an.
Zusätzlich ist für dich auch der Listentyp ObservableCollection<T> wichtig.
Sieh dir zu beidem bitte auch unbedingt die MSDN-Seiten an.

So, nun konkreter.
In deinem VM hast du eine ObservableCollection<PersonModel>.
(Auf diese bindest du in der View.)
Diese füllst du im Konstruktor oder in einem Command mit Hilfe einer Repository-Klasse.
Diese Klasse ist die eigentliche Verbindung zur DB.
Man könnte ihr im Konstruktor alle wichtigen Infos für den Verbindungsaufbau übergeben und eine Funktion Get() einrichten, die die Personen von der DB läd, eine List<PersonModel> erstellt und zurück gibt.
Dann brauchst du nur noch im VM die Liste zu einer OC machen und fertig.

Wie du siehst hat die Beschaffung der Daten nix mit dem VM zu tun.
Theoretisch könntest du dir die Daten ganz anders beschaffen.
Wenn du für das Repository ein schönes Interface baust, kannst du am Ende sogar das Repository austauschen und die Daten z.B. aus ne XML-Datei holen ohne eine Zeile Code im "MVVM-Bereich" deiner Anwendung zu ändern.

VG Ezio

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

Hab jetzt mal etwas rumgebastelt (ist allerdings noch ungetestet)
So ungefähr? - Wenn ja, habe ich das Prinzip schon einmal verstanden und kann darauf weiter aufbauen.

Das ist meine sozusagen repository klasse

 public class Database
    {

        private string _ConnectionString, _ConnectionPath;

        public Database(string connectionString, string connectionPath)
        {
            _ConnectionPath = connectionPath;
            _ConnectionString = connectionString;
        }

        public List<string> select(string fromTable, string selected, bool lookingForWho, string where, string reading)
        {
            using (var con = new SQLiteConnection(@"Data Source=" + _ConnectionPath + "\\" + _ConnectionString))
            {
                con.Open();
                SQLiteDataReader r;

                List<string> selectList = new List<string>();
                using (SQLiteCommand reader = new SQLiteCommand(con))
                {
                    switch (lookingForWho)
                    {

                        case true:
                            
                            reader.CommandText = @"SELECT " + selected + " FROM " + fromTable + "WHERE " + where;
                            r = reader.ExecuteReader();
                            while(r.Read())
                            {
                                selectList.Add(Convert.ToString(reading));
                            }
                            
                            break;
                        
                        case false:
                            
                            reader.CommandText = @"SELECT " + selected + " FROM " + fromTable + "WHERE " + where;
                            r = reader.ExecuteReader();
                            while(r.Read())
                            {
                                selectList.Add(Convert.ToString(reading));
                            }
                            
                            break;
                    
                    }

                } // end using Command

                con.Close();

                return selectList;

            } // end using Connection
           
        } // end List

    } // end class

Hier stell ich die vb zu DB her, erstelle ne Liste packe diese mit Daten und lass mir die Liste mit daten zurück geben & so greif ich auf die Liste zu & setzte dies später dan in ein OC.


Database db = new Database("Name_der_DB", "C:\\Pfad_der_DB");

        List<string> test = new List<string>();

 test = db.select("Tutorial", "Name", false, "", "Name");

?

F
10.010 Beiträge seit 2004
vor 8 Jahren

Nein, das ist es nicht.
So muss deine UI wissen wie Tabellen heißen, wie Abfragen gemacht werden usw.

Dein Repository sollte konkrete Klassen liefern und die Abfragen selber machen.
Was du da hast ist erst mal nur ein DAL.
Auch solltest du aufhören alles in strings zu frickeln.
C# ist eine typisierte Sprache, benutze also echte typen.

Wenn du sowieso SQLite einsetzen willst, benutze entweder SQLite-Net oder z.b. Linq2Db als ORMapper.

SQLite-Net besteht aus einer C# Datei ( über NuGet zu bekommen ) und einer DLL die du unter http://www.sqlite.org/download.html bekommst.

Habe das mal in 20 Minuten nach dem essen zusammengehackt.
paar mal auf "Neue Person" geclicked und dann speichern.

Ist wirklich nicht viel

G
gh0st93 Themenstarter:in
85 Beiträge seit 2014
vor 8 Jahren

So muss deine UI wissen wie Tabellen heißen, wie Abfragen gemacht werden usw.

Wieso muss, wenn ich dies so mache, meine UI wissen wie meine Tabellen heißen?
in meiner UI hab ich ja nur die Databinding an mein VM, & das VM sendet die Daten an das Model was wiederrum die Daten speichert?!

Auch solltest du aufhören alles in strings zu frickeln.
C# ist eine typisierte Sprache, benutze also echte typen.

Die Aussage versteh ich nun nicht ganz genau?
sind 'strings' keine echte typen? und wen ich vorerst nur Name, Domain und passwort speichere sind dies doch strings. oder meinst Du wegen den Query's ?

Wenn du sowieso SQLite einsetzen willst, benutze entweder SQLite-Net oder z.b. Linq2Db als ORMapper.

SQLite-Net besteht aus einer C# Datei ( über NuGet zu bekommen ) und einer DLL die du unter
>
bekommst.

Ja, die dll's hab ich. Nur hab ich im Netz so einiges über Mapper gesucht, gefunden und den überblick nun schluss endlich doch total verloren! was genau machen den Mapper & wann ist deren Einsatz von vorteilhaft?
Würde die DAl, wie ich es bis jetzt hab für ne vorerst kleine Anwendung nicht reichen?

&'nd wie sooft steht man nun als Anfänger wieder da und weiß nicht weiter.

Würde es nicht gehen, wenn ich mir einfach eine Helper-class erstelle, was mir die Verbindung aufbaut, daten ausgibt/einliest/bearbeitet/löscht und mir dementsprechend eine Liste zurück gibt worauf ich im Model auf die Liste zugreife, dort je nach bedarf Sortiere, was genau angezeigt wird und was nicht und wieder eine Liste zurück gebe um dann im VM auf diese Liste zuzugriefen und dies im View dan als DataContext nutze?

5.658 Beiträge seit 2006
vor 8 Jahren

Hi gh0st93,

&'nd wie sooft steht man nun als Anfänger wieder da und weiß nicht weiter.

Wenn ich mir deinen Code so anschaue, solltest du evtl. erstmal ein Buch über die Grundlagen von C# lesen. Wieso verwendest du ein switch-Statement für Boolsche Werte, wenn doch dafür ein einfaches if/else reichen würde? Ganz abgesehen davon, daß beide Codezweige exakt das gleiche machen. Wenn du die Möglichkeiten und Grenzen der Sprache verstanden hast, dann kannst du dich mit Datenbanken beschäftigen. Auch hier gibt es einiges zu beachten, z.B. das Arbeiten mit Parametern: [Artikelserie] SQL: Parameter von Befehlen.

Wenn du dich aber stattdessen gleich mit OR-Mappern oder mehrschichtigen Anwendungen beschäftigen willst, dann ist klar, daß du gar nicht verstehst, worum es eigentlich geht, und welche Probleme dadurch gelöst werden sollten. Eventuell solltest du mal überlegen, ob du nicht erstmal mit einfacheren Sachen anfängst, und dich erstmal in den Grundlagen übst. Ansonsten wirst du immer wieder frustiert vor irgendwelchen Problemen stehen, die du nicht verstehst.

Man fängt ja schließlich auch nicht gleich nach der ersten Klavierstunde an, Chopin zu spielen.

Christian

Weeks of programming can save you hours of planning

F
10.010 Beiträge seit 2004
vor 8 Jahren

Wieso muss, wenn ich dies so mache, meine UI wissen wie meine Tabellen heißen?
in meiner UI hab ich ja nur die Databinding an mein VM, & das VM sendet die Daten an das Model was wiederrum die Daten speichert?!

Solltest du irgendwann mal die Artikel durchlesen die wir dir hier ständig ans Herz legen hättest du schon lange verstanden das ( View + VM ) == UI Layer.

sind 'strings' keine echte typen?

Doch, aber nur wenn das das einzige ist, was du lesen willst.
Du willst aber ganze Objekte lesen, also z.b. eine Person.
Das diese dann Name, Vorname usw hat ist dabei erstmal nebensächlich.
Aber das Problem ensteht ja nur weil du o.g. nicht verstanden hast.

Hör endlich auf irgendwas wild zu suchen, oder irgendwas auszuprobieren.
Das kannst du machen wenn du die Grundlagen verstanden hast.

Würde es nicht gehen, wenn ich mir einfach eine Helper-class erstelle, was mir die Verbindung aufbaut, daten ausgibt/einliest/bearbeitet/löscht und mir dementsprechend eine Liste zurück gibt worauf ich im Model auf die Liste zugreife, dort je nach bedarf Sortiere, was genau angezeigt wird und was nicht und wieder eine Liste zurück gebe um dann im VM auf diese Liste zuzugriefen und dies im View dan als DataContext nutze?

Genau das ist das Repository.
Nur das hier statt Connection und DataReader eben der ORMapper benutzt wurde.
Steht aber auch in dem wieder und wieder verlinkten Artikel.