Memulai WPF
Panduan langkah demi langkah ini menunjukkan cara mengikat jenis POCO ke kontrol WPF dalam bentuk "detail utama". Aplikasi ini menggunakan API Kerangka Kerja Entitas untuk mengisi objek dengan data dari database, melacak perubahan, dan menyimpan data ke database.
Model mendefinisikan dua jenis yang berpartisipasi dalam hubungan satu-ke-banyak: Kategori (utama\utama) dan Produk (dependent\detail). Kerangka kerja pengikatan data WPF memungkinkan navigasi antara objek terkait: memilih baris dalam tampilan master menyebabkan tampilan detail diperbarui dengan data anak yang sesuai.
Cuplikan layar dan daftar kode dalam panduan ini diambil dari Visual Studio 2019 16.6.5.
Tip
Anda dapat melihat contoh artikel ini di GitHub.
Prasyarat
Anda harus menginstal Visual Studio 2019 16.3 atau yang lebih baru dengan beban kerja desktop .NET yang dipilih untuk menyelesaikan panduan ini. Untuk informasi selengkapnya tentang menginstal Visual Studio versi terbaru, lihat Menginstal Visual Studio.
Membuat Aplikasi
- Membuka Visual Studio
- Di jendela mulai, pilih Buat proyek baru.
- Cari "WPF," pilih Aplikasi WPF (.NET Core) lalu pilih Berikutnya.
- Di layar berikutnya, beri nama proyek, misalnya, GetStartedWPF, dan pilih Buat.
Menginstal paket Entity Framework NuGet
Klik kanan pada solusi dan pilih Kelola Paket NuGet untuk Solusi...
Ketik
entityframeworkcore.sqlite
di kotak pencarian.Pilih paket Microsoft.EntityFrameworkCore.Sqlite .
Periksa proyek di panel kanan dan klik Instal
Ulangi langkah-langkah untuk
entityframeworkcore.proxies
mencari dan menginstal Microsoft.EntityFrameworkCore.Proxies.
Catatan
Saat Anda menginstal paket Sqlite, paket tersebut secara otomatis menarik paket dasar Microsoft.EntityFrameworkCore terkait. Paket Microsoft.EntityFrameworkCore.Proxies menyediakan dukungan untuk data "pemuatan malas". Ini berarti ketika Anda memiliki entitas dengan entitas anak, hanya orang tua yang diambil pada beban awal. Proksi mendeteksi kapan upaya untuk mengakses entitas anak dibuat dan secara otomatis memuatnya sesuai permintaan.
Tentukan Model
Dalam panduan ini Anda akan menerapkan model menggunakan "kode terlebih dahulu." Ini berarti bahwa EF Core akan membuat tabel database dan skema berdasarkan kelas C# yang Anda tentukan.
Tambahkan kelas baru. Beri nama: Product.cs
dan isi seperti ini:
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; }
}
}
Selanjutnya, tambahkan kelas bernama Category.cs
dan isi dengan kode berikut:
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>();
}
}
Properti Produk pada kelas Kategori dan properti Kategori pada kelas Produk adalah properti navigasi. Dalam Kerangka Kerja Entitas, properti navigasi menyediakan cara untuk menavigasi hubungan antara dua jenis entitas.
Selain menentukan entitas, Anda perlu menentukan kelas yang berasal dari DbContext dan mengekspos properti DbSet<TEntity> . Properti DbSet<TEntity> memberi tahu konteks jenis mana yang ingin Anda sertakan dalam model.
Instans jenis turunan DbContext mengelola objek entitas selama run time, yang mencakup mengisi objek dengan data dari database, pelacakan perubahan, dan menyimpan data ke database.
Tambahkan kelas baru ProductContext.cs
ke proyek dengan definisi berikut:
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();
}
}
}
- Memberi
DbSet
tahu EF Core entitas C# apa yang harus dipetakan ke database. - Ada berbagai cara untuk mengonfigurasi EF Core
DbContext
. Anda dapat membacanya di: Mengonfigurasi DbContext. - Contoh ini menggunakan penimpaan
OnConfiguring
untuk menentukan file data Sqlite. - Panggilan memberi
UseLazyLoadingProxies
tahu EF Core untuk menerapkan pemuatan malas, sehingga entitas anak dimuat secara otomatis saat diakses dari induk.
Tekan CTRL+SHIFT+B atau navigasi ke > Build Build Solution untuk mengkompilasi proyek.
Tip
Pelajari tentang hal yang berbeda adalah menjaga database dan model EF Core Anda tetap sinkron: Mengelola Skema Database.
Pemuatan Lambat
Properti Produk pada kelas Kategori dan properti Kategori pada kelas Produk adalah properti navigasi. Di Entity Framework Core, properti navigasi menyediakan cara untuk menavigasi hubungan antara dua jenis entitas.
EF Core memberi Anda opsi untuk memuat entitas terkait dari database secara otomatis saat pertama kali Anda mengakses properti navigasi. Dengan jenis pemuatan ini (disebut pemuatan malas), ketahuilah bahwa pertama kali Anda mengakses setiap properti navigasi, kueri terpisah akan dijalankan terhadap database jika konten belum dalam konteks.
Saat menggunakan jenis entitas "Plain Old C# Object" (POCO), EF Core mencapai pemuatan malas dengan membuat instans jenis proksi turunan selama runtime lalu menimpa properti virtual di kelas Anda untuk menambahkan kait pemuatan. Untuk mendapatkan pemuatan objek terkait yang malas, Anda harus mendeklarasikan getter properti navigasi sebagai publik dan virtual (Dapat Diganti di Visual Basic), dan kelas Anda tidak boleh disegel(NotOverridable di Visual Basic). Saat menggunakan Database First, properti navigasi secara otomatis dibuat virtual untuk mengaktifkan pemuatan malas.
Mengikat Objek ke Kontrol
Tambahkan kelas yang didefinisikan dalam model sebagai sumber data untuk aplikasi WPF ini.
Klik dua kali MainWindow.xaml di Penjelajah Solusi untuk membuka formulir utama
Pilih tab XAML untuk mengedit XAML.
Segera setelah tag pembuka
Window
, tambahkan sumber berikut untuk terhubung ke entitas 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>
Ini menyiapkan sumber untuk kategori "induk", dan sumber kedua untuk produk "detail".
Selanjutnya, tambahkan markup berikut ke XAML Anda setelah tag pembuka
Grid
.<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>
Perhatikan bahwa
CategoryId
diatur keReadOnly
karena ditetapkan oleh database dan tidak dapat diubah.
Menambahkan Kisi Detail
Sekarang setelah kisi ada untuk menampilkan kategori, kisi detail dapat ditambahkan untuk menampilkan produk. Tambahkan ini di Grid
dalam elemen , setelah elemen kategori 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>
Terakhir, tambahkan Save
tombol dan kawat di peristiwa klik ke Button_Click
.
<Button Content="Save" HorizontalAlignment="Center" Margin="0,240,0,0"
Click="Button_Click" Height="20" Width="123"/>
Tampilan desain Anda akan terlihat seperti ini:
Menambahkan Kode yang Menangani Interaksi Data
Saatnya untuk menambahkan beberapa penanganan aktivitas ke jendela utama.
Di jendela XAML, klik <elemen Window> , untuk memilih jendela utama.
Di jendela Properti pilih Peristiwa di kanan atas, lalu klik ganda kotak teks di sebelah kanan label Dimuat .
Ini membawa Anda ke kode di belakang untuk formulir, kami sekarang akan mengedit kode untuk menggunakan ProductContext
untuk melakukan akses data. Perbarui kode seperti yang ditunjukkan di bawah ini.
Kode mendeklarasikan instans yang berjalan lama dari ProductContext
. Objek ProductContext
digunakan untuk mengkueri dan menyimpan data ke database. Metode Dispose()
pada ProductContext
instans kemudian dipanggil dari metode yang ditimpa OnClosing
. Komentar kode menjelaskan apa yang dilakukan setiap langkah.
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);
}
}
}
Catatan
Kode menggunakan panggilan ke untuk EnsureCreated()
membangun database pada eksekusi pertama. Ini dapat diterima untuk demo, tetapi dalam aplikasi produksi Anda harus melihat migrasi untuk mengelola skema Anda. Kode juga dijalankan secara sinkron karena menggunakan database SQLite lokal. Untuk skenario produksi yang biasanya melibatkan server jarak jauh, pertimbangkan untuk menggunakan versi asinkron dari Load
metode dan SaveChanges
.
Menguji Aplikasi WPF
Kompilasi dan jalankan aplikasi dengan menekan F5 atau memilih Debug > Mulai Debugging. Database harus dibuat secara otomatis dengan file bernama products.db
. Masukkan nama kategori dan tekan enter, lalu tambahkan produk ke kisi bawah. Klik simpan dan tonton refresh kisi dengan id yang disediakan database. Sorot baris dan tekan Hapus untuk menghapus baris. Entitas akan dihapus saat Anda mengklik Simpan.
Pemberitahuan Perubahan Properti
Contoh ini bergantung pada empat langkah untuk menyinkronkan entitas dengan UI.
- Panggilan
_context.Categories.Load()
awal memuat data kategori. - Proksi pemuatan malas memuat data produk dependen.
- Pelacakan perubahan bawaan EF Core membuat modifikasi yang diperlukan pada entitas, termasuk penyisipan dan penghapusan, ketika
_context.SaveChanges()
dipanggil. - Panggilan untuk
DataGridView.Items.Refresh()
memaksa pemuatan ulang dengan id yang baru dibuat.
Ini berfungsi untuk sampel memulai kami, tetapi Anda mungkin memerlukan kode tambahan untuk skenario lain. Kontrol WPF merender UI dengan membaca bidang dan properti pada entitas Anda. Saat Anda mengedit nilai di antarmuka pengguna (UI), nilai tersebut diteruskan ke entitas Anda. Saat Anda mengubah nilai properti langsung pada entitas Anda, seperti memuatnya dari database, WPF tidak akan segera mencerminkan perubahan di UI. Mesin penyajian harus diberi tahu tentang perubahan. Proyek melakukan ini dengan memanggil Refresh()
secara manual . Cara mudah untuk mengotomatiskan pemberitahuan ini adalah dengan menerapkan antarmuka INotifyPropertyChanged . Komponen WPF akan secara otomatis mendeteksi antarmuka dan mendaftar untuk peristiwa perubahan. Entitas bertanggung jawab untuk menaikkan peristiwa ini.
Tip
Untuk mempelajari selengkapnya tentang cara menangani perubahan, baca: Cara menerapkan pemberitahuan perubahan properti.
Langkah berikutnya
Pelajari selengkapnya tentang Mengonfigurasi DbContext.
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk