Laden...

DataGrid / Dateneingabe in MS SQL Datenbank speichern

Erstellt von Timm2023 vor 4 Monaten Letzter Beitrag vor 3 Monaten 467 Views
T
Timm2023 Themenstarter:in
9 Beiträge seit 2023
vor 4 Monaten
DataGrid / Dateneingabe in MS SQL Datenbank speichern

Guten Abend zusammen,

in einer WPF Anwendung versuche ich mich gerade am DataGrid. Dieses befülle ich aus einer MS SQL Datenbank, was auch gut funktioniert.

Nun möchte ich, dass Dateneingaben im DataGrid wiederum in die Datenbank gespeichert werden. Durch meine Recherche und lesen hier in den Forumsbeiträge bin ich auf einen Ansatz mit DataTable und DataSet gestoßen, jedoch im Bereich DataGridView (Windows Forms). Bin mir nicht sicher, ob es der richtige Ansatz ist.

Nachfolgend die entsprechenden Auszüge aus dem Programmcode:

public class Mitarbeiter
{
    public string Vorname { get; set; }
    public string Nachname { get; set; }
    public string Geburtsort { get; set; }

    public Mitarbeiter (string vorname, string nachname, string geburtsort)
    {

        Vorname = vorname;
        Nachname = nachname;
           Geburtsort = geburtsort;
    }
}

private void Btn_GO_Click_1(object sender, RoutedEventArgs e)
{
    try
    {
        .
        .
        .
        
        String[] Daten1 = new String[3];
        String a = "";
        String b = "";
        String c = "";
        
        //Daten werden aus der Datenbank gelesen und zu einem Array hinzugefügt
        a += reader["Vorname"].ToString();
        b += reader["Nachname"].ToString();
        c += reader["Geburtsort"].ToString();

        Daten1[0] = a;
        Daten1[1] = b;
        Daten1[2] = c;


        Mitarbeiter newtemp = new Mitarbeiter(a, b, c);

        //Hier mein Ansatz mit DataTable und Dataset

        DataTable table = new DataTable();
        DataSet dataSet = new DataSet();
        
        table.Columns.Add("Vorname", typeof(string));
        table.Columns.Add("Nachname", typeof(string));
        table.Columns.Add("Geburtsort", typeof (string));
        
        
//Datenzeile einfügen
        DataRow dr = table.NewRow();
        
        //Bin mir nicht sicher ob, der nachfolgende Programmcode so richtig ist???
        dr[0] = newtemp;
        .
           .     
        .

    }
    catch
    {
        MessageBox.Show("Es ist ein Fehler aufgetreten!");
    }
    .
    .
    .
}

Wie füge ich die Daten nun aus dem Datatable in das DataGrid ein?  Ich bin auf den nachfolgenden Ansatz gestoßen, der jedoch nicht funktioniert:

NameDesDataGrid.DataSource = table;

Zuvor habe ich die Daten aus dem Array immer  per NamesDesDataGrid.Items.Add(newtemp); statisch eingefügt.

Wie kann ich mir des Weiteren anzeigen lassen, welche Daten im DataTable stehen bzw. wo werden diese im Bereich des Lokalfenster hinterlegt?

Gruß

Timm

A
763 Beiträge seit 2007
vor 4 Monaten

Hallo Timm2023

Bei WPF benutzt du am besten das MVVM-Pattern:

https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding

https://www.c-sharpcorner.com/UploadFile/ptmujeeb/wpf-mvvm-pattern-a-simple-tutorial-for-absolute-beginners/

DataSet und DataTable brauchst du gar nicht.

Für die Mitarbeiter aus der Datenbank machst du dir in dein ViewModel eine ObservableCollection:

public ObservableCollection<Mitarbeiter> AllMitarbeiter { get; set; }

Im View kannst du daran binden:

<DataGrid DockPanel.Dock="Top" ItemsSource="{Binding AllMitarbeiter}" />

Les dich ein und fang damit an. Damit solltest du soweit kommen, dass die Mitarbeiter angezeigt werden. Für das Speichern kommst du dann mit deinem neuen MVVM-Ansatz wieder.

Gruss
Alf

T
Timm2023 Themenstarter:in
9 Beiträge seit 2023
vor 4 Monaten
DataGrid / Dateneingabe in MS SQL Datenbank speichern

Hallo Alf,

danke für deine Hilfestellung. Das MVVM Pattern nutze ich bereits, um die Daten aus der Datenbank im DataGrid darzustellen. Das klappt auch soweit.

Nun dachte ich, dass ich zum Speichern Datatable/Dataset benötige.

Aber anscheinend geht es mit dem MVVM Pattern. Könntest du mir hier nochmal Hilfestellung geben?

Gruß

Timm

A
763 Beiträge seit 2007
vor 4 Monaten

Guten Morgen

Ich nehme mal an, dass auf Knopfdruck gespeichert werden soll.

Statt dem ClickEvent kannst du das Command-Pattern verwenden.

Dafür bindest du ein Command an dein ViewModel:

<Button Content="Mitarbeiter speichern" Command="{Binding SaveCommand}" CommandParameter="{Binding AllMitarbeiter}" />
public RelayCommand<ObservableCollection<MitarbeiterViewModel>> SaveCommand { get; private set; }

Im Konstruktor vom ViewModel kann der Command instantiiert werden:

public MitarbeiterOverviewViewModel(MitarbeiterService mitarbeiterService)
{
    this.mitarbeiterService = mitarbeiterService;
    SaveCommand = new RelayCommand<ObservableCollection<MitarbeiterViewModel>>(SaveAll, CanSaveAll);
}

Eine Implementierung für RelayCommand gibt es hier: https://www.c-sharpcorner.com/UploadFile/20c06b/icommand-and-relaycommand-in-wpf/

Die Methode SaveAll, die vom Command aufgerufen wird, bekommt als Parameter die Liste mit den Mitarbeitern.

private void SaveAll(ObservableCollection<MitarbeiterViewModel>? allMitarbeiterViewModel)
{
    if (allMitarbeiterViewModel == null) return;
    var allMitarbeiter = allMitarbeiterViewModel.Select(ToMitarbeiter);
    mitarbeiterService.SaveAll(allMitarbeiter);
}

Beachte hier, dass ich in meinem Beispiel-Projekt nicht das Model Mitarbeiter direkt im UI verwende, sondern ein MitarbeiterViewModel. Beim Landen und Speichern wird jeweils übersetzt. (Beachte, dass deine ViewModels INotifyPropertyChanged implementieren.)

private Mitarbeiter ToMitarbeiter(MitarbeiterViewModel viewModel)
{
    return new Mitarbeiter(viewModel.Vorname, viewModel.Nachname, viewModel.Geburtsort);
}

Der MitarbeiterService hält ein MitarbeiterRepository, über das die Kommunikation mit der Datenbank stattfindet.
Statt über den MitarbeiterService kann das MitarbeiterRepository auch direkt im ViewModel verwendet werden.

Wichtig ist, dass ab hier die UI von der Datenbank und Logik-Schicht getrennt ist: https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur

Den UI-Kram kannst du schonmal ausprobieren. Ziel ist, dass auf Knopfdruck SaveAll mit deinen Mitarbeitern aufgerufen wird. Meine Implementierung im MitarbeiterService:

internal void SaveAll(IEnumerable<Mitarbeiter> allMitarbeiter)
{
    foreach (var mitarbeiter in allMitarbeiter)
        Debug.WriteLine(mitarbeiter);
}

Wenn das funktioniert, kann das Repository implementiert werden. Bei konkreten Fragen meldest du dich wieder hier.

Gruss
Alf

T
Timm2023 Themenstarter:in
9 Beiträge seit 2023
vor 4 Monaten
DataGrid / Dateneingabe in MS SQL Datenbank speichern

Hallo Alf,

ganz herzlichen Dank für deine ausführliche Hilfestellung. Versuche mich jetzt daran. Eine Rückmeldung erfolgt bzw. bin ich mir sicher, dass ich noch die eine oder andere Verständnisfrage haben werden.

Wünsche Dir einen schönen Feiertag.

Gruß

Timm

T
Timm2023 Themenstarter:in
9 Beiträge seit 2023
vor 3 Monaten
DataGrid / Dateneingabe in MS SQL Datenbank speichern

Guten Abend Alf,

habe die letzten Tag versucht mein Vorhaben, mit deiner Hilfestellung, umzusetzen.

Die folgenden Klassen habe ich angelegt:

  1. Mitarbeiter
  2. ViewModel
  3. DelegateCommand

Dann habe ich noch

4. MainWindow (Model)

5. meine View (XAML)

Die Mitarbeiternr. wird nun in eine Textbox eingegeben und durch einen OK_Button erfolgt das Auslesen der Datensätze aus der Datenbank. Diese werden dann in der ObservableCollection abgelegt.  Aktuell noch mit dem Ereignis Button_click.

public class DelegateCommand : ICommand
{
    readonly Action<object> execute;
    readonly Predicate<object> canExecute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Predicate<object> canExecute, Action<object> execute) =>
        (this.canExecute, this.execute) = (canExecute, execute);

    public DelegateCommand(Action<object> execute) : this(null, execute) { }

    public void RaiseCanExecuteChanged() => this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);


    public bool CanExecute(object parameter) => this.canExecute?.Invoke(parameter) ?? true;


    public void Execute(object parameter) => this.execute?.Invoke(parameter);

}

Beim DelegateCommand ist mir nicht klar warum als parameter "null" übermittelt wird. Nach meinem Verständnis kann ein Button doch nur geklickt also True oder nicht geklickt False liefern.

Des Weiteren weiß ich nicht wie ich den Konstruktor des DelegateCommand füllen muss, damit dieser dann das Auslesen aus der Datenbank durchführt.

Hier mein Ansatz:

internal class MainViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string firstname;
    string lastname;
    string geburtsort;
    
    
public DelegateCommand Load_Data { get; set; }

    public MainViewModel()
    {
    //Wie muss der Konstruktor gefüllt werden???
        this.Load_data = new DelegateCommand();

    }

    public string Firstname
    {
        get => firstname;

        set
        {
            if (firstname != value)
            {
                firstname = value;
                this.RaisePropertyChanged();
               
            }
        }
    }
    .
    .
    .
    
    

    

    private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (!string.IsNullOrEmpty(propertyName))
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }

Auch ist mir nicht ganz klar, wo der nachfolgende Programmcode hingehört:

private void Btn_GO_Click(object sender, RoutedEventArgs e)
{
    SqlConnection connection = new SqlConnection("Data Source=TIMM\\TESTSQL;initial Catalog = Company_Test;Integrated Security=True");
    connection.Open();

    try
    {
        string result_txt = txtMitarbeiternr.Text;
        MessageBox.Show(result_txt);
        int lfdNr = Convert.ToInt32(result_txt);

        String[] Daten1 = new String[3];
        String a = "";
        String b = "";
        String c = "";
        

        ObservableCollection<Mitarbeiter> AllMitarbeiter = new ObservableCollection<Mitarbeiter>();
        for (int lfdNr = 1; lfdNr <= 3; lfdNr++)
        {
            //SqlCommand 
          
            a += reader["Vorname"].ToString();
            b += reader["Nachname"].ToString();
            c += reader["Geburtsort"].ToString();

            Daten1[0] = a;
            Daten1[1] = b;
            Daten1[2] = c;

            Mitarbeiter newtemp = new Mitarbeiter(a, b, c);

            a = "";
            b = "";
            c = "";

            AllMitarbeiter.Add(newtemp);


        }

        DataGrid1.Items.Add(AllMitarbeiter[0]);
        DataGrid1.Items.Add(AllMitarbeiter[1]);
        DataGrid1.Items.Add(AllMitarbeiter[2]);


        
    }
    catch
    {
        MessageBox.Show("Es ist ein Fehler aufgetreten!");
    }

Habe mir anscheinend ein komplexes Thema ausgesucht, für meine ersten Gehversuche im Bereich MVVM Pattern.

Gruß

Timm

16.788 Beiträge seit 2008
vor 3 Monaten

Du erstellst Zeug, Commands wie Collections im CodeBehind.
Das ist genau das, was man bei MVVM nicht tun sollte.

Und nein - eigentlich ist das super simpel; wenn man die Ideen von MVVM umsetzt.
Das Problem ist: MVVM ist ein konzeptioneller Pattern, das heisst mit Try-Error / ausprobieren kommst leider nicht weit.
Daher gilt MVVM auch als ein Pattern, der eine Lernhürde hat, weil Du wirklich so eine Doc und die Regeln von MVVM beachten und anwenden musst.

A
763 Beiträge seit 2007
vor 3 Monaten

Hallo Timm

Das MainViewModel braucht noch ein Property für die Mitarbeiter-Liste:

public ObservableCollection<MitarbeiterViewModel> AllMitarbeiter { get; } = new();

Im View wird das DataGrid daran gebunden:

<DataGrid ItemsSource="{Binding AllMitarbeiter}" />

Ausserdem wird der Load-Button an den DelegateCommand gebunden:

<Button Content="Load Mitarbeiter" Command="{Binding LoadCommand}" CommandParameter="{Binding}" />

Der CommandParameter ist der DataContext, also das MainViewModel.

Des Weiteren weiß ich nicht wie ich den Konstruktor des DelegateCommand füllen muss, damit dieser dann das Auslesen aus der Datenbank durchführt.

Der execute-Parameter beim DelegateCommand ist die Methode, die beim Button-Click ausgeführt wird.

public MainViewModel()
{
    // Load_data → LoadCommand
    this.LoadCommand = new DelegateCommand((vm) => LoadData(vm));
}

...

private void LoadData(object boxedMainViewModel)
{
    var mainViewModel = boxedMainViewModel as MainViewModel;
    mainViewModel.LoadAllMitarbeiter();
}

...

private void LoadAllMitarbeiter()
{
    this.AllMitarbeiter.Clear();

    foreach (var mitarbeiter in this.mitarbeiterService.GetAll())
    {
        this.AllMitarbeiter.Add(mitarbeiter);
    }
}

In  this.mitarbeiterService.GetAll()werden die Daten aus der Datenbank geladen.

Zum Testen reicht da auch sowas:

internal IEnumerable<Mitarbeiter> GetAll()
{
    yield return new Mitarbeiter("Guybrush", "Threepwood", "Monkey Island");
    yield return new Mitarbeiter("Elaine", "Marley", "Melee Island");
}

Beim DelegateCommand ist mir nicht klar warum als parameter "null" übermittelt wird. Nach meinem Verständnis kann ein Button doch nur geklickt also True oder nicht geklickt False liefern.

Der canExecute-Parameter zeigt nicht an, ob der Button gedrückt wurde, sondern ob er gedrückt werden darf. Wenn nein, dann wird er in der UI deaktiviert angezeigt. Den kannst du erstmal ignorieren.

Auch ist mir nicht ganz klar, wo der nachfolgende Programmcode hingehört:

    SqlConnection connection = new SqlConnection("Data Source=TIMM\\TESTSQL;initial Catalog = Company_Test;Integrated Security=True");
    connection.Open();

In den MitarbeiterService, bzw. noch besser in das MitarbeiterRepository, dass vom MitarbeiterService benutzt wird (https://dotnettutorials.net/lesson/repository-design-pattern-csharp/).

Der Rest kann weg.

Habe mir anscheinend ein komplexes Thema ausgesucht, für meine ersten Gehversuche im Bereich MVVM Pattern.

Ja, der Einstieg ist nicht ganz einfach. Die Mühe lohnt sich aber, zum einen für stabilere Programme, zum anderen entwickelt es das eigene Programmier-Verständnis ungemein.

Gruss
Alf

PS: Es folgt noch ein zweiter Beitrag mit ein paar Anmerkungen.

4.921 Beiträge seit 2008
vor 3 Monaten

Hallo Timm,

schau dir am besten mal ein einfaches WPF MVVM-Datenbankprojekt an, wie z.B.

  • WPF MVVM Practical Data Application (den Code dazu - dies steht nur in einem der Kommentare - gibt es unter vikramvee/MVVMApplication)
    Hier wird außerdem noch direkt das Entitiy Framework als ORM verwendet, aber dies ist nur eine weitere Abstraktion gegenüber einem selbstprogrammierten ADO.NET Zugriff.
  • Movie-Catalog-A Simple MVVM based WPF application with SQL Database
    Leider verwendet dieses Projekt kein ICommand, sondern auch im Codebehind ButtonClick- aber dafür verwendet es verschiedene Datenbankoperationen sowie zum Datenbankzugriff ein Repository (s.u.).
  • Using WPF MVVM for Database Access
    Sehr detailliert erklärt, aber dafür benötigt man auch mehr Englischkenntnisse - es verwendet sowohl RelayCommand als ICommand-Implementierung als auch verschiedene Views und ViewModels. Zum Datenbankzugriff jedoch verwendet es das veraltete LinqToSQL sowie direkte Datenbankprozeduren - dies kann man aber selbstverständlich durch ein anderes ORM ersetzen.

Bzgl. deiner Fragen:

Beim DelegateCommand ist mir nicht klar warum als parameter "null" übermittelt wird. Nach meinem Verständnis kann ein Button doch nur geklickt also True oder nicht geklickt False liefern.

Meinst du beim Konstruktor public DelegateCommand(Action<object> execute) : this(null, execute) { }?  Dies ist der Parameter canExecute, welcher angibt, ob das UI-Element (hier Button) aktiviert ist oder nicht (d.h. ausgegraut). Bei Angabe von null ist dieser immer aktiv (s. Implementierung von CanExecute).

Auch ist mir nicht ganz klar, wo der nachfolgende Programmcode hingehört:

Die gesamte Funktionalität der Methode Btn_GO_Click wird aufgeteilt auf verschiedene Methoden (in unterschiedlichen Schichten/Klassen):

  • Im ViewModel wird dem DelegateCommand eine Methode als Parameter execute übergeben, welche dann in dessen Execute-Methode automatisch ausgeführt wird.
  • In dieser übergebenen Methode sollte dann eine Methode aus der Geschäftslogikschicht (Model) aufgerufen werden, welche wiederum eine Methode aus der Datenzugriffsschicht aufruft (für letzteres sind die Stichworte "Repository" und "UnitOfWork" wichtig).
T
Timm2023 Themenstarter:in
9 Beiträge seit 2023
vor 3 Monaten
DataGrid / Dateneingabe in MS SQL Datenbank speichern

Hallo Alf, hallo th69,

zunächst einmal vielen Dank für eure Hilfestellung. Ich dachte canExecute kann nur true oder false sein. Diese Annahme war also falsch. CanExecute kann also true, false und Null sein.

Grundsätzliche habe ich verstanden wie das MVVM pattern funktioniert und auch die Vorteile, die es einem eröffnet.

Wo ich bis jetzt noch Schwierigkeiten habe ist einzuordnen wo nun welcher Programmcode hingehört und was einzelne Programmteile bewirken.

Wie das Binding zwischen View und ViewModel funktioniert habe ich verstanden.

Nachfolgend nochmal der vollständige Programmcode indem ihr meine Fragen jeweils im Programmcode findet:

 <Grid>
     <Button x:Name="btn_speichern" Content="Datensatz speichern" HorizontalAlignment="Left" Margin="25,350,0,0" VerticalAlignment="Top" Height="48" 		 Width="150" />

     <DataGrid x:Name="DataGrid1"  Margin="25,100,25,100" AlternatingRowBackground="Aqua" AutoGenerateColumns="false" VerticalGridLinesBrush="#FFF8F4F4" HorizontalGridLinesBrush="#FFFAF7F7">
         <DataGrid.Columns>
             <DataGridTextColumn Header = "Vorname" Binding ="{Binding Vorname}" Width="100" />
             <DataGridTextColumn Header = "Nachname" Binding ="{Binding Nachname}" Width="100" />
             <DataGridTextColumn Header = "Geburtsort" Binding ="{Binding Geburtsort}" Width="*" />
         </DataGrid.Columns>
     </DataGrid>
     <TextBox x:Name="txtMitarbeiternr" HorizontalAlignment="Left" Height="22" Margin="150,65,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="133" />
     <Label Content="Mitarbeiternr" HorizontalAlignment="Left" Height="30" Margin="25,60,0,0" VerticalAlignment="Top" Width="100" FontSize="16" FontWeight="Bold"/>
     <Button x:Name="Btn_OK" Content="OK" HorizontalAlignment="Left" Margin="325,65,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.1,-0.564" Width="124"  />
 </Grid>
 internal class MainViewModel : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler PropertyChanged;
	// Deine Verson mit new (); ist erst ab Sprachversion C#9 oder höher verfügbar
	// Ich nutze die Community Version Visual Studio 2022; keine ausstehenden Updates; ist die Sprachversion bei mir verfügbar?
	
     public ObservableCollection<MitarbeiterViewModel> AllMitarbeiter { get; } = new ObservableCollection<MitarbeiterViewModel>();

     string firstname;
     string lastname;
     string geburtsort;

     public DelegateCommand LoadCommand { get; set; }

     public MainViewModel()
     {
     	//Button wurde gedrückt DelegateCommand wird ausgeführt; Warum muss ein neues Object vm erzeugt werden???
         this.LoadCommand = new DelegateCommand((vm) => LoadData(vm));

     }

     private void LoadData(object boxedMainViewModel)
     {
     	//Welche Daten soll das object boxedMainViewModel aufnehmen
         var mainViewModel = boxedMainViewModel as MainViewModel;
         mainViewModel.LoadAllMitarbeiter();
     }

     private void LoadAllMitarbeiter()
     {
         this.AllMitarbeiter.Clear();

         foreach (var mitarbeiter in this.mitarbeiterService.GetAll())
         {
             this.AllMitarbeiter.Add(mitarbeiter);
         }
     }
     
	//Den Part verstehe ich nicht, wozu dient der Mitarbeiterservice?
	

     public MitarbeiterOverviewViewModel(MitarbeiterService mitarbeiterService)
     {
        this.mitarbeiterService = mitarbeiterService;
        SqlConnection connection = new SqlConnection("Data Source=....;initial Catalog = Company_Test;Integrated Security=True");
		connection.Open();
         /// Wenn ich es richtig verstanden habe, benötige ich alles was hiernach kommt, sprich das try & catch nicht mehr.
         /// Die Datenbankverbindung stelle ich zukünftig über die neue Klasse ADO.Net Entity Data Model her??? Aber warum brauche ich dann noch die 		
         /// SQL connection???
          try
 		{

     		string result_txt = txtMitarbeiternr.Text;
     		MessageBox.Show(result_txt);
     		int lfdNr = Convert.ToInt32(result_txt);

	
     		String[] Daten1 = new String[3];
     		String a = "";
     		String b = "";
     		String c = "";

     

     		ObservableCollection<Mitarbeiter> AllMitarbeiter = new ObservableCollection<Mitarbeiter>();
     		for (int lfdNr = 1; lfdNr <= 3; lfdNr++)
     		{
         		SqlCommand command = new SqlCommand("use Company_Test select * from Mitarbeiter Where [Mitarbeiternr] = " + (lfdNr), connection);
         		SqlDataReader reader = null;
         		reader = command.ExecuteReader();
         		reader.Read();

		
         		a += reader["Vorname"].ToString();
         		b += reader["Nachname"].ToString();
         		c += reader["Geburtsort"].ToString();

		
         		Daten1[0] = a;
         		Daten1[1] = b;
         		Daten1[2] = c;

		
         		Mitarbeiter newtemp = new Mitarbeiter(a, b, c);

		
         		a = "";
         		b = "";
         		c = "";

		
         		AllMitarbeiter.Add(newtemp);
     		}

		
     		DataGrid1.Items.Add(AllMitarbeiter[0]);
     		DataGrid1.Items.Add(AllMitarbeiter[1]);
     		DataGrid1.Items.Add(AllMitarbeiter[2]);
 		}
 		catch
 		{
     		MessageBox.Show("Es ist ein Fehler aufgetreten!");
 		}
         


     }
     
     public string Firstname
     {
         get => firstname;

         set
         {
             if (firstname != value)
             {
                 firstname = value;
                 this.RaisePropertyChanged();
             }
         }
     }

 	... //

     private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
     {
         if (!string.IsNullOrEmpty(propertyName))
         {
             this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
         }

     }
     
 }

Mein MainWindow (Model) sieht zurzeit wie folgt aus:

namespace ....
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }           
    }
} 

Nach meinem derzeitigen Verständnis wird das Button-Click Event durch ein Command-Binding ersetzt. Dazu wird der OK-Button per Datenbindung mit dem ViewModel verbunden. Das ViewModel enthält die Logik, was mit dem View passieren soll wenn z.B. ein Button geklickt wird, eine Änderung etc. erfolgt.

Wird nun der OK-Button geklickt erzeugt es einen neuen DelegateCommand, dieser wiederum ruft die Methode LoadData auf usw..

Ich hoffe, dass es bis hierhin richtig verstanden und wiedergegeben habe. Ich glaube es wäre für mich sehr hilfreich wenn wir Schritt für Schritt vorgehen.

Ich habe die letzten Tage soviel gelesen, dass ich den Wald vor lauter Bäume nicht mehr sehe.

Gruß

Timm

125 Beiträge seit 2023
vor 3 Monaten

Ich habe deinen Code mal nur so überflogen allerdings sehe ich ich fast überall wo ich hinschaue Fehler, das es mir zu viele sind als jetzt auf jeden einzugehen.

Schau dir doch einfach mal in Ruhe die Beispiele an die du genannt bekommen hast und versuche mit denen zu arbeiten und vor allem das Konzept MVVM zu verstehen.

Hat die Blume einen Knick, war der Schmetterling zu dick.

A
763 Beiträge seit 2007
vor 3 Monaten

Hallo Timm

CanExecute kann also true, false und Null sein.

CanExecure ist eine Art Methode, die true oder false zurück gibt. Kann bei deiner ICommand-Implementierung aber auch null sein, dann wird also keine Methode übergeben und CanExecute gibt dann immer true zurück.

     <Button x:Name="btn_speichern" Content="Datensatz speichern" HorizontalAlignment="Left" Margin="25,350,0,0" VerticalAlignment="Top" Height="48" 		 Width="150" />

     <DataGrid x:Name="DataGrid1"  Margin="25,100,25,100" AlternatingRowBackground="Aqua" AutoGenerateColumns="false" VerticalGridLinesBrush="#FFF8F4F4" HorizontalGridLinesBrush="#FFFAF7F7">
     ...
     </DataGrid>
     ...
     <Button x:Name="Btn_OK" Content="OK" HorizontalAlignment="Left" Margin="325,65,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.1,-0.564" Width="124"  />

Im Xaml-Code fehlen die Bindings. Beim Button das Command-Binding und beim DataGrid das ItemsSource-Binding.

    // Deine Verson mit new (); ist erst ab Sprachversion C#9 oder höher verfügbar
    // Ich nutze die Community Version Visual Studio 2022; keine ausstehenden Updates; ist die Sprachversion bei mir verfügbar?
    

Die C#-Version hängt mit der .NET-Version zusammen, die im Projekt eingestellt ist.

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version

         //Button wurde gedrückt DelegateCommand wird ausgeführt; Warum muss ein neues Object vm erzeugt werden???
         this.LoadCommand = new DelegateCommand((vm) => LoadData(vm));

'vm' ist in diesem Fall das ViewModel, dass vom Command (per CommandParameter-Binding) übergeben wird. Es wird also kein neues Objekt erzeugt.

Das beantwortet auch die Frage:

         //Welche Daten soll das object boxedMainViewModel aufnehmen
     private void LoadAllMitarbeiter()
     {
         this.AllMitarbeiter.Clear();

         foreach (var mitarbeiter in this.mitarbeiterService.GetAll())
         {
             this.AllMitarbeiter.Add(mitarbeiter);
         }
     }
     
    //Den Part verstehe ich nicht, wozu dient der Mitarbeiterservice?

     public MitarbeiterOverviewViewModel(MitarbeiterService mitarbeiterService)
     {
        this.mitarbeiterService = mitarbeiterService;

Der MitarbeiterService stellt die Verbindung zur Geschäftslogik her, von dort kommen die Mitarbeiter-Daten und da gehen sie wieder hin, wenn sie gespeichert werden sollen. Alles was mit Datenbank zu tun hat, wird dahinter versteckt und hat in der UI nichts mehr zu suchen. 
Schau dir dafür das hier an: https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur

        SqlConnection connection = new SqlConnection("Data Source=....;initial Catalog = Company_Test;Integrated Security=True");
        connection.Open();

         /// Die Datenbankverbindung stelle ich zukünftig über die neue Klasse ADO.Net Entity Data Model her??? Aber warum brauche ich dann noch die 		
         /// SQL connection???

Kein Plan wo die Daten aktuell herkommen. Für die UI ist das auch nicht wichtig. Wie ich schon geschrieben hatte, muss der Datenbank-Kram aus der UI raus und hinter den MitarbeiterService.

Mein MainWindow (Model) sieht zurzeit wie folgt aus:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }           
    }

Wo wird das ViewModel dem DataSource vom Window zugewiesen?

Nach meinem derzeitigen Verständnis wird das Button-Click Event durch ein Command-Binding ersetzt. check
Dazu wird der OK-Button per Datenbindung mit dem ViewModel verbunden. check
Das ViewModel enthält die Logik, was mit dem View passieren soll wenn z.B. ein Button geklickt wird, eine Änderung etc. erfolgt. check

Wird nun der OK-Button geklickt erzeugt es einen neuen DelegateCommand, dieser wiederum ruft die Methode LoadData auf usw..

Der DelegateCommand wird schon im Konstuktor vom ViewModel erzeugt und enthält eine Verknüpfung auf die LoadData-Methode.

Ich hoffe, dass es bis hierhin richtig verstanden und wiedergegeben habe. Ich glaube es wäre für mich sehr hilfreich wenn wir Schritt für Schritt vorgehen.

Ich habe die letzten Tage soviel gelesen, dass ich den Wald vor lauter Bäume nicht mehr sehe.

Es wäre ja langweilig, wenn es einfach wäre. 😃