Bagikan melalui


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

  1. Membuka Visual Studio
  2. Di jendela mulai, pilih Buat proyek baru.
  3. Cari "WPF," pilih Aplikasi WPF (.NET Core) lalu pilih Berikutnya.
  4. Di layar berikutnya, beri nama proyek, misalnya, GetStartedWPF, dan pilih Buat.

Menginstal paket Entity Framework NuGet

  1. Klik kanan pada solusi dan pilih Kelola Paket NuGet untuk Solusi...

    Manage NuGet Packages

  2. Ketik entityframeworkcore.sqlite di kotak pencarian.

  3. Pilih paket Microsoft.EntityFrameworkCore.Sqlite .

  4. Periksa proyek di panel kanan dan klik Instal

    Sqlite Package

  5. 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.

  1. Klik dua kali MainWindow.xaml di Penjelajah Solusi untuk membuka formulir utama

  2. Pilih tab XAML untuk mengedit XAML.

  3. 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>
    
  4. Ini menyiapkan sumber untuk kategori "induk", dan sumber kedua untuk produk "detail".

  5. 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>
    
  6. Perhatikan bahwa CategoryId diatur ke ReadOnly 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:

Screenshot of WPF Designer

Menambahkan Kode yang Menangani Interaksi Data

Saatnya untuk menambahkan beberapa penanganan aktivitas ke jendela utama.

  1. Di jendela XAML, klik <elemen Window> , untuk memilih jendela utama.

  2. Di jendela Properti pilih Peristiwa di kanan atas, lalu klik ganda kotak teks di sebelah kanan label Dimuat .

    Main Window Properties

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.

Running application

Pemberitahuan Perubahan Properti

Contoh ini bergantung pada empat langkah untuk menyinkronkan entitas dengan UI.

  1. Panggilan _context.Categories.Load() awal memuat data kategori.
  2. Proksi pemuatan malas memuat data produk dependen.
  3. Pelacakan perubahan bawaan EF Core membuat modifikasi yang diperlukan pada entitas, termasuk penyisipan dan penghapusan, ketika _context.SaveChanges() dipanggil.
  4. 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.