Laden...

DataGrid füllen aus SQLite Database

Erstellt von Mert93 vor 8 Jahren Letzter Beitrag vor 8 Jahren 5.282 Views
M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren
DataGrid füllen aus SQLite Database

Hallo liebes Forum. 😃
Ich versuche grade mein DataGrid mit den Daten aus meiner DB zu füllen doch wird mir leider nix angezeigt. 😦

Mein DataGrid

<DataGrid x:Name="adressenDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" SelectedItem="{Binding AuflistungSelected}" ItemsSource="{Binding Auflistung}" CanUserAddRows="False" RowDetailsVisibilityMode="VisibleWhenSelected">
                <DataGrid.DataContext>
                    <ViewModels:MainWindowViewModel/>
                </DataGrid.DataContext>
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="iDColumn" Binding="{Binding ID}" Header="ID" Width="55"/>
                    <DataGridTextColumn x:Name="anredeColumn" Binding="{Binding Anrede}" Header="Anrede" Width="95"/>
                    <DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="1*"/>
                </DataGrid.Columns>
            </DataGrid>

MeinWindowViewModel


        private ObservableCollection<AdressModel> _Auflistung;
        private ObservableCollection<AdressModel> _AuflistungSelected;

        public ObservableCollection<AdressModel> AuflistungSelected
        {
            get { return _AuflistungSelected; }
            set
            {
                if (_AuflistungSelected != value)
                { _AuflistungSelected = value; NotifyPropertyChanged(); }
            }
        }

        public ObservableCollection<AdressModel> Auflistung
        {
            get { return this._Auflistung; }
            set
            {
                if (_Auflistung != value)
                { _Auflistung = value; NotifyPropertyChanged(); }
            }
        }


#region Kontakt Speichern
        RelayCommand _saveContact;
        public ICommand SaveContact
        {
            get
            {
                if (_saveContact == null)
                {
                    _saveContact = new RelayCommand(param => this.makeSaveContact(), param => IsTrue());
                }
                return _saveContact;
            }
        }

        private bool IsTrue()
        {
            if (Name != null)
            { return true; }
            else { return false; }

        }

        private void makeSaveContact()
        {
            using (var instance = new AdressModel())
            {
                Adressen ad = new Adressen();

                ad.Anrede = Anrede;
                ad.Name = Name;
                ad.Vorname = Vorname;
                ad.Strasse = Strasse;
                ad.Postfach = Postfach;
                ad.Ort = Ort;
                ad.PLZ = PLZ;
                ad.TeleBeruf = TeleBeruf;
                ad.TeleMobile = TeleMobile;
                ad.TelePrivat = TelePrivat;
                ad.Faxnummer = Faxnummer;
                ad.Email = Email;
                ad.Homepage = Homepage;
                ad.IBAN = IBAN;
                ad.BIC = BIC;
                ad.Bundesland = Bundesland;
                ad.Anmerkung = Anmerkung;
                ad.Bday = Bday;

                instance.Adressen.Add(ad);
                instance.SaveChanges();
            }

Ist doch "eigentlich" alles richtig, oder?

Gespeichert werden die Daten so wie sie sollen. Werden mir nur ledeglich nicht angezeigt,
Ich nutzte SQLite + EntityFramework (Code First)
Sieht ihr eventuell wo mein Fehler ist? 😒
PS: ich weiß, die Namensgebung ist nicht die beste aber erfüllt sein zweck 😄

1.040 Beiträge seit 2007
vor 8 Jahren

Wann genau kommen Daten in die Auflistung?

Die AuflistungSelected muss übrigens vom Typ AdressModel sein, aber das nur am Rande...

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo Mert93,

du bindest eine Collection "Auflistung" and das DataGrid. Darin enthalten sind AdressModels. Willst du vielleicht Adressen an deine DataGrid binden? Aus deinem Code sieht man, dass "Adressen" all die Properties haben (bis auf die ID), die du binden willst.

Lange Rede kurzer Sinn: Schau ob die Properites auf dem Typ bereitstehen, den du bindest.

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

Gruss

Coffeebean

2.079 Beiträge seit 2012
vor 8 Jahren

PS: ich weiß, die Namensgebung ist nicht die beste aber erfüllt sein zweck 😄

Noch 😉

Zum Beispiel sehe ich hier ein paar Probleme in der Namesgebung, die es zumindest mir schwer machen, deinen Code zu verstehen.

Zuerst einmal: Die SelectedItem-Property vom DataGrid beinhaltet nur ein Item, Du bindest aber an eine Liste. Die SelectedItems-Property ist keine DependencyProperty, dafür müsstest Du dir eine eigene AttachedProperty schreiben.

Und hau die IsTrue-Methode raus.
Das einzige, was die tut, ist folgendes:

return Name != null;

Und das kannst Du direkt im RelayCommand als Lambda schreiben.

Ein weiterer Punkt, den ich nicht verstehe:
Was genau ist AdressModel? Das IDisposable finde ich irgendwie ziemlich fehl am Platz, ein einfaches Datenobjekt sollte kein Dispose brauchen O.o

Hat AdressModel überhaupt die besagten Eigenschaften ""ID", "Andrede" und "Name"?
Wenn ich mir eine Adresse vorstellen (was der Name suggestiert), würde ich da nur die Property "ID" vorstellen können.

W
872 Beiträge seit 2005
vor 8 Jahren

Wenn Du VS2015 benutzt - dann solltest Du mal im Output Window nach Binding Fehlern schauen. Du solltest bei "Options" "Debugging" "Output Window" "WPF Trace Settings" schauen, das es angeschaltet ist

M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren

Ok. Ich sehe, dass ich wohl "einige" falsche Wege eingeschlagen habe. x)

Ich schau mal im Netz ob ich ein nutzsbares Tutorial zu dem Thema C#, WPF, SQLite + EntityFramework was finde. =)

Danke für eure mühen. x.x

PS: AdressModel ist von EF selbst erzeugte Klasse mit dem DbSet.

1.040 Beiträge seit 2007
vor 8 Jahren

SQLite & EntityFramework haben erstmal nichts mit deinem Problem zu tun, wahrscheinlich sind einfach 'nur' die Bindings falsch.

2.079 Beiträge seit 2012
vor 8 Jahren

PS: AdressModel ist von EF selbst erzeugte Klasse mit dem DbSet.

Das beantwortet meine Frage nicht: Hat die Klassen die Properties "ID", "Andrede" und "Name"?
Und dann muss ein ViewModel bzw. eine Klasse, an die Du bindest, INotifyPropertyChanged implementieren, wenn sich darin Werte ändern können - und davon gehe ich mal aus.
Aus dem Grund nehme ich eigentlich nie direkt Model-Klassen, sondern schreibe immer ein ViewModel. Das kann dann ja immer noch an das Model durch reichen, aber es ist eine eigene Klasse und implementiert genau das, was die View braucht.

Außerdem solltest Du schon verstehen, wie das EntityFramework arbeitet. Das generiert dir zwar die Klassen, aber Du hast nichts gewonnen, wenn das Speichern/Ladden dann "zufällig" funktionieren, wenn Du deshalb an anderer Stelle Fehler machst, die Du leicht vermeiden könntest.
Ein gutes Tutorial findest Du hier.

M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren

Palladin007:
Ja, die sind enthalten.

modelBuilder.Entity<Adressen>()
                .Property(e => e.ID);

            modelBuilder.Entity<Adressen>()
                .Property(e => e.Anrede)
                .IsUnicode(false);

            modelBuilder.Entity<Adressen>()
                .Property(e => e.Name)
                .IsUnicode(false);

Und das MainWindowViewModel enthält



    public class MainWindowViewModel : INotifyPropertyChanged
    {
private string _Anrede, _Name, _Vorname;
private int _ID;

private ObservableCollection<Adressen> _Auflistung;
        private ObservableCollection<AdressModel> _AuflistungSelected;

        public ObservableCollection<AdressModel> AuflistungSelected
        {
            get { return _AuflistungSelected; }
            set
            {
                if (_AuflistungSelected != value)
                { _AuflistungSelected = value; NotifyPropertyChanged(); }
            }
        }

        public ObservableCollection<Adressen> Auflistung
        {
            get { return this._Auflistung; }
            set
            {
                if (_Auflistung != value)
                { _Auflistung = value; NotifyPropertyChanged(); }
            }
        }

        public int? ID
        {
            get { return _ID; }
            set { if (_ID != value) { _ID = value; } }
        }

        public string Anrede
        {
            get { return _Anrede; }
            set
            {
                if (_Anrede != value)
                { _Anrede = value; NotifyPropertyChanged(); }
            }
        }

        public string Name
        {
            get { return _Name; }
            set
            {
                if (_Name != value)
                { _Name = value; NotifyPropertyChanged(); }
            }
        }
      
}
2.079 Beiträge seit 2012
vor 8 Jahren

Was das MainViewModel enthält ist unwichtig, denn die Column bekommt beim Binding ein Element der Auflistung vom DataGrid, sprich AdressModel.

Und der Code, den Du zeigst, zeigt nicht, dass AdressModel die besagten Properties enthält.
Das was Du zeigst ist die Konfiguration, wie EF die Klassen auf das Datenbank-Schema mapped.
Außerdem mappst Du hier nicht die Properties der AdressModel-Klasse, sondern von der Klasse Adressen. Das DataGrid bekommt aber eine AdressModel-Liste.

Lies dir mal das Tutorial durch, was ich verlinkt habe.
Das versucht nicht, vollständit zu sein, aber es erklärt eigentlich alles, was Du so allgemein brauchst.
Dann verstehst Du auch, was das Entity Framework tut, das macht ja viel automatisch und man sollte wissen, was automatisch passiert, sonst verlierst Du schnell den Überblick.

Ich persönlich halte es so, dass ich die Klassen selber schreibe, ich lasse sie nicht generieren.
So mache ich mir konkret zu jeder Klasse Gedanken und weiß am Ende auch genau, was wo sein soll.

M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren

Ok, die Daten an das DataGrid bekomm ich nun gefüllt.
Ich hab nur noch 2 kleine probleme.

  1. Wenn ich Daten abspeichere wird mein DataGrid nicht mit den neuen Daten gefüllt, außer ich beende die Anwendung und öffne Sie erneut.
  2. In mein DataGrid hab ich nen Button, dass man sich die Daten in den TextBoxen wieder anzeigen lassen kann, dies klappt jedoch nicht, wenn der Button in mein DataGrid ist.

Das INotifyPropertyChanged ist implementiert, hatte es auch mit PRISM versucht, hat auch nicht soganz Funktioniert.

Habt Ihr eventuell ein anderen Lösungsweg für mich?


<DataGrid Style="{StaticResource AzureDataGrid}" FontSize="17" AutoGenerateColumns="False" 
                      ItemsSource="{Binding AllContacts}" IsReadOnly="True"
                      SelectionMode="Single" SelectedValue="{Binding SelectedContact}" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Width="135" Header="Auswählen">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button Content="Auswählen" Command="{Binding Select}" Margin="6"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn Header="Anrede" Binding="{Binding Anrede}" Width="105" FontSize="18"/>
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="1*" FontSize="18"/>
                </DataGrid.Columns>
            </DataGrid>



private ObservableCollection<Adressen> _allContacts;
private Adressen _selectedContact;

        public ObservableCollection<Adressen> AllContacts
        {
            get { return this._allContacts; }
            set
            {
                if(_allContacts != value)
                {
                    _allContacts = value;
                    NotifyPropertyChanged();
                }
                
            }
        }

        public Adressen SelectedContact
        {
            get { return _selectedContact; }
            set
            {
                if(value!= this._selectedContact)
                {
                    this._selectedContact = value;
                    NotifyPropertyChanged();
                }
            }
        }

#region SaveCommand
RelayCommand _saveContact;
        public ICommand SaveContact
        {
            get
            {
                if (_saveContact == null)
                {
                    _saveContact = new RelayCommand(param => this.makeSaveContact(), param => true);
                }
                return _saveContact;
            }
        }

private void makeSaveContact()
        {
            using (var db = new AdressenEntityModel())
            {
                Adressen a = new Adressen();
                a.Anrede = _anrede;
                a.Name = _name;
                a.Vorname = _vorname;
                a.Geburtsdatum = _geburtsdatum;
                a.Ort = _ort;
                a.Postfach = _postfach;
                a.Strasse = _strasse;
                a.PLZ = _plz;
                a.Email = _email;
                a.Homepage = _homepage;
                a.TelefonBeruf = _telB;
                a.TelefonMobile = _telM;
                a.TelefonPrivat = _telP;
                a.Faxnummer = _faxnummer;
                a.IBAN = _iban;
                a.BIC = _bic;
                a.Anmerkung = _anmerkung;
                a.Bundesland = _bundesland;

                db.Adressen.Add(a);
                db.SaveChanges();
                GetDatas();
            }
        }
#endregion

#region Selected
        RelayCommand _select;
        public ICommand Select
        {
            get
            {
                if (_select == null)
                {
                    _select = new RelayCommand(param => this.Selected(), param => true);
                }
                return _select;
            }
        }

        private void Selected()
        {
            Name = _selectedContact.Name;
            Anrede = _selectedContact.Anrede;
            Vorname = _selectedContact.Vorname;
            Geburtsdatum = _selectedContact.Geburtsdatum;
            
        }
        #endregion


2.079 Beiträge seit 2012
vor 8 Jahren

Wenn ich Daten abspeichere wird mein DataGrid nicht mit den neuen Daten gefüllt, außer ich beende die Anwendung und öffne Sie erneut.

Kommen die Daten nicht aus dem DataGrid? Dann müsste die doch drin stehen
Wenn die Daten von wo anders kommen und direkt über das Model in der Datenbank gespeichert werden, würde ich - analog zum SaveCommand - einen LoadCommand schreiben, der die Daten lädt. Das kannst Du dann z.B. hinter einem Aktualisieren-Button aufrufen, oder Du rufst eine Load-Methode direkt nach dem Ändern der Daten auf. Oder Du behältst ein Event, was dem ViewModel mit teilt, dass die Daten geändert wurden und es aktualisieren muss.

In mein DataGrid hab ich nen Button, dass man sich die Daten in den TextBoxen wieder anzeigen lassen kann, dies klappt jedoch nicht, wenn der Button in mein DataGrid ist.

Ohne Code lässt sich hier nichts sagen.
Das klingt aber ganz stark nach einem kaputten Binding.
So einen Button würde ich aber auch nicht im DataGrid ansiedeln. Das DataGrid enthält nur die Columns und das, was für die Properties des DataGrids ist. Alles andere, z.B. ein Button neben dem DataGrid, wird über ein Panel positioniert. DtackPanel, DockPanel, Grid, etc.

Hast Du ein ContextMenu im DataGrid mit dem Command - Versuch den Button lieber neben dem DataGrid zu positionieren 😄
Ich hab auch immer Probleme, in einem ContextMenu zu binden. Da das ContextMenu nicht regulär ein Teil des VisualTrees ist, ist es auch niicht ganz so einfach, an den DataContext vom DataGrid zu kommen.
Du kannst versuchen, im Binding als RelativeSource über den AncestorType das DataGrid zu suchen. Ich persönlich bin aber eher ein Fan vom BindingProxy. Das ist ein Objekt, was irgendwo in den Resourcen von einem Element liegt und die Daten, die Du willst in seiner Data-Property per Binding bereit hält. Im ContextMenu kannst Du dann normal binden, aber die Source-Property setzt Du auf die StaticResource. Beispiele dazu sind im Link.

Was mir bei deinem Code noch auffällt:

Adressen a = new Adressen();
a.Anrede = _anrede;
a.Name = _name;
a.Vorname = _vorname;
a.Geburtsdatum = _geburtsdatum;
a.Ort = _ort;
a.Postfach = _postfach;
a.Strasse = _strasse;
a.PLZ = _plz;
a.Email = _email;
a.Homepage = _homepage;
a.TelefonBeruf = _telB;
a.TelefonMobile = _telM;
a.TelefonPrivat = _telP;
a.Faxnummer = _faxnummer;
a.IBAN = _iban;
a.BIC = _bic;
a.Anmerkung = _anmerkung;
a.Bundesland = _bundesland;

Was sind das für Klassen-Variablen (Die mit dem Unterstrich)? Das sieht für mich nicht so aus, als würden sie da hin gehören.
Ich würde da eher ein AddessViewModel erstellen, was auch INotifyPropertyChanged implementiert. Das Erstellen einer neuen Adresse besteht dann daraus, davon ein neues Objekt der Liste hinzuzufügen.
Im Speichern musst Du dann beachten, dass manche Adressen noch im Datenmodel fehlen.

PS:
Schlag dir Prism mal wieder aus dem Kopf.
Das ist ein Framework zur sauberen modularisierung von Anwendungen. Wenn Du das nicht brauchst, machst Du dir deine Anwendung nur komplizierter als notwendig.
Das Binding, was Du da haben willst, ist Standard in WPF, dafür brauchst Du kein Prism.

M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren

Palladin007:
Das sind meine Privat deklarierten Variablen in der AdressenViewModel
PS: Habe nur die eine ViewModel klasse, da das Programm eigentlich weiter sonst nix tuen braucht, ich mich in mvvm mal weiter ausbauen wollte habe ich die beiden einfach vereint. . Auch wen für die kleine Anwendung Code-Behind eigentlich auch getan hätte.


private string _anrede;
private string _name;
//.....

public string Anrede
{
get { return this._anrede; }
set 
{
if(this._anrede != value)
this._anrede = value;
NotifyPropertyChanged();
}
// .. und so weiter
5.299 Beiträge seit 2008
vor 8 Jahren

ich versteh den ganzen Vorgang nicht.
Also du hast ein Datagrid, dann hast du wohl auch eine Auflistung von Addressen.

Wieso willst du dann nur eine Addresse abspeichern?
Und was machst du, wenn du eine Addresse löschst? Oder wenn eine bestehende geändert wird?

Also In meiner Welt würde man die Addressen bearbeiten nach Belieben, und dann alle auf einmal abspeichern.
Also alle, die geändert, gelöscht oder hinzugefügt wurden, unveränderte würde man natürlich nicht abspeichern.
Dieses zu unterscheiden ist Aufgabe des sog. ChangeTracking - EF sollte das draufhaben.

Also laden, was man will, ändern was man will, und dann ein einziger Aufruf: objectContext.SaveChanges(), und alles ist in trockenen Tüchern.

Der frühe Apfel fängt den Wurm.

M
Mert93 Themenstarter:in
64 Beiträge seit 2015
vor 8 Jahren

ErfinderDesRades:
Das Programm ist für einen Nachbar gedacht, der unter starker Seeschwäche leidet.
Es wird nicht von Nöten sein, mehr als einen Kontakt abzuspeichern und wieder anzeigen zu lassen.
Ich hatte vorerst auch in Planung, aus mein DT die Daten zu speichern, jedoch da der Nachbar ein Vergrößerung's Programm nutzt und sich alles bis zu 6x-7x Vergrößern lässt am Bildschirm würde man im DataGrid dann nach genug einträgen nicht mehr sehen können, was nun in welchen Feld eingetragen werden müsste.
So erschien mir zumindest, dass es so doch schon besser ist.
PS: Schließlich lernt man ja auch nicht am Tag mehrere Menschen kennen 😁

2.079 Beiträge seit 2012
vor 8 Jahren

Dann würde ich aber kein DataGrid verwenden, sondern ein ItemsControl.
Jede Adess-Item wird dann so dargestellt, dass es bei starker Vergrößerung genau auf den Bildschirm passt. Wichtig ist nur, dass nie seitlich gescrollt werden muss, das nervt nämlich tierisch 😄
Der User (dein Nachbar) kann dann weiter scrollen oder über ein paar Buttons am oberen Bildschirm-Rand speichern oder andere Dinge machen.

Und doch: Ich habe schon öffter viele Leute am selben Tag kennen gelernt 😄