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
Entity Framework CORE und WPF Datagrid
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

Entity Framework CORE und WPF Datagrid

beantworten | zitieren | melden

Hallo Leute,
ich bin blutiger Anfänger im Bereich EF Core und WPF und versuche derzeit mir diese Technologien selbst beizubringen.
Also ich habe in SQL Server zwei Tabellen erstellt (ChemischeAnalysen und ChemischeAnalysenDetails) und beide mit einem Fremschlüssel verknüpft. Anschließend habe ich in VS in einem Konsolen-Projekt das Model mit Scaffold-DBContext erstellt. Dann konnte ich einfach mit LINQ die Daten abfragen:


var context = new Models.BetriebsdatenContext();
            var analysen = context.ChemischeAnalysen
                                                .Include(s => s.ChemischeAnalysenDetails)
                                                .ToList();

Das klappt einwandfrei und es kommen auch die korrekten Daten zurückgeliefert. Wobei ich jedoch gnadenlos gescheitert bin ist die Bindung der Daten der untergeordneten Tabelle an ein WPF Datagrid.
Ich kann die Daten der übergeordneten Tabelle ChemischenAnalysen problemlos binden, aber bei der den Chemischen Analysen untergeordneten Liste (ChemischeAnalysenDetails) wird in den Spalten nichts angezeigt und ich bekomme einen Binding Path expression Error für diese Felder.
(Siehe bitte Bild im Anhang.)
Irgendwo fehlt mir hier offensichtlich ein grundsätzliches Verständnis wie diese Bindung gehandhabt wird.Wenn mir hier bitte jemand einen Stubs in die richtige Richtung geben könnte, wäre ich sehr dankbar.Ich habe mir schon einiges zum Thema "WPF Databinding with nested Lists" angesehen, und verstehe einfach nicht warum es bei mir nicht funktioniert.



<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTest"
        mc:Ignorable="d"
        Title="Analysis" Height="450" Width="800" Background="#FF797373">
        
    <Grid>
        <DataGrid x:Name="dataGrid1" HorizontalAlignment="Left" Height="401" Margin="10,10,0,0" VerticalAlignment="Top" Width="668" AutoGenerateColumns="False">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Datum" Binding="{Binding Datum}" Width="100"/>
                <DataGridTextColumn Header="Bezeichnung" Binding="{Binding Bezeichung}" Width="100"/>
                <DataGridTextColumn Header="Anmerkung" Binding="{Binding Anmerkung}" Width="100"/>
                <DataGridTextColumn Header="Gerät" Binding="{Binding Gerät}" Width="100"/>
                <DataGridTextColumn Header="Kategorie" Binding="{Binding Kategorie}" Width="100"/>
                <DataGridTextColumn Header="Element" Binding="{Binding ChemischeAnalysenDetails.Element}" Width="50"/>
                <DataGridTextColumn Header="Wert" Binding="{Binding ChemischeAnalysenDetails.Wert}" Width="50"/>
                <DataGridTextColumn Header="ChemieID" Binding="{Binding ChemischeAnalysenDetails.ChemieId}" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
        <Button x:Name="btnPopulate" Content="Bind&#xD;&#xA;" HorizontalAlignment="Left" Height="27" Margin="683,10,0,0" VerticalAlignment="Top" Width="100" Click="BtnPopulate_Click"/>

    </Grid>
</Window>


Vielen herzlichen Dank für Eure Hilfe.
Attachments
Meli
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5973
Herkunft: Leipzig

beantworten | zitieren | melden

Wenn ChemischeAnalysenDetails eine Liste ist, dann gibt es dort keine Eigenschaft Element.

Wenn ich es richtig verstehe, hat jeder Datensatz eine Liste von ChemischeAnalysenDetails, und du versuchst, diese in der gleichen Tabelle darzustellen. Wie soll denn das Ergebnis aussehen, das du erwartest?
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Schau dir mal das MVVM-Pattern an, damit kann man das relativ einfach lösen. Die grundlegende Idee wäre ein MainViewModel zu erstellen welches an die View gebunden wird. Dann benötigt man im ViewModel
* ein IEnumerable<ChemischeAnalyse> "List" für die die Hauptliste (gebunden an DataGrids ItemsSource)
* ein ChemischeAnalyse-Property "Current" das das aktuell im DataGrid gewählte Objekt repräsentiert (gebunden an DataGrids SelectedItem)
* ein IEnumerable<ChemischeAnalyseDetail> "Details" welches an das DetailGrid gebunden wird (ItemsSource)
Dann kann man prima im Setter von Current die Detailliste umhängen: wird ein anderes Objekt gewählt ändert sich Current, dann reicht einfach ein Details = Current.Details;
* ICommand's für Laden, Speichern etc
PS: Klassen sollten im Singular benannt werden um sie von namespaces unterschieden zu können.
private Nachricht | Beiträge des Benutzers
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo Mr. Sparkle,
danke für die Antwort.
Ja,das Ergebnis soll so sein wie in dieser Sicht in SQL Server.

CREATE VIEW [dbo].[ChemischeAnalyse]
AS
SELECT dbo.ChemischeAnalysen.Datum, dbo.ChemischeAnalysen.Bezeichung, dbo.ChemischeAnalysen.Anmerkung, dbo.ChemischeAnalysen.Gerät, dbo.ChemischeAnalysen.Kategorie, dbo.ChemischeAnalysen_Details.Element, dbo.ChemischeAnalysen_Details.Wert, 
             dbo.ChemischeAnalysen_Details.ChemieID
FROM   dbo.ChemischeAnalysen LEFT OUTER JOIN
             dbo.ChemischeAnalysen_Details ON dbo.ChemischeAnalysen.headerId = dbo.ChemischeAnalysen_Details.ChemieID
GO

Die beiden Klassen die EF Core generiert hat schauen so aus:


 public partial class ChemischeAnalysen
    {
        public ChemischeAnalysen()
        {
            ChemischeAnalysenDetails = new HashSet<ChemischeAnalysenDetails>();
        }

        public int HeaderId { get; set; }
        public DateTime? Datum { get; set; }
        public string Bezeichung { get; set; }
        public string Anmerkung { get; set; }
        public string Gerät { get; set; }
        public string Kategorie { get; set; }

        public virtual ICollection<ChemischeAnalysenDetails> ChemischeAnalysenDetails { get; set; }
    }


 public partial class ChemischeAnalysenDetails
    {
        public int Id { get; set; }
        public string Element { get; set; }
        public decimal? Wert { get; set; }
        public int? ChemieId { get; set; }

        public virtual ChemischeAnalysen Chemie { get; set; }
    }
}

Attachments
Meli
private Nachricht | Beiträge des Benutzers
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo Witte,
danke für die Antwort. Würdest Du diesen Artikel zum Thema empfehlen, den ich im Forum entdeckt habe, oder gibt es zum Thema Viewmodel noch bessere Tutorials/Bücher?
https://www.codingfreaks.de/2017/08/14/wpf-und-mvvm-richtig-einsetzen-teil-5/

Danke
Meli
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5973
Herkunft: Leipzig

beantworten | zitieren | melden

Zu MVVM gibt es hier diesen Artikel: [Artikel] MVVM und DataBinding. Das ist aber erst dann interessant, wenn die Daten auch geändert werden sollen. Solange sie nur angezeigt werden sollen, geht es auch so.

Nur ergibt die Ansicht keinen Sinn. Jeder Eintrag in deiner Liste hat ja mehrere Elemente, ChemieIDs etc.

Edit: Achso, ich glaube, jetzt verstehe ich es:


var analysen = context.ChemischeAnalysenDetails
   .Include(s => s.Chemie)
   .ToList();
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo,
ja das war ein dummes Beispiel jetzt. Also ChemischeAnalysen representiert einen Header für eine Analyse, ChemischeAnalysenDetails beinhaltet alle unter diesem Header gemessenen Elemente:
Also eigentlich ware das eine Master->Detail ansicht, nur möchte ich in erstem Schritt nur eine flache Liste.

Edit: Toller Artikel, Mr. Sparkle. Den werde ich in jedem Fall durcharbeiten!
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MGernot am .
Attachments
Meli
private Nachricht | Beiträge des Benutzers
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo Leute,
danke nochmal für eure Hilfe.Ich habe die Sache jetzt mal so mit JOIN gelöst, damit ich mal ein Erfolgserlebnis habe ;-) Bin immer wieder erstaunt, wie mächtig LINQ ist.
Soll man aber offensichtlich auch so nicht machen, sondern EF Core navigation properties verwenden.


  var analysis = (from a in context.ChemischeAnalysen
                                join p in context.ChemischeAnalysenDetails
                                on a.HeaderId equals p.ChemieId
                                select new
                                {
                                    Datum = a.Datum,
                                    Bezeichung = a.Bezeichung,
                                    Anmerkung = a.Anmerkung,
                                    Gerät = a.Gerät,
                                    Kategorie = a.Kategorie,
                                    Element = p.Element,
                                    Wert = p.Wert

                                }).ToList();

Ich merke jetzt das ich von diesen Technologien und Entwicklermuster viel zu wenig verstehe, um irgendwas sinnvolles auf die Beine zu stellen.

Danke, vorerst und schöne Grüße aus Österreich.
Attachments
Meli
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15967

beantworten | zitieren | melden

Tipp: Wenn Du schon teilweise Deutsch programmierst, was alles andere als eine gute Idee ist, dann lass bitte wenigstens die Umlaute weg.
Es funktioniert zwar theoretisch; aber EF hat das zumindest in der Vergangenheit nicht immer gemocht.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
MGernot
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo Abt,
ja danke für den Tip,werde ich in Zukunft vermeiden. Das ist so eine dumme Angewohnheit, die ich mir leider bei der VBA Programmierung eingehandelt habe.
Meli
private Nachricht | Beiträge des Benutzers
MorphieX
myCSharp.de - Member



Dabei seit:
Beiträge: 184
Herkunft: Rahden

beantworten | zitieren | melden

Ich wundere mich gerade, dass noch gar nicht der Einwand kam, dass Datenbank Entitäten nicht an die UI gebunden werden, sondern dafür ViewModels benutzt werden sollten.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15967

beantworten | zitieren | melden

Wurde implizit bereits durch den Hinweis auf mvvm gemacht.
Und wenn man nur liest ist das eben nur halb so schlimm.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers