Windows Forms'a Başlarken

Bu adım adım kılavuz, SQLite veritabanı tarafından desteklenen basit bir Windows Forms (WinForms) uygulamasının nasıl derlendiğini gösterir. Uygulama, veritabanından veri yüklemek, bu verilerde yapılan değişiklikleri izlemek ve bu değişiklikleri veritabanında kalıcı hale getirmek için Entity Framework Core (EF Core) kullanır.

Bu kılavuzdaki ekran görüntüleri ve kod listeleri Visual Studio 2022 17.3.0'dan alınmıştır.

İpucu

Bu makalenin örneğini GitHub'da görüntüleyebilirsiniz.

Önkoşullar

Bu kılavuzu tamamlamak için Visual Studio 2022 17.3 veya üzerini .NET masaüstü iş yükü seçili olarak yüklemeniz gerekir. Visual Studio'nun en son sürümünü yükleme hakkında daha fazla bilgi için bkz . Visual Studio'yu Yükleme.

Uygulamayı Oluşturma

  1. Visual Studio’yu açın

  2. Başlangıç penceresinde Yeni proje oluştur'u seçin.

  3. Windows Forms Uygulaması'nı ve ardından İleri'yi seçin.

    Yeni bir Windows Forms projesi oluşturma

  4. Sonraki ekranda projeye getStartedWinForms gibi bir ad verin ve İleri'yi seçin.

  5. Sonraki ekranda, kullanılacak .NET sürümünü seçin. Bu izlenecek yol .NET 7 ile oluşturulmuştur, ancak sonraki sürümlerle de çalışması gerekir.

  6. Oluştur’u seçin.

EF Core NuGet paketlerini yükleme

  1. Çözüme sağ tıklayın ve Çözüm için NuGet Paketlerini Yönet... seçeneğini belirleyin .

    Çözüm için NuGet Paketlerini Yönetme

  2. Gözat sekmesini seçin ve "Microsoft.EntityFrameworkCore.Sqlite" araması yapın.

  3. Microsoft.EntityFrameworkCore.Sqlite paketini seçin.

  4. Sağ bölmedeki GetStartedWinForms projesini denetleyin.

  5. En son sürümü seçin. Yayın öncesi sürümü kullanmak için Ön sürümü dahil et kutusunun işaretli olduğundan emin olun.

  6. Yükle'ye tıklayın

    Microsoft.EntityFrameworkCore.Sqlite paketini yükleme

Not

Microsoft.EntityFrameworkCore.Sqlite, EF Core'u SQLite veritabanıyla kullanmaya yönelik "veritabanı sağlayıcısı" paketidir. Diğer veritabanı sistemleri için de benzer paketler mevcuttur. Veritabanı sağlayıcısı paketinin yüklenmesi, EF Core'u bu veritabanı sistemiyle kullanmak için gereken tüm bağımlılıkları otomatik olarak getirir. Bu, Microsoft.EntityFrameworkCore temel paketini içerir.

Bir Model Tanımlayın

Bu kılavuzda "Code First" kullanarak bir model uygulayacağız. Bu, EF Core'un tanımladığınız C# sınıflarını temel alan veritabanı tablolarını ve şemasını oluşturacağı anlamına gelir. Bunun yerine var olan bir veritabanının nasıl kullanılacağını görmek için bkz . Veritabanı Şemalarını Yönetme.

  1. Projeye sağ tıklayıp Ekle'yi ve ardından Sınıf... öğesini seçerek yeni bir sınıf ekleyin.

    Yeni sınıf ekleme

  2. dosya adını Product.cs kullanın ve sınıfın kodunu şununla değiştirin:

    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. Aşağıdaki kodu kullanarak Category.cs'yi oluşturmak için tekrarlayın.

    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();
    }
    

Products sınıfındaki Category özelliği ve Category sınıfındaki Product özelliği "gezintiler" olarak adlandırılır. EF Core'da gezintiler iki varlık türü arasında bir ilişki tanımlar. Bu durumda gezinti, Product.Category belirli bir ürünün ait olduğu kategoriye başvurur. Benzer şekilde, koleksiyon gezintisi Category.Products belirli bir kategoriye ilişkin tüm ürünleri içerir.

İpucu

Windows Forms kullanılırken, ObservableCollectionListSourceuygulamasını uygulayan IListSource, koleksiyon gezintileri için kullanılabilir. Bu gerekli değildir, ancak iki yönlü veri bağlama deneyimini geliştirir.

DbContext'i tanımlama

EF Core'da, DbContext öğesinden türetilen bir sınıf, bir modeldeki varlık türlerini yapılandırmak ve veritabanıyla etkileşime geçmek için kullanılır ve bir oturum olarak görev yapar. En basit durumda, bir DbContext sınıf:

  • Modeldeki her varlık türünün özelliklerini içerir DbSet .
  • Veritabanı sağlayıcısı ve kullanılacak bağlantı dizesini yapılandırmak için OnConfiguring metodunu geçersiz kılar. Daha detaylı bilgi için DbContext'i yapılandırma bölümüne bakın.

Bu durumda, DbContext sınıfı da OnModelCreating yöntemini, uygulama için bazı örnek veriler sağlamak üzere aşar.

Aşağıdaki kodla projeye yeni ProductsContext.cs bir sınıf ekleyin:

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" });
    }
}

Bu noktada çözümü derlediğinden emin olun.

Forma bir denetim ekleme

Uygulama, kategorilerin ve ürünlerin listesini gösterir. İlk listede bir kategori seçildiğinde, ikinci liste bu kategoriye ilişkin ürünleri gösterecek şekilde değişir. Bu listeler ürün ve kategori eklemek, kaldırmak veya düzenlemek için değiştirilebilir ve bu değişiklikler Bir Kaydet düğmesine tıklanarak SQLite veritabanına kaydedilebilir.

  1. Ana formun adını Form1'dan MainForm olarak değiştirin.

    Form1'i MainForm olarak yeniden adlandırma

  2. Başlığı da "Ürünler ve Kategoriler" olarak değiştirin.

  3. Araç Kutusu'nu kullanarak yan yana yerleştirilmiş iki DataGridView denetim ekleyin.

    DataGridView Ekleme

  4. İlk Özellikler içindeki DataGridView için, Ad öğesini dataGridViewCategories olarak değiştirin.

  5. İkinci DataGridView için Özellikler kısmında, AdıdataGridViewProducts olarak değiştirin.

  6. Ayrıca Araç Kutusu'nu kullanarak bir Button denetim ekleyin.

  7. Düğmeyi buttonSave adlandırın ve "Kaydet" metnini verin. Form şu şekilde görünmelidir:

    Form düzeni

Veri bağlama

Sonraki adım, modeldeki Product ve Category türlerini denetimlere bağlamaktır DataGridView . Bu, EF Core tarafından yüklenen verileri denetimlere bağlar; böylece EF Core tarafından izlenen varlıklar denetimlerde görüntülenenlerle eşitlenmiş olarak tutulur.

  1. İlk üzerinde Tasarımcı Eylem Karakteri'neDataGridViewtıklayın. Bu, denetimin sağ üst köşesindeki küçük düğmedir.

    Tasarımcı Eylem Simge

  2. Bu, Eylem Listesi'ni açar; buradan Veri Kaynağı Seç açılır menüsüne erişilebilir. Henüz bir veri kaynağı oluşturmadık, bu nedenle en alta gidin ve Yeni Nesne Veri Kaynağı Ekle... öğesini seçin.

    Yeni Nesne Veri Kaynağı Ekle

  3. Kategoriler için nesne veri kaynağı oluşturmak üzere Kategori'yi seçin ve Tamam'a tıklayın.

    Kategori veri kaynağı türünü seçin

    İpucu

    Burada veri kaynağı türü görünmüyorsa, projeye eklendiğinden Product.csCategory.csve ProductsContext.cs çözümün oluşturulduğundan emin olun.

  4. Veri Kaynağı Seç açılan listesinde şimdi yeni oluşturduğumuz nesne veri kaynağı yer alır. Diğer Veri Kaynakları'nı genişletin, ardından Proje Veri Kaynakları'nı genişletin ve Kategori'yi seçin.

    Kategori veri kaynağını seçin

    İkincisi DataGridView ürünlere bağlı olacaktır. Ancak, en üst düzey Product türüne bağlanmak yerine, ilk DataGridView bağlamasından gelen Category gezintisine bağlanacaktır. Bu, birinci görünümde bir kategori seçildiğinde, söz konusu kategoriye ilişkin ürünlerin ikinci görünümde otomatik olarak kullanılacağı anlamına gelir.

  5. İkinci Designer Action Glyph’ı kullanarak Veri Kaynağını Seç, ardından ’ü genişletip ’ü seçin.

    Ürünler veri kaynağını seçin

Görüntülenenleri yapılandırma

Varsayılan olarak, bağlı türlerin DataGridView her özelliği için içinde bir sütun oluşturulur. Ayrıca, bu özelliklerin her birinin değerleri kullanıcı tarafından düzenlenebilir. Ancak, birincil anahtar değerleri gibi bazı değerler kavramsal olarak salt okunur olduğundan düzenlenmemelidir. Ayrıca, yabancı anahtar özelliği ve CategoryId gezinti gibi Category bazı özellikler kullanıcı için yararlı değildir ve bu nedenle gizlenmelidir.

İpucu

Gerçek bir uygulamada birincil anahtar özelliklerini gizlemek yaygın bir durumdur. EF Core'un arka planda neler yaptığını görmelerini kolaylaştırmak için burada görünür durumda kalırlar.

  1. İlk DataGridView üzerine sağ tıklayın ve Sütunları Düzenle...'yi seçin.

    DataGridView sütunlarını düzenleme

  2. CategoryId Birincil anahtarı temsil eden sütunu salt okunur yapın ve Tamam'a tıklayın.

    CategoryId sütununu salt okunur yapma

  3. İkinciye DataGridView sağ tıklayın ve Sütunları Düzenle...'yi seçin. ProductId Sütunu salt okunur yapın ve ve CategoryId sütunlarını Category kaldırın, ardından Tamam'a tıklayın.

    ProductId sütununu salt okunur yapma ve CategoryId ve Category sütunlarını kaldırma

EF Core'a bağlanma

Uygulamanın artık EF Core'u veriye bağlı denetimlere bağlamak için az miktarda koda ihtiyacı vardır.

  1. Dosyaya MainForm sağ tıklayıp Kodu Görüntüle'yi seçerek kodu açın.

    Kodu Görüntüle

  2. Oturum için DbContext öğesini tutacak özel bir alan ekleyin ve OnLoad ve OnClosing yöntemleri için geçersiz kılmalar ekleyin. Kod şu şekilde görünmelidir:

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;
        }
    }
}

OnLoad Form yüklendiğinde yöntemi çağrılır. Şu anda

  • ProductsContext örneği oluşturulur ve bu örnek, uygulamanın görüntülediği ürün ve kategorilerdeki değişiklikleri yüklemek ve izlemek için kullanılacaktır.
  • EnsureCreated, SQLite veritabanını oluşturmak üzere DbContext üzerinde çağrılır, eğer henüz yoksa. Bu, uygulamaları prototip oluştururken veya test ederken veritabanı oluşturmanın hızlı bir yoludur. Ancak model değişirse veritabanının yeniden oluşturulabilmesi için silinmesi gerekir. (Uygulama EnsureDeleted çalıştırıldığında veritabanını kolayca silmek ve yeniden oluşturmak için satırın açıklaması kaldırılabilir.) Bunun yerine, veri kaybetmeden veritabanı şemasını değiştirmek ve güncelleştirmek için EF Core Migrations kullanmak isteyebilirsiniz.
  • EnsureCreated , yeni veritabanını yönteminde ProductsContext.OnModelCreating tanımlanan verilerle de doldurur.
  • Load uzantı yöntemi, veritabanındaki tüm kategorileri içine DbContextyüklemek için kullanılır. Bu varlıklar artık DbContext tarafından izlenecek ve kategoriler kullanıcı tarafından düzenlendiğinde yapılan değişiklikleri algılayacak.
  • categoryBindingSource.DataSource özelliği, DbContext tarafından izlenen kategorilere ayarlanır. Bu, Local.ToBindingList()'nin CategoriesDbSet özelliği üzerinde çağrılması ile gerçekleştirilir. Local izlenen kategorilerin yerel görünümüne erişim sağlar ve yerel verilerin görüntülenen verilerle eşitlenmiş durumda kalmasını sağlamak için olaylar bağlanmış durumdadır ve tam tersi de geçerlidir. ToBindingList() bu verileri, Windows Forms veri bağlaması tarafından anlaşılan bir IBindingListolarak kullanıma sunar.

OnClosing Form kapatıldığında yöntemi çağrılır. Şu anda, DbContext nesnesi atılır, bu da tüm veritabanı kaynaklarının serbest bırakılmasını sağlar ve dbContext alanı null olarak ayarlanır, böylece yeniden kullanılamaz.

Ürünler görünümünü doldurma

Uygulama bu noktada başlatılırsa şuna benzer olmalıdır:

Uygulamanın ilk çalıştırması

Kategorilerin veritabanından yüklendiğine, ancak ürünler tablosunun boş kaldığına dikkat edin. Ayrıca Kaydet düğmesi çalışmaz.

Ürünler tablosunu doldurmak için EF Core'un seçilen kategori için veritabanından ürün yüklemesi gerekir. Bunu başarmak için:

  1. Ana formun tasarımcısında DataGridView için kategorileri seçin.

  2. Özellikler içinde DataGridView olayları (şimşek düğmesi) seçin ve SelectionChanged olayına çift tıklayın.

    SelectionChanged olayını ekleme

    Bu, kategori seçimi her değiştiğinde tetiklenecek bir olay için ana form kodunda saplama oluşturur.

  3. Olayın kodunu doldurun:

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();
        }
    }
}

Bu kodda, etkin (null olmayan) bir DbContext oturumu varsa, şu anda seçili olan DataViewGrid satırına bağlı Category örneğini elde ederiz. Görünümdeki son satır seçili olduğunda ve yeni kategoriler oluşturmak için kullanıldığında null olabilir. Seçili bir kategori varsa, DbContext bu kategoriyle ilişkili ürünleri yüklemesi istenir. Bu işlem şu şekilde yapılır:

  • Category örneği için EntityEntry alma (dbContext.Entry(category))
  • EF Core'a, Category (.Collection(e => e.Products)) koleksiyon gezintisinde Products üzerinde çalışmak istediğimizi bildirmek
  • Ve son olarak EF Core'a bu ürün koleksiyonunu veritabanından yüklemek istediğimizi söylemek (.Load();)

İpucu

Çağrıldığında Load , EF Core yalnızca henüz yüklenmemiş olan ürünleri yüklemek için veritabanına erişir.

Uygulama şimdi yeniden çalıştırılırsa, bir kategori seçildiğinde uygun ürünleri yüklemelidir:

Ürünler yüklendi

Değişiklikler kaydediliyor

Son olarak, ürünlerde ve kategorilerde yapılan tüm değişikliklerin veritabanına kaydedilmesi için Kaydet düğmesi EF Core'a bağlanabilir.

  1. Ana formun tasarımcısında Kaydet düğmesini seçin.

  2. Özellikler içinde, olayları (şimşek düğmesi) seçin ve Click olayında çift tıklayın.

    Kaydet için Click olayını ekleme

  3. Olayın kodunu doldurun:

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

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

Bu kod, SQLite veritabanında yapılan değişiklikleri kaydeden SaveChanges öğesini DbContext üzerinde çağırır. Hiçbir değişiklik yapılmadıysa, bu işlem yapılmaz ve veritabanı çağrısı yapılmaz. Kaydettikten sonra DataGridView denetimler yenilenir. Bunun nedeni EF Core'un veritabanındaki tüm yeni ürünler ve kategoriler için oluşturulan birincil anahtar değerlerini okumasıdır. Refresh çağrıldığında, görüntü bu oluşturulan değerlerle güncellenir.

Son uygulama

Ana formun tam kodu aşağıdadır:

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();
        }
    }
}

Uygulama artık çalıştırılabilir ve ürünler ve kategoriler eklenebilir, silinebilir ve düzenlenebilir. Uygulamayı kapatmadan önce Kaydet düğmesine tıklanırsa, yapılan tüm değişikliklerin veritabanında depolanacağına ve uygulama yeniden başlatıldığında yeniden yüklendiğine dikkat edin. Kaydet'e tıklanmazsa, uygulama yeniden başlatıldığında tüm değişiklikler kaybolur.

İpucu

Denetimin en altındaki boş satır kullanılarak yeni bir DataViewControl kategori veya ürün eklenebilir. Satır seçilerek ve Del tuşuna basılarak silinebilir.

Kaydetmeden önce

Kaydet'e tıklamadan önce çalışan uygulama

Kaydettikten sonra

Kaydet'e tıkladıktan sonra çalışan uygulama

Kaydet'e tıklandığında, eklenen kategori ve ürünler için birincil anahtar değerlerinin doldurulduğunu fark edin.

Daha fazla bilgi edinin