Aracılığıyla paylaş


WPF ile veri bağlama

Önemli

Bu belge yalnızca .NET Framework'te WPF için geçerlidir

Bu belgede.NET Framework'te WPF için veri bağlama açıklanmaktadır. Yeni .NET Core projeleri için Entity Framework 6 yerine EF Core kullanmanızı öneririz. EF Core'da veri bağlama belgeleri buradadır: WPF ile Çalışmaya Başlama.

Bu adım adım izlenecek yol, POCO türlerini WPF denetimlerine "ana-ayrıntı" biçiminde bağlamayı gösterir. Uygulama, veritabanındaki verilerle nesneleri doldurmak, değişiklikleri izlemek ve verileri veritabanında kalıcı hale getirmek için Entity Framework API'lerini kullanır.

Model, bire çok ilişkisine katılan iki tür tanımlar: Kategori (sorumlu\ana) ve Ürün (bağımlı\ayrıntı). Ardından Modelde tanımlanan türleri WPF denetimlerine bağlamak için Visual Studio araçları kullanılır. WPF veri bağlama çerçevesi, ilgili nesneler arasında gezintiyi etkinleştirir: ana görünümde satırların seçilmesi, ayrıntı görünümünün ilgili alt verilerle güncelleştirilmesine neden olur.

Bu kılavuzdaki ekran görüntüleri ve kod listeleri Visual Studio 2013'ten alınmıştır, ancak bu kılavuzu Visual Studio 2012 veya Visual Studio 2010 ile tamamlayabilirsiniz.

WPF Veri Kaynakları Oluşturmak için 'Nesne' Seçeneğini Kullanma

Entity Framework'ün önceki sürümünde, EF Tasarım Aracı ile oluşturulan bir modeli temel alan yeni bir Veri Kaynağı oluştururken Veritabanı seçeneğini kullanmanızı önerirdik. Bunun nedeni tasarımcının ObjectContext'ten ve EntityObject'ten türetilen varlık sınıflarından türetilen bir bağlam oluşturmasıydı. Veritabanı seçeneğini kullanmak, bu API yüzeyiyle etkileşim için en iyi kodu yazmanıza yardımcı olur.

Visual Studio 2012 ve Visual Studio 2013 için EF Tasarım Aracı, basit POCO varlık sınıflarıyla birlikte DbContext'ten türetilen bir bağlam oluşturur. Visual Studio 2010 ile, bu kılavuzun ilerleyen bölümlerinde açıklandığı gibi DbContext kullanan bir kod oluşturma şablonuna geçiş yapmanızı öneririz.

DbContext API yüzeyini kullanırken, bu kılavuzda gösterildiği gibi yeni bir Veri Kaynağı oluştururken Nesne seçeneğini kullanmanız gerekir.

Gerekirse, EF Tasarım Aracı ile oluşturulan modeller için ObjectContext tabanlı kod oluşturma işlemine geri dönebilirsiniz.

Önkoşullar

Bu kılavuzu tamamlamak için Visual Studio 2013, Visual Studio 2012 veya Visual Studio 2010 yüklü olmalıdır.

Visual Studio 2010 kullanıyorsanız NuGet'i de yüklemeniz gerekir. Daha fazla bilgi için bkz . NuGet'i Yükleme.  

Uygulamayı Oluşturma

  • Visual Studio’yu açın
  • Dosya -> Yeni -> Project....
  • Sol bölmede Windows'a ve sağ bölmede WPFUygulama'ya tıklayın
  • Ad olarak WPFwithEFSample girin
  • Tamam'ı seçin

Entity Framework NuGet paketini yükleme

  • Çözüm Gezgini'da WinFormswithEFSample projesine sağ tıklayın
  • NuGet Paketlerini Yönet... öğesini seçin .
  • NuGet Paketlerini Yönet iletişim kutusunda Çevrimiçi sekmesini seçin ve EntityFramework paketini seçin
  • Yükle'ye tıklayın

    Dekont

    EntityFramework derlemesine ek olarak System.ComponentModel.DataAnnotations başvurusu da eklenir. Projenin System.Data.Entity başvurusu varsa, EntityFramework paketi yüklendiğinde kaldırılır. System.Data.Entity derlemesi artık Entity Framework 6 uygulamaları için kullanılmaz.

Model Tanımlama

Bu kılavuzda, Önce Kod veya EF Tasarım Aracı kullanarak bir model uygulamayı seçebilirsiniz. Aşağıdaki iki bölümden birini tamamlayın.

1. Seçenek: Önce Kod Kullanarak Model Tanımlama

Bu bölümde, Code First kullanarak modelin ve ilişkili veritabanının nasıl oluşturulacağı gösterilmektedir. EF tasarımcısını kullanarak modelinizi veritabanından tersine mühendislik uygulamak için Önce Veritabanı'nı kullanmayı tercih ediyorsanız sonraki bölüme (Seçenek 2: Önce Veritabanı kullanarak model tanımlama) atlayın

Code First geliştirmesini kullanırken genellikle kavramsal (etki alanı) modelinizi tanımlayan .NET Framework sınıfları yazarak başlarsınız.

  • WPFwithEFSample'a yeni bir sınıf ekleyin:
    • Proje adına sağ tıklayın
    • Ekle'yi ve ardından Yeni Öğe'yi seçin
    • Sınıf'ı seçin ve sınıf adı olarak Ürün girin
  • Product sınıfı tanımını aşağıdaki kodla değiştirin:
    namespace WPFwithEFSample
    {
        public class Product
        {
            public int ProductId { get; set; }
            public string Name { get; set; }

            public int CategoryId { get; set; }
            public virtual Category Category { get; set; }
        }
    }
  • Aşağıdaki tanıma sahip bir Category sınıfı ekleyin:
    using System.Collections.ObjectModel;

    namespace WPFwithEFSample
    {
        public class Category
        {
            public Category()
            {
                this.Products = new ObservableCollection<Product>();
            }

            public int CategoryId { get; set; }
            public string Name { get; set; }

            public virtual ObservableCollection<Product> Products { get; private set; }
        }
    }

Category sınıfındaki Products özelliği ve Product sınıfındaki Category özelliği gezinti özellikleridir. Entity Framework'te gezinti özellikleri, iki varlık türü arasındaki ilişkide gezinmek için bir yol sağlar.

Varlıkları tanımlamaya ek olarak, DbContext'ten türetilen ve DbSet<TEntity> özelliklerini kullanıma sunan bir sınıf tanımlamanız gerekir. DbSet<TEntity> özellikleri, bağlama modele hangi türleri eklemek istediğinizi bildirir.

DbContext türetilmiş türünün bir örneği, çalışma zamanında varlık nesnelerini yönetir. Bu, nesneleri veritabanındaki verilerle doldurma, değişiklik izleme ve verileri veritabanında kalıcı hale getirme gibi işlemleri içerir.

  • Projeye aşağıdaki tanım ile yeni bir ProductContext sınıfı ekleyin:
    using System.Data.Entity;

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

Projeyi derleyin.

2. Seçenek: Önce Veritabanı kullanarak model tanımlama

Bu bölümde, EF tasarımcısını kullanarak modelinizi veritabanından tersine mühendislik uygulamak için Önce Veritabanı'nın nasıl kullanılacağı gösterilmektedir. Önceki bölümü tamamladıysanız (Seçenek 1: Önce Kod kullanarak model tanımlama), bu bölümü atlayın ve doğrudan Gecikmeli Yükleme bölümüne gidin.

Mevcut Veritabanı Oluşturma

Genellikle mevcut bir veritabanını hedeflediğiniz zaman zaten oluşturulur, ancak bu kılavuzda erişmek için bir veritabanı oluşturmamız gerekir.

Visual Studio ile yüklenen veritabanı sunucusu, yüklediğiniz Visual Studio sürümüne bağlı olarak farklıdır:

  • Visual Studio 2010 kullanıyorsanız bir SQL Express veritabanı oluşturacaksınız.
  • Visual Studio 2012 kullanıyorsanız bir LocalDB veritabanı oluşturacaksınız.

Şimdi veritabanını oluşturalım.

  • Görünüm -> Sunucu Gezgini

  • Veri Bağlan ions -> Bağlan Ekle... öğesine sağ tıklayın

  • Veri kaynağı olarak Microsoft SQL Server'ı seçmeniz gerekmeden önce Sunucu Gezgini'nden bir veritabanına bağlanmadıysanız

    Change Data Source

  • Hangisini yüklediğinize bağlı olarak LocalDB veya SQL Express'e Bağlan ve Veritabanı adı olarak ürünler

    Add Connection LocalDB

    Add Connection Express

  • Tamam'ı seçtiğinizde yeni veritabanı oluşturmak isteyip istemediğiniz sorulur ve Evet'i seçin

    Create Database

  • Yeni veritabanı artık Sunucu Gezgini'nde görünür, sağ tıklayın ve Yeni Sorgu'yu seçin

  • Aşağıdaki SQL'i yeni sorguya kopyalayın, ardından sorguya sağ tıklayın ve Yürüt'e tıklayın

    CREATE TABLE [dbo].[Categories] (
        [CategoryId] [int] NOT NULL IDENTITY,
        [Name] [nvarchar](max),
        CONSTRAINT [PK_dbo.Categories] PRIMARY KEY ([CategoryId])
    )

    CREATE TABLE [dbo].[Products] (
        [ProductId] [int] NOT NULL IDENTITY,
        [Name] [nvarchar](max),
        [CategoryId] [int] NOT NULL,
        CONSTRAINT [PK_dbo.Products] PRIMARY KEY ([ProductId])
    )

    CREATE INDEX [IX_CategoryId] ON [dbo].[Products]([CategoryId])

    ALTER TABLE [dbo].[Products] ADD CONSTRAINT [FK_dbo.Products_dbo.Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [dbo].[Categories] ([CategoryId]) ON DELETE CASCADE

Tersine Mühendislik Modeli

Modelimizi oluşturmak için Visual Studio'nun bir parçası olan Entity Framework Tasarım Aracı kullanacağız.

  • Proje -> Yeni Öğe Ekle...

  • Sol menüden Veri'yi seçin ve ardından Varlık Veri Modeli'ni ADO.NET

  • Ad olarak ProductModel yazın ve Tamam'a tıklayın

  • Bu işlem Varlık Veri Modeli Sihirbazı'nı başlatır

  • Veritabanından Oluştur'a tıklayın ve İleri'ye tıklayın

    Choose Model Contents

  • İlk bölümde oluşturduğunuz veritabanı bağlantısını seçin, bağlantı dizesi adı olarak ProductContext yazın ve İleri'ye tıklayın

    Choose Your Connection

  • 'Tablolar' öğesinin yanındaki onay kutusuna tıklayarak tüm tabloları içeri aktarın ve 'Son'a tıklayın

    Choose Your Objects

Tersine mühendislik işlemi tamamlandıktan sonra yeni model projenize eklenir ve Entity Framework Tasarım Aracı'nde görüntülemeniz için açılır. Projenize veritabanı için bağlantı ayrıntılarıyla birlikte bir App.config dosyası da eklendi.

Visual Studio 2010'daki Ek Adımlar

Visual Studio 2010'da çalışıyorsanız EF tasarımcısını EF6 kod oluşturma özelliğini kullanacak şekilde güncelleştirmeniz gerekir.

  • EF Tasarım Aracı modelinizin boş bir noktasına sağ tıklayın ve Kod Oluşturma Öğesi Ekle... öğesini seçin.
  • Sol menüden Çevrimiçi Şablonlar'ı seçin ve DbContext araması yapın
  • C# için EF 6.x DbContext Oluşturucusunu seçin, ad olarak ProductsModel yazın ve Ekle'ye tıklayın

Veri bağlama için kod oluşturma güncelleştiriliyor

EF, T4 şablonlarını kullanarak modelinizden kod oluşturur. Visual Studio ile gönderilen veya Visual Studio galerisinden indirilen şablonlar genel amaçlı kullanıma yöneliktir. Bu, bu şablonlardan oluşturulan varlıkların basit ICollection<T> özelliklerine sahip olduğu anlamına gelir. Ancak WPF kullanarak veri bağlama yaparken, WPF'nin koleksiyonlarda yapılan değişiklikleri izleyebilmesi için koleksiyon özellikleri için ObservableCollection kullanılması tercih edilir. Bu amaçla, şablonları ObservableCollection kullanacak şekilde değiştireceğiz.

  • Çözüm Gezgini açın ve ProductModel.edmx dosyasını bulun

  • ProductModel.edmx dosyasının altına yerleştirilecek ProductModel.tt dosyasını bulun

    WPF Product Model Template

  • visual studio düzenleyicisinde açmak için ProductModel.tt dosyasına çift tıklayın

  • "ICollection" öğesinin iki oluşumunu bulun ve "ObservableCollection" ile değiştirin. Bunlar yaklaşık olarak 296 ve 484. satırlarda bulunur.

  • "HashSet" öğesinin ilk oluşumunu bulun ve "ObservableCollection" ile değiştirin. Bu oluşum yaklaşık 50. satırda bulunur. Kodda daha sonra bulunan ikinci HashSet örneğini değiştirmeyin.

  • "System.Collections.Generic" öğesinin tek oluşumunu bulun ve "System.Collections.ObjectModel" ile değiştirin. Bu, yaklaşık olarak 424. satırda bulunur.

  • ProductModel.tt dosyasını kaydedin. Bu, varlıkların kodunun yeniden üretilmesine neden olmalıdır. Kod otomatik olarak yeniden oluşturulmazsa, ProductModel.tt sağ tıklayın ve "Özel Aracı Çalıştır"ı seçin.

Şimdi Category.cs dosyasını (ProductModel.tt altında iç içe yerleştirilmiştir) açarsanız, Products koleksiyonunun ObservableCollection<Product> türünde olduğunu görmeniz gerekir.

Projeyi derleyin.

Geç Yükleme

Category sınıfındaki Products özelliği ve Product sınıfındaki Category özelliği gezinti özellikleridir. Entity Framework'te gezinti özellikleri, iki varlık türü arasındaki ilişkide gezinmek için bir yol sağlar.

EF, gezinti özelliğine ilk kez erişişiniz için veritabanından ilgili varlıkları otomatik olarak yükleme seçeneği sunar. Bu yükleme türüyle (gecikmeli yükleme olarak adlandırılır), her gezinti özelliğine ilk kez erişişinizde, içerik henüz bağlamda değilse veritabanında ayrı bir sorgu yürütüleceğini unutmayın.

POCO varlık türlerini kullanırken EF, çalışma zamanı sırasında türetilmiş proxy türlerinin örneklerini oluşturarak ve ardından yükleme kancasını eklemek için sınıflarınızdaki sanal özellikleri geçersiz kılarak yavaş yükleme sağlar. İlgili nesnelerin yavaş yüklenmesini sağlamak için, gezinti özelliği alıcılarını genel ve sanal (Visual Basic'te Geçersiz Kılınabilir) olarak bildirmeniz ve sınıfınızın korumalı olmaması gerekir (Visual Basic'te NotOverridable). İlk Veritabanı gezinti özellikleri kullanılırken yavaş yüklemeyi etkinleştirmek için otomatik olarak sanal hale getirilir. İlk Kod bölümünde gezinti özelliklerini aynı nedenle sanal hale getirmeyi seçtik.

Nesneyi Denetimlere Bağlama

Modelde tanımlanan sınıfları bu WPF uygulaması için veri kaynakları olarak ekleyin.

  • Ana formu açmak için Çözüm Gezgini mainWindow.xaml öğesine çift tıklayın

  • Ana menüden Proje -> Yeni Veri Kaynağı Ekle ... öğesini seçin (Visual Studio 2010'da Veri -> Yeni Veri Kaynağı Ekle...) seçeneğini belirlemeniz gerekir

  • Veri Kaynağı Seçin Türüwindow'da Nesne'yi seçin ve İleri'ye tıklayın

  • Veri Nesnelerini Seç iletişim kutusunda WPFwithEFSample'ı iki kez açın ve Kategori'yi seçin
    Ürün veri kaynağını seçmenize gerek yoktur, çünkü kategori veri kaynağındaki Ürün özelliği aracılığıyla bu kaynağa ulaşacağız

    Select Data Objects

  • Finish (Son) düğmesine tıklayın.

  • Veri Kaynakları penceresi MainWindow.xaml penceresinin yanında açılır Veri Kaynakları penceresi gösterilmiyorsa Görünüm -> Diğer Windows-> Veri Kaynakları'nı seçin

  • Veri Kaynakları penceresinin otomatik olarak gizlenmemesi için raptiye simgesine basın. Pencere zaten görünür durumdaysa yenile düğmesine basmanız gerekebilir.

    Data Sources

  • Kategori veri kaynağını seçin ve formda sürükleyin.

Bu kaynağı sürüklediğimizde aşağıdakiler oldu:

  • categoryViewSource kaynağı ve categoryDataGrid denetimi XAML'ye eklendi
  • Üst Kılavuz öğesindeki DataContext özelliği "{StaticResource categoryViewSource }" olarak ayarlandı. categoryViewSource kaynağı, outer\parent Grid öğesi için bağlama kaynağı görevi görür. İç Kılavuz öğeleri daha sonra üst Kılavuzdan DataContext değerini devralır (categoryDataGrid'in ItemsSource özelliği "{Binding}" olarak ayarlanır)
    <Window.Resources>
        <CollectionViewSource x:Key="categoryViewSource"
                                d:DesignSource="{d:DesignInstance {x:Type local:Category}, CreateList=True}"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource categoryViewSource}">
        <DataGrid x:Name="categoryDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True"
                    ItemsSource="{Binding}" Margin="13,13,43,191"
                    RowDetailsVisibilityMode="VisibleWhenSelected">
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="categoryIdColumn" Binding="{Binding CategoryId}"
                                    Header="Category Id" Width="SizeToHeader"/>
                <DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}"
                                    Header="Name" Width="SizeToHeader"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

Ayrıntılar Kılavuzu Ekleme

Artık Kategorileri görüntülemek için bir kılavuzumuz olduğuna göre, ilişkili Ürünleri görüntülemek için bir ayrıntı kılavuzu ekleyelim.

  • Kategori veri kaynağının altından Products özelliğini seçin ve formda sürükleyin.
    • categoryProductsViewSource kaynağı ve productDataGrid kılavuzu XAML'ye eklenir
    • Bu kaynağın bağlama yolu Ürünler olarak ayarlanmış
    • WPF veri bağlama çerçevesi, productDataGrid'de yalnızca seçili Kategoriyle ilgili Ürünlerin gösterilmesini sağlar
  • Araç Kutusu'ndan Düğme'yi forma sürükleyin. Name özelliğini buttonSave ve Content özelliğini Kaydet olarak ayarlayın.

Form şuna benzer görünmelidir:

Designer Form

Veri Etkileşimlerini İşleyen Kod Ekleme

Ana pencereye bazı olay işleyicileri eklemenin zamanı geldi.

  • XAML penceresinde Window öğesine tıklayın<; bu işlem ana pencereyi seçer

  • Özellikler penceresinde sağ üstteki Olaylar'ı seçin, ardından Yüklenen etiketinin sağındaki metin kutusuna çift tıklayın

    Main Window Properties

  • Ayrıca, tasarımcıda Kaydet düğmesine çift tıklayarak Kaydet düğmesinin Click olayını ekleyin.

Bu sizi formun arkasındaki koda getirir; şimdi veri erişimi gerçekleştirmek için ProductContext'i kullanacak şekilde kodu düzenleyeceğiz. MainWindow kodunu aşağıda gösterildiği gibi güncelleştirin.

Kod, ProductContext'in uzun süre çalışan bir örneğini bildirir. ProductContext nesnesi, verileri sorgulamak ve veritabanına kaydetmek için kullanılır. ProductContext örneğindeki Dispose() daha sonra geçersiz kılınan OnClosing yönteminden çağrılır. Kod açıklamaları, kodun ne yaptığı hakkında ayrıntılar sağlar.

    using System.Data.Entity;
    using System.Linq;
    using System.Windows;

    namespace WPFwithEFSample
    {
        public partial class MainWindow : Window
        {
            private ProductContext _context = new ProductContext();
            public MainWindow()
            {
                InitializeComponent();
            }

            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                System.Windows.Data.CollectionViewSource categoryViewSource =
                    ((System.Windows.Data.CollectionViewSource)(this.FindResource("categoryViewSource")));

                // Load is an extension method on IQueryable,
                // defined in the System.Data.Entity namespace.
                // This method enumerates the results of the query,
                // similar to ToList but without creating a list.
                // When used with Linq to Entities this method
                // creates entity objects and adds them to the context.
                _context.Categories.Load();

                // After the data is loaded call the DbSet<T>.Local property
                // to use the DbSet<T> as a binding source.
                categoryViewSource.Source = _context.Categories.Local;
            }

            private void buttonSave_Click(object sender, RoutedEventArgs e)
            {
                // When you delete an object from the related entities collection
                // (in this case Products), the Entity Framework doesn’t mark
                // these child entities as deleted.
                // Instead, it removes the relationship between the parent and the child
                // by setting the parent reference to null.
                // So we manually have to delete the products
                // that have a Category reference set to null.

                // The following code uses LINQ to Objects
                // against the Local collection of Products.
                // The ToList call is required because otherwise the collection will be modified
                // by the Remove call while it is being enumerated.
                // In most other situations you can use LINQ to Objects directly
                // against the Local property without using ToList first.
                foreach (var product in _context.Products.Local.ToList())
                {
                    if (product.Category == null)
                    {
                        _context.Products.Remove(product);
                    }
                }

                _context.SaveChanges();
                // Refresh the grids so the database generated values show up.
                this.categoryDataGrid.Items.Refresh();
                this.productsDataGrid.Items.Refresh();
            }

            protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
            {
                base.OnClosing(e);
                this._context.Dispose();
            }
        }

    }

WPF Uygulamasını Test Edin

  • Uygulamayı derleyin ve çalıştırın. Code First kullandıysanız sizin için bir WPFwithEFSample.ProductContext veritabanı oluşturulduğunu görürsünüz.

  • Üst kılavuza bir kategori adı girin ve alt kılavuzdaki ürün adları Birincil anahtar veritabanı tarafından oluşturulduğundan Kimlik sütunlarına hiçbir şey girmeyin

    Main Window with new categories and products

  • Verileri veritabanına kaydetmek için Kaydet düğmesine basın

DbContext'in SaveChanges() çağrısından sonra, kimlikler veritabanı tarafından oluşturulan değerlerle doldurulur. SaveChanges() sonrasında Refresh() adını aldığımız için DataGrid denetimleri de yeni değerlerle güncelleştirilir.

Main Window with IDs populated

Ek Kaynaklar

WPF kullanarak koleksiyonlara veri bağlama hakkında daha fazla bilgi edinmek için WPF belgelerinde bu konuya bakın.