Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento podrobný návod ukazuje, jak svázat typy POCO s ovládacími prvky WPF ve formuláři "main-detail". Aplikace používá rozhraní API entity Framework k naplnění objektů daty z databáze, sledování změn a zachování dat do databáze.
Model definuje dva typy, které se účastní relace 1:N: Category (principal\main) a Product (závislý\detail). Architektura datových vazeb WPF umožňuje navigaci mezi souvisejícími objekty: výběr řádků v hlavním zobrazení způsobí, že se zobrazení podrobností aktualizuje s odpovídajícími podřízenými daty.
Snímky obrazovky a výpisy kódu v tomto návodu pocházejí ze sady Visual Studio 2019 16.6.5.
Tip
Ukázku tohoto článku najdete naGitHubu .
Pre-Requisites
K dokončení tohoto návodu musíte mít nainstalovanou sadu Visual Studio 2019 16.3 nebo novější s vybranou úlohou .NET Desktop . Další informace o instalaci nejnovější verze sady Visual Studio naleznete v tématu Instalace sady Visual Studio.
Vytvoření aplikace
- Otevřete Visual Studio
- V úvodním okně zvolte Vytvořit nový projekt.
- Vyhledejte "WPF", zvolte APLIKACI WPF (.NET) a pak zvolte Další.
- Na další obrazovce zadejte název projektu, například GetStartedWPF, a zvolte Vytvořit.
Nainstalujte balíčky NuGet Entity Framework
Klikněte pravým tlačítkem na řešení a zvolte Spravovat balíčky NuGet pro řešení...
Zadejte
entityframeworkcore.sqlitedo vyhledávacího pole.Vyberte balíček Microsoft.EntityFrameworkCore.Sqlite .
Zkontrolujte projekt v pravém podokně a klikněte na Nainstalovat.
Opakováním kroků vyhledejte
entityframeworkcore.proxiesa nainstalujte Microsoft.EntityFrameworkCore.Proxies.
Note
Když jste nainstalovali balíček Sqlite, automaticky se stáhl související základní balíček Microsoft.EntityFrameworkCore . Balíček Microsoft.EntityFrameworkCore.Proxies poskytuje podporu pro opožděná načítání dat. To znamená, že pokud máte entity s podřízenými entitami, se při počátečním načtení načítají pouze nadřazené entity. Proxy servery zjistí, kdy se provede pokus o přístup k podřízeným entitám, a automaticky je načte na vyžádání.
Definování modelu
V tomto názorném postupu implementujete model pomocí kódu jako první. To znamená, že EF Core vytvoří databázové tabulky a schéma založené na definovaných třídách jazyka C#.
Přidejte novou třídu. Pojmenujte ho takto: Product.cs a naplňte ho následovně:
Product.cs
namespace GetStartedWPF
{
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
}
Dále přidejte třídu s názvem Category.cs a naplňte ji následujícím kódem:
Category.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace GetStartedWPF
{
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product>
Products
{ get; private set; } =
new ObservableCollection<Product>();
}
}
Vlastnost Products ve třídě Category a Category ve třídě Product jsou navigační vlastnosti. Ve službě Entity Framework poskytují navigační vlastnosti způsob, jak přecházet mezi dvěma typy entit.
Kromě definování entit je nutné definovat třídu, která je odvozena z DbContext a zveřejňuje DbSet<TEntity> vlastnosti. Vlastnosti DbSet<TEntity> znají kontext, které typy chcete zahrnout do modelu.
Instance odvozeného typu DbContext spravuje objekty entity během doby běhu, což zahrnuje naplnění objektů dat z databáze, sledování změn a zachování dat do databáze.
Přidejte do projektu novou ProductContext.cs třídu s následující definicí:
ProductContext.cs
using Microsoft.EntityFrameworkCore;
namespace GetStartedWPF
{
public class ProductContext : 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");
optionsBuilder.UseLazyLoadingProxies();
}
}
}
- Informuje
DbSetEF Core o tom, jaké entity jazyka C# by měly být mapovány na databázi. - Existují různé způsoby konfigurace EF Core
DbContext. O nich si můžete přečíst v tématu Konfigurace DbContext. - Tento příklad používá přepis
OnConfiguringk určení datového souboru SQLite. - Volání
UseLazyLoadingProxiesinstruuje EF Core k implementaci líného načítání, takže podřízené entity jsou automaticky načteny při přístupu z nadřazeného objektu.
Stisknutím CTRL+SHIFT+B nebo přejděte na Stavět > Stavět řešení zkompilujte projekt.
Tip
Zjistěte, jakými způsoby můžete udržet databázi a modely EF Core v synchronizaci: Správa schémat databáze.
Líné načítání
Vlastnost Products ve třídě Category a Category ve třídě Product jsou navigační vlastnosti. V Entity Framework Core poskytují navigační vlastnosti způsob, jak procházet vztah mezi dvěma typy entit.
EF Core nabízí možnost načíst související entity z databáze automaticky při prvním přístupu k navigační vlastnosti. U tohoto typu načítání (označovaného jako opožděné načítání) mějte na paměti, že při prvním přístupu ke každé navigační vlastnosti se vůči databázi spustí samostatný dotaz, pokud obsah ještě není v kontextu.
Pokud používáte entity "Plain Old C# Object" (POCO), EF Core dosahuje opožděného načítání vytvořením instancí odvozených typů proxy během běhu a přepsáním virtuálních vlastností ve vašich třídách, aby se přidalo načítání háku. Chcete-li získat opožděné načítání souvisejících objektů, musíte deklarovat navigační vlastnost getters jako veřejné a virtuální (Overridable v jazyce Visual Basic) a vaše třída nesmí být zapečetěná (NotOverridable v jazyce Visual Basic). Při použití funkce Database First se navigační vlastnosti automaticky vytvoří jako virtuální, aby se povolilo opožděné načítání.
Vytvoření vazby objektu k ovládacím prvkům
Přidejte třídy definované v modelu jako zdroje dat pro tuto aplikaci WPF.
Poklikáním na MainWindow.xaml v Průzkumníku řešení otevřete hlavní formulář.
Zvolte kartu XAML a upravte xaml.
Hned za počáteční
Windowznačku přidejte následující zdroje pro připojení k entitě EF Core.<Window x:Class="GetStartedWPF.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:GetStartedWPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> <Window.Resources> <CollectionViewSource x:Key="categoryViewSource"/> <CollectionViewSource x:Key="categoryProductsViewSource" Source="{Binding Products, Source={StaticResource categoryViewSource}}"/> </Window.Resources>Tímto se nastavuje zdroj pro "rodičovské" kategorie a druhý zdroj pro "podrobné" produkty.
Dále přidejte následující označení do XAML za počáteční
Gridznačku.<DataGrid x:Name="categoryDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding Source={StaticResource categoryViewSource}}" Margin="13,13,43,229" RowDetailsVisibilityMode="VisibleWhenSelected"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding CategoryId}" Header="Category Id" Width="SizeToHeader" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="*"/> </DataGrid.Columns> </DataGrid>Všimněte si, že
CategoryIdje nastaveno naReadOnlyprotože je přiřazeno databází a nelze jej změnit.
Přidání mřížky podrobností
Teď, když mřížka existuje pro zobrazení kategorií, je možné přidat mřížku podrobností, aby se zobrazily produkty. Přidejte tento prvek do elementu Grid za element categories DataGrid .
MainWindow.xaml
<DataGrid x:Name="productsDataGrid" AutoGenerateColumns="False"
EnableRowVirtualization="True"
ItemsSource="{Binding Source={StaticResource categoryProductsViewSource}}"
Margin="13,205,43,108" RowDetailsVisibilityMode="VisibleWhenSelected"
RenderTransformOrigin="0.488,0.251">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding CategoryId}"
Header="Category Id" Width="SizeToHeader"
IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding ProductId}" Header="Product Id"
Width="SizeToHeader" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="*"/>
</DataGrid.Columns>
</DataGrid>
Nakonec přidejte tlačítko Save a propojte událost kliknutí Button_Click.
<Button Content="Save" HorizontalAlignment="Center" Margin="0,240,0,0"
Click="Button_Click" Height="20" Width="123"/>
Vaše návrhové zobrazení by mělo vypadat takto:
Přidání kódu, který zpracovává interakci s daty
Je čas přidat některé obslužné rutiny událostí do hlavního okna.
V okně XAML klikněte na prvek <Window>, abyste vybrali hlavní okno.
V okně Vlastnosti zvolte Události v pravém horním rohu a potom poklikejte na textové pole napravo od načteného popisku.
Tím se dostanete ke kódu na pozadí pro formulář, který nyní upravíme tak, abychom použili ProductContext k provádění přístupu k datům. Aktualizujte kód, jak je znázorněno níže.
Kód deklaruje dlouhotrvající instanci ProductContext. Objekt ProductContext se používá k dotazování a ukládání dat do databáze. Metoda Dispose() v ProductContext instanci se pak volá z přepsáné OnClosing metody. Komentáře ke kódu vysvětlují, co každý krok dělá.
MainWindow.xaml.cs
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
namespace GetStartedWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ProductContext _context =
new ProductContext();
private CollectionViewSource categoryViewSource;
public MainWindow()
{
InitializeComponent();
categoryViewSource =
(CollectionViewSource)FindResource(nameof(categoryViewSource));
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// this is for demo purposes only, to make it easier
// to get up and running
_context.Database.EnsureCreated();
// load the entities into EF Core
_context.Categories.Load();
// bind to the source
categoryViewSource.Source =
_context.Categories.Local.ToObservableCollection();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// all changes are automatically tracked, including
// deletes!
_context.SaveChanges();
// this forces the grid to refresh to latest values
categoryDataGrid.Items.Refresh();
productsDataGrid.Items.Refresh();
}
protected override void OnClosing(CancelEventArgs e)
{
// clean up database connections
_context.Dispose();
base.OnClosing(e);
}
}
}
Note
Kód používá volání na EnsureCreated() pro sestavení databáze při prvním spuštění. To je přijatelné pro ukázky, ale v produkčních aplikacích byste se měli podívat na migrace pro správu schématu. Kód se také spouští synchronně, protože používá místní databázi SQLite. V produkčních scénářích, které obvykle zahrnují vzdálený server, zvažte použití asynchronních Load verzí a SaveChanges metod.
Testování aplikace WPF
Zkompilujte a spusťte aplikaci stisknutím klávesy F5 nebo výběrem Spustit > ladění. Databáze by se měla automaticky vytvořit pomocí souboru s názvem products.db. Zadejte název kategorie a stiskněte Enter a pak přidejte produkty do dolní mřížky. Klikněte na Uložit a sledujte aktualizaci mřížky s ID přidělenými databází. Zvýrazněte řádek a stisknutím klávesy Odstranit odeberte řádek. Entita bude odstraněna po kliknutí na tlačítko Uložit.
Oznámení o změně vlastnosti
Tento příklad využívá čtyři kroky k synchronizaci entit s uživatelským rozhraním.
- Počáteční volání
_context.Categories.Load()načte data kategorií. - Proxy pro líné načítání načítají data závislých produktů.
- Vestavěné sledování změn EF Core provádí potřebné úpravy entit, včetně vkládání a odstraňování, když se volá
_context.SaveChanges(). - Volání
DataGridView.Items.Refresh()vynutí opětovné načtení s nově vygenerovanými ID.
To funguje pro naši ukázku Začínáme, ale pro jiné scénáře můžete vyžadovat další kód. Ovládací prvky WPF vykreslují uživatelské rozhraní čtením polí a vlastností entit. Při úpravě hodnoty v uživatelském rozhraní (UI) se tato hodnota předá vaší entitě. Když změníte hodnotu vlastnosti přímo na entitě, například ji načítáte z databáze, WPF okamžitě neodráží změny v uživatelském rozhraní. Vykreslovací modul musí být informován o změnách. Projekt to udělal ručním voláním Refresh(). Snadný způsob, jak toto oznámení automatizovat, je implementace INotifyPropertyChanged rozhraní. Komponenty WPF automaticky rozpozná rozhraní a zaregistrují události změn. Entita zodpovídá za vyvolání těchto událostí.
Tip
Další informace o tom, jak zpracovávat změny, najdete v tématu : Jak implementovat oznámení o změně vlastnosti.
Další kroky
Přečtěte si další informace o konfiguraci DbContext.