Erste Schritte mit Windows Forms

Diese Schrittanleitung zeigt Ihnen, wie Sie eine einfache Windows Forms-Anwendung (WinForms) erstellen, die durch eine SQLite-Datenbank gestützt wird. Die Anwendung verwendet Entity Framework Core (EF Core), um Daten aus der Datenbank zu laden, an diesen Daten vorgenommene Änderungen nachzuverfolgen und diese Änderungen wieder in der Datenbank zu speichern.

Die Screenshots und Codelistings in dieser exemplarischen Vorgehensweise stammen aus Visual Studio 2022 17.3.0.

Tipp

Das in diesem Artikel verwendete Beispiel finden Sie auf GitHub.

Voraussetzungen

Um diese exemplarische Vorgehensweise nachvollziehen zu können, müssen Sie Visual Studio 2022 17.3 oder höher mit ausgewählter .NET-Desktopworkload installiert haben. Weitere Informationen zur Installation der neuesten Version von Visual Studio finden Sie unter Installieren von Visual Studio.

Erstellen der Anwendung

  1. Öffnen Sie Visual Studio.

  2. Wählen Sie im Startfenster Neues Projekt erstellen aus.

  3. Wählen Sie Windows Forms-App und dann Weiter aus.

    Create a new Windows Forms project

  4. Vergeben Sie auf dem nächsten Bildschirm einen Namen für das Projekt (z. B. GetStartedWinForms), und wählen Sie Weiter aus.

  5. Wählen Sie auf dem nächsten Bildschirm die .NET-Version aus, die verwendet werden soll. Diese exemplarische Vorgehensweise wurde mit .NET 7 erstellt, sollte aber auch mit späteren Versionen funktionieren.

  6. Wählen Sie Erstellen aus.

Installieren der EF Core-NuGet-Pakete

  1. Klicken Sie mit der rechten Maustaste auf die Projektmappe, und wählen Sie NuGet-Pakete für Projektmappe verwalten aus.

    Manage NuGet Packages for Solution

  2. Wählen Sie die Registerkarte Durchsuchen aus, und suchen Sie nach „Microsoft.EntityFrameworkCore.Sqlite“.

  3. Wählen Sie das Paket Microsoft.EntityFrameworkCore.Sqlite aus.

  4. Aktivieren Sie das Projekt GetStartedWinForms im rechten Bereich.

  5. Wählen Sie die neueste Version aus. Um eine Vorabversion zu verwenden, stellen Sie sicher, dass das Kontrollkästchen Vorabversion einschließen aktiviert ist.

  6. Klicken Sie auf Install (Installieren).

    Install the Microsoft.EntityFrameworkCore.Sqlite package

Hinweis

Microsoft.EntityFrameworkCore.Sqlite ist das Datenbankanbieterpaket für die Verwendung von EF Core mit einer SQLite-Datenbank. Ähnliche Pakete sind für andere Datenbanksysteme verfügbar. Durch die Installation eines Datenbankanbieterpakets werden automatisch alle Abhängigkeiten bereitgestellt, die für die Verwendung von EF Core mit dem zugehörigen Datenbanksystem erforderlich sind. Dies schließt das Microsoft.EntityFrameworkCore-Basispaket ein.

Definieren eines Modells

In dieser exemplarischen Vorgehensweise implementieren Sie ein Modell mit „Code First“. Dies bedeutet, dass EF Core die Datenbanktabellen und das Schema basierend auf den von Ihnen definierten C#-Klassen erstellt. Wenn Sie stattdessen eine vorhandene Datenbank verwenden möchten, finden Sie entsprechende Informationen unter Verwalten von Datenbankschemas.

  1. Klicken Sie mit der rechten Maustaste auf das Projekt, und wählen Sie Hinzufügen und dann Klasse... aus, um eine neue Klasse hinzuzufügen.

    Add new class

  2. Verwenden Sie den Dateinamen Product.cs, und ersetzen Sie den Code für die Klasse durch Folgendes:

    using System.ComponentModel;
    
    namespace GetStartedWinForms;
    
    public class Product
    {
        public int ProductId { get; set; }
    
        public string? Name { get; set; }
    
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; } = null!;
    }
    
  3. Wiederholen Sie diesen Vorgang mit dem folgenden Code, um Category.cs zu erstellen:

    using Microsoft.EntityFrameworkCore.ChangeTracking;
    
    namespace GetStartedWinForms;
    
    public class Category
    {
        public int CategoryId { get; set; }
    
        public string? Name { get; set; }
    
        public virtual ObservableCollectionListSource<Product> Products { get; } = new();
    }
    

Die Products-Eigenschaft in der Category-Klasse und die Category-Eigenschaft in der Product--Klasse werden als „Navigationselemente“ bezeichnet. In EF Core definieren Navigationselemente eine Beziehung zwischen zwei Entitätstypen. In diesem Fall verweist das Navigationselement Product.Category auf die Kategorie, zu der ein bestimmtes Produkt gehört. Das Navigationselement der Category.Products-Sammlung enthält alle Produkte für eine bestimmte Kategorie.

Tipp

Beim Verwenden von Windows Forms kann das ObservableCollectionListSource-Element, das IListSource implementiert, für Sammlungsnavigationselemente verwendet werden. Dies ist nicht zwingend erforderlich, verbessert aber die bidirektionale Datenbindung.

Definieren von DbContext

In EF Core wird eine von DbContext abgeleitete Klasse verwendet, um Entitätstypen in einem Modell zu konfigurieren und um als Sitzung für die Interaktion mit der Datenbank zu fungieren. Im einfachsten Fall handelt es sich um eine DbContext-Klasse:

  • Enthält DbSet-Eigenschaften für jeden Entitätstyp im Modell.
  • Überschreibt die OnConfiguring-Methode zum Konfigurieren des zu verwendenden Datenbankanbieters und der zu verwendenden Verbindungszeichenfolge. Weitere Informationen finden Sie unter Konfigurieren von DbContext.

In diesem Fall überschreibt die DbContext-Klasse auch die OnModelCreating-Methode, um einige Beispieldaten für die Anwendung bereitzustellen.

Fügen Sie dem Projekt mit dem folgenden Code eine neue ProductsContext.cs-Klasse hinzu:

using Microsoft.EntityFrameworkCore;

namespace GetStartedWinForms;

public class ProductsContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlite("Data Source=products.db");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Category>().HasData(
            new Category { CategoryId = 1, Name = "Cheese" },
            new Category { CategoryId = 2, Name = "Meat" },
            new Category { CategoryId = 3, Name = "Fish" },
            new Category { CategoryId = 4, Name = "Bread" });

        modelBuilder.Entity<Product>().HasData(
            new Product { ProductId = 1, CategoryId = 1, Name = "Cheddar" },
            new Product { ProductId = 2, CategoryId = 1, Name = "Brie" },
            new Product { ProductId = 3, CategoryId = 1, Name = "Stilton" },
            new Product { ProductId = 4, CategoryId = 1, Name = "Cheshire" },
            new Product { ProductId = 5, CategoryId = 1, Name = "Swiss" },
            new Product { ProductId = 6, CategoryId = 1, Name = "Gruyere" },
            new Product { ProductId = 7, CategoryId = 1, Name = "Colby" },
            new Product { ProductId = 8, CategoryId = 1, Name = "Mozzela" },
            new Product { ProductId = 9, CategoryId = 1, Name = "Ricotta" },
            new Product { ProductId = 10, CategoryId = 1, Name = "Parmesan" },
            new Product { ProductId = 11, CategoryId = 2, Name = "Ham" },
            new Product { ProductId = 12, CategoryId = 2, Name = "Beef" },
            new Product { ProductId = 13, CategoryId = 2, Name = "Chicken" },
            new Product { ProductId = 14, CategoryId = 2, Name = "Turkey" },
            new Product { ProductId = 15, CategoryId = 2, Name = "Prosciutto" },
            new Product { ProductId = 16, CategoryId = 2, Name = "Bacon" },
            new Product { ProductId = 17, CategoryId = 2, Name = "Mutton" },
            new Product { ProductId = 18, CategoryId = 2, Name = "Pastrami" },
            new Product { ProductId = 19, CategoryId = 2, Name = "Hazlet" },
            new Product { ProductId = 20, CategoryId = 2, Name = "Salami" },
            new Product { ProductId = 21, CategoryId = 3, Name = "Salmon" },
            new Product { ProductId = 22, CategoryId = 3, Name = "Tuna" },
            new Product { ProductId = 23, CategoryId = 3, Name = "Mackerel" },
            new Product { ProductId = 24, CategoryId = 4, Name = "Rye" },
            new Product { ProductId = 25, CategoryId = 4, Name = "Wheat" },
            new Product { ProductId = 26, CategoryId = 4, Name = "Brioche" },
            new Product { ProductId = 27, CategoryId = 4, Name = "Naan" },
            new Product { ProductId = 28, CategoryId = 4, Name = "Focaccia" },
            new Product { ProductId = 29, CategoryId = 4, Name = "Malted" },
            new Product { ProductId = 30, CategoryId = 4, Name = "Sourdough" },
            new Product { ProductId = 31, CategoryId = 4, Name = "Corn" },
            new Product { ProductId = 32, CategoryId = 4, Name = "White" },
            new Product { ProductId = 33, CategoryId = 4, Name = "Soda" });
    }
}

Zu diesem Zeitpunkt müssen Sie die Lösung kompilieren.

Hinzufügen von Steuerelementen zum Formular

Die Anwendung zeigt eine Liste der Kategorien und eine Liste der Produkte an. Wenn in der ersten Liste eine Kategorie ausgewählt wird, ändert sich die zweite Liste und zeigt Produkte für diese Kategorie an. Diese Listen können geändert werden, um Produkte und Kategorien hinzuzufügen, zu entfernen oder zu bearbeiten. Sie können diese Änderungen in der SQLite-Datenbank speichern, indem Sie auf die Schaltfläche Speichern klicken.

  1. Ändern Sie den Namen des Hauptformulars von Form1 zu MainForm.

    Rename Form1 to MainForm

  2. Ändern Sie auch den Titel zu „Produkte und Kategorien“.

    Title MainForm as

  3. Fügen Sie mithilfe der Toolbox zwei nebeneinander angeordnete DataGridView-Steuerelemente hinzu.

    Add DataGridView

  4. Ändern Sie in den Eigenschaften für die erste DataGridView den Namen zu dataGridViewCategories.

  5. Ändern Sie in den Eigenschaften für die zweite DataGridView den Namen zu dataGridViewProducts.

  6. Fügen Sie, ebenfalls mithilfe der Toolbox, ein Button-Steuerelement hinzu.

  7. Benennen Sie die Schaltfläche buttonSave, und geben Sie als Text „Speichern“ ein. Das Formular sollte in etwa so aussehen:

    Form layout

Datenbindung

Der nächste Schritt besteht darin, die Typen Product und Category aus dem Modell mit den DataGridView-Steuerelementen zu verbinden. Dadurch werden die von EF Core geladenen Daten an die Steuerelemente gebunden, sodass die von EF Core nachverfolgten Entitäten mit den in den Steuerelementen angezeigten Entitäten synchronisiert werden.

  1. Klicken Sie im ersten DataGridView-Element auf die Designer-Aktionsglyphe. Dies ist die kleine Schaltfläche in der oberen rechten Ecke des Steuerelements.

    The Designer Action Glyph

  2. Dadurch wird die Aktionsliste geöffnet, von der aus auf die Dropdownliste für Datenquelle auswählen zugegriffen werden kann. Wir haben noch keine Datenquelle erstellt. Wählen Sie also unten in der Dropdownliste die Option Neue Objektdatenquelle hinzufügen... aus.

    Add new Object Data Source

  3. Wählen Sie Kategorie aus, um eine Objektdatenquelle für Kategorien zu erstellen, und klicken Sie auf OK.

    Choose Category data source type

    Tipp

    Wenn hier keine Datenquellentypen angezeigt werden, stellen Sie sicher, dass Product.cs, Category.cs und ProductsContext.cs dem Projekt hinzugefügt wurden und dass die Lösung kompiliert wurde.

  4. Jetzt enthält die Dropdownliste Datenquelle auswählen die soeben erstellte Objektdatenquelle. Erweitern Sie Andere Datenquellen und dann Projektdatenquellen, und wählen Sie Kategorie aus.

    Choose Category data source

    Die zweite DataGridView wird an Produkte gebunden. Anstatt die Ansicht jedoch an den Product-Typ der obersten Ebene zu binden, wird sie von der Category-Bindung des ersten DataGridView an das Products-Navigationselement gebunden. Das bedeutet: Wenn in der ersten Ansicht eine Kategorie ausgewählt wird, werden in der zweiten Ansicht automatisch die Produkte für diese Kategorie automatisch.

  5. Wählen Sie mit der Designer-Aktionsglyphe in der zweiten DataGridView die Option Datenquelle auswählen aus, erweitern Sie dann die categoryBindingSource, und wählen Sie Products aus.

    Choose Products data source

Konfigurieren der angezeigten Elemente

Standardmäßig wird in der DataGridView für jede Eigenschaft der gebundenen Typen eine Spalte erstellt. Außerdem können die Werte für jede dieser Eigenschaften vom Benutzer bearbeitet werden. Einige Werte wie z. B. die Primärschlüsselwerte sind jedoch konzeptbedingt schreibgeschützt und sollten daher nicht bearbeitet werden. Außerdem sind einige Eigenschaften wie die Fremdschlüsseleigenschaft CategoryId und das Category-Navigationselement für den Benutzer nicht nützlich und sollten daher ausgeblendet werden.

Tipp

Es ist üblich, Primärschlüsseleigenschaften in einer echten Anwendung auszublenden. In diesem Tutorial sind sie sichtbar, damit Sie besser erkennen können, welche Vorgänge EF Core hinter den Kulissen ausführt.

  1. Klicken Sie mit der rechten Maustaste auf die DataGridView, und wählen Sie Spalten bearbeiten... aus.

    Edit DataGridView columns

  2. Legen Sie die Spalte CategoryId, die den Primärschlüssel repräsentiert, als schreibgeschützt fest, und klicken Sie auf OK.

    Make CategoryId column read-only

  3. Klicken Sie mit der rechten Maustaste auf die zweite DataGridView, und wählen Sie Spalten bearbeiten... aus. Legen Sie die Spalte ProductId als schreibgeschützt fest, entfernen Sie die Spalten CategoryId und Category, und klicken Sie dann auf OK.

    Make ProductId column read-only and remove CategoryId and Category columns

Verbinden mit EF Core

Die Anwendung benötigt jetzt etwas Code, um EF Core mit den datengebundenen Steuerelementen zu verbinden.

  1. Öffnen Sie den Code für MainForm, indem Sie mit der rechten Maustaste auf die Datei klicken und Code anzeigen auswählen.

    View Code

  2. Fügen Sie ein privates Feld hinzu, das den DbContext für die Sitzung enthalten soll, und fügen Sie Überschreibungen für die Methoden OnLoad und OnClosing hinzu. Der Code sollte wie folgt aussehen:

using Microsoft.EntityFrameworkCore;
using System.ComponentModel;

namespace GetStartedWinForms
{
    public partial class MainForm : Form
    {
        private ProductsContext? dbContext;

        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.dbContext = new ProductsContext();

            // Uncomment the line below to start fresh with a new database.
            // this.dbContext.Database.EnsureDeleted();
            this.dbContext.Database.EnsureCreated();

            this.dbContext.Categories.Load();

            this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            this.dbContext?.Dispose();
            this.dbContext = null;
        }
    }
}

Die OnLoad-Methode wird aufgerufen, wenn das Formular geladen wird. Zu diesem Zeitpunkt geschieht Folgendes:

  • Eine Instanz von ProductsContext wird erstellt, die zum Laden und Nachverfolgen von Änderungen an den von der Anwendung angezeigten Produkten und Kategorien verwendet wird.
  • EnsureCreated wird für den DbContext aufgerufen, um die SQLite-Datenbank zu erstellen, sofern diese noch nicht vorhanden ist. Das ist eine schnelle Möglichkeit zum Erstellen einer Datenbank beim Erstellen von Prototyp- oder Testanwendungen. Wenn sich das Modell ändert, muss die Datenbank jedoch gelöscht werden, damit sie erneut erstellt werden kann. (Die Auskommentierung der Zeile EnsureDeleted kann aufgehoben werden, damit die Datenbank einfach gelöscht und neu erstellt werden kann, wenn die Anwendung ausgeführt wird.) Sie können stattdessen EF Core-Migrationen verwenden, um das Datenbankschema zu ändern und zu aktualisieren, ohne dass Daten verloren gehen.
  • EnsureCreated füllt auch die neue Datenbank mit den in der ProductsContext.OnModelCreating-Methode definierten Daten auf.
  • Die Erweiterungsmethode Load wird verwendet, um alle Kategorien aus der Datenbank in DbContext zu laden. Diese Entitäten werden nun von DbContext nachverfolgt. Damit werden alle Änderungen erkannt, die beim Bearbeiten von Kategorien durch Benutzer vorgenommen werden.
  • Die Eigenschaft categoryBindingSource.DataSource wird in den Kategorien initialisiert, die von DbContext nachverfolgt werden. Dazu wird Local.ToBindingList() für die Categories-Eigenschaft DbSet aufgerufen. Local ermöglicht den Zugriff auf eine lokale Ansicht der nachverfolgten Kategorien, wobei Ereignisse eingebunden sind, um sicherzustellen, dass die lokalen Daten mit den angezeigten Daten synchronisiert bleiben und umgekehrt. ToBindingList() macht diese Daten als IBindingList verfügbar, die von der Windows Forms-Datenbindung verstanden wird.

Die OnClosing-Methode wird aufgerufen, wenn das Formular geschlossen wird. Zu diesem Zeitpunkt wird DbContext verworfen, wodurch sichergestellt wird, dass Datenbankressourcen freigegeben werden, und das Feld dbContext wird auf NULL festgelegt, sodass es nicht erneut verwendet werden kann.

Auffüllen der Ansicht „Produkte“

Wenn die Anwendung an diesem Punkt gestartet wird, sollte sie etwa wie folgt aussehen:

Fist run of the application

Beachten Sie, dass die Kategorien aus der Datenbank geladen wurden, die Produkttabelle jedoch leer bleibt. Außerdem funktioniert die Schaltfläche Speichern nicht.

Zum Auffüllen der Produkttabelle muss EF Core Produkte für die ausgewählte Kategorie aus der Datenbank laden. Hierzu sind folgende Schritte erforderlich:

  1. Wählen Sie im Designer für das Hauptformular die DataGridView für Kategorien aus.

  2. Wählen Sie in den Eigenschaften für DataGridView die Schaltfläche für Ereignisse (Blitz) aus, und doppelklicken Sie auf das Ereignis SelectionChanged.

    Add the SelectionChanged event

    Dadurch wird im Hauptformularcode ein Stub erstellt, damit ein Ereignis ausgelöst wird, wenn sich die Kategorieauswahl ändert.

  3. Geben Sie den Code für das Ereignis ein:

private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
{
    if (this.dbContext != null)
    {
        var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;

        if (category != null)
        {
            this.dbContext.Entry(category).Collection(e => e.Products).Load();
        }
    }
}

Wenn in diesem Code eine aktive DbContext Sitzung (nicht NULL) vorhanden ist, wird die Category-Instanz abgerufen, die an die aktuell ausgewählte Zeile der DataViewGrid gebunden ist. (Dies kann null sein, wenn die letzte Zeile in der Ansicht ausgewählt ist, die zum Erstellen neuer Kategorien verwendet wird.) Wenn eine ausgewählte Kategorie vorhanden ist, wird DbContext angewiesen, die mit dieser Kategorie verknüpften Produkte zu laden. Dies wird wie folgt erreicht:

  • Es wird ein EntityEntry für die Category-Instanz abgerufen (dbContext.Entry(category)).
  • EF Core wird darüber informiert, dass das Navigationselement der Sammlung Products dieser Category verwendet werden soll (.Collection(e => e.Products)).
  • Und schließlich wird EF Core mitgeteilt, dass diese Sammlung von Produkten aus der Datenbank geladen werden soll (.Load();).

Tipp

Wenn Load aufgerufen wird, greift EF Core nur auf die Datenbank zu, um die Produkte zu laden, falls sie noch nicht geladen wurden.

Wenn die Anwendung jetzt erneut ausgeführt wird, sollte sie die entsprechenden Produkte laden, wenn eine Kategorie ausgewählt wird:

Products are loaded

Änderungen werden gespeichert

Schließlich kann die Schaltfläche Speichern mit EF Core verbunden werden, sodass alle Änderungen, die an den Produkten und Kategorien vorgenommen wurden, in der Datenbank gespeichert werden.

  1. Wählen Sie im Designer für das Hauptformular die Schaltfläche Speichern aus.

  2. Wählen Sie in den Eigenschaften für Button die Schaltfläche für Ereignisse (Blitz) aus, und doppelklicken Sie auf das Ereignis Click.

    Add the Click event for Save

  3. Geben Sie den Code für das Ereignis ein:

private void buttonSave_Click(object sender, EventArgs e)
{
    this.dbContext!.SaveChanges();

    this.dataGridViewCategories.Refresh();
    this.dataGridViewProducts.Refresh();
}

Dieser Code ruft SaveChanges für DbContext auf, wodurch alle Änderungen gespeichert werden, die an der SQLite-Datenbank vorgenommen wurden. Wenn keine Änderungen vorgenommen wurden, werden keine Vorgänge verarbeitet, und es erfolgt kein Datenbankaufruf. Nach dem Speichern werden die DataGridView-Steuerelemente aktualisiert. Dies liegt daran, dass EF Core generierte Primärschlüsselwerte für alle neuen Produkte und Kategorien aus der Datenbank liest. Durch Aufrufen von Refresh wird die Anzeige mit diesen generierten Werten aktualisiert.

Die endgültige Anwendung

Hier sehen Sie den vollständigen Code für das Hauptformular:

using Microsoft.EntityFrameworkCore;
using System.ComponentModel;

namespace GetStartedWinForms
{
    public partial class MainForm : Form
    {
        private ProductsContext? dbContext;

        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.dbContext = new ProductsContext();

            // Uncomment the line below to start fresh with a new database.
            // this.dbContext.Database.EnsureDeleted();
            this.dbContext.Database.EnsureCreated();

            this.dbContext.Categories.Load();

            this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            this.dbContext?.Dispose();
            this.dbContext = null;
        }

        private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
        {
            if (this.dbContext != null)
            {
                var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;

                if (category != null)
                {
                    this.dbContext.Entry(category).Collection(e => e.Products).Load();
                }
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            this.dbContext!.SaveChanges();

            this.dataGridViewCategories.Refresh();
            this.dataGridViewProducts.Refresh();
        }
    }
}

Die Anwendung kann jetzt ausgeführt werden, und Produkte und Kategorien können hinzugefügt, gelöscht und bearbeitet werden. Beachten Sie Folgendes: Wenn vor dem Schließen der Anwendung auf die Schaltfläche Speichern geklickt wird, werden alle vorgenommenen Änderungen in der Datenbank gespeichert und erneut geladen, wenn die Anwendung erneut gestartet wird. Wenn nicht auf Speichern geklickt wird, gehen alle Änderungen verloren, wenn die Anwendung erneut gestartet wird.

Tipp

Eine neue Kategorie oder ein neues Produkt kann einem DataViewControl über die leere Zeile am unteren Rand des Steuerelements hinzugefügt werden. Eine Zeile kann gelöscht werden, indem Sie sie auswählen und die Taste ENTF drücken.

Vor dem Speichern

The running application before clicking Save

Nach dem Speichern

The running application after clicking Save

Beachten Sie, dass die Primärschlüsselwerte für die hinzugefügte Kategorie und Produkte aufgefüllt werden, wenn auf Speichern geklickt wird.

Weitere Informationen