WPF ve Entity Framework 6 kullanarak basit veri uygulaması oluşturma

Uyarı

Visual Studio 2022 kullanıyorsanız, bu öğretici için Visual Studio 2022 sürüm 17.3 Preview 3 veya üzerini kullanmalısınız.

Bu kılavuz, Visual Studio'da temel bir "veri üzerinde formlar" uygulamasının nasıl oluşturulacağını gösterir. Uygulama SQL Server LocalDB, Northwind veritabanı, Entity Framework 6 (Entity Framework Core değil) ve .NET Framework için Windows Presentation Foundation (.NET Core veya .NET 5 veya üzeri değil) kullanır. Ana ayrıntı görünümüyle temel veri bağlamanın nasıl yapılacağını gösterir ve ayrıca Sonrakini Taşı, Öncekini Taşı, Başa taşı, Sona taşı, Güncelleştir ve Sil düğmelerine sahip özel bir Bağlama Gezgini'ne sahiptir.

Bu makale, Visual Studio'da veri araçlarını kullanmaya odaklanır ve temel alınan teknolojileri ayrıntılı olarak açıklamaya çalışmaz. XAML, Entity Framework ve SQL hakkında temel bir bilginiz olduğu varsayılır. Bu örnekte WPF uygulamaları için standart olan Model-View-ViewModel (MVVM) mimarisi de gösterilmez. Ancak, bu kodu birkaç değişiklikle kendi MVVM uygulamanıza kopyalayabilirsiniz.

Bu öğreticinin son kodunu Visual Studio Öğretici Örnekleri - EF6'daki GitHub'da bulabilirsiniz.

Northwind'i yükleme ve northwind'e bağlanma

Bu örnekte SQL Server Express LocalDB ve Northwind örnek veritabanı kullanılmaktadır. Bu ürünün ADO.NET veri sağlayıcısı Entity Framework'i destekliyorsa, diğer SQL veritabanı ürünleriyle de çalışmalıdır.

  1. SQL Server Express LocalDB'niz yoksa Visual Studio Yükleyicisi aracılığıyla yükleyin. Visual Studio Yükleyicisi, SQL Server Express LocalDB'yi Veri depolama ve işleme iş yükünün bir parçası olarak veya tek bir bileşen olarak yükleyebilirsiniz.

  2. Aşağıdaki adımları izleyerek Northwind örnek veritabanını yükleyin:

    1. Visual Studio'da SQL Server Nesne Gezgini penceresini açın. (SQL Server Nesne Gezgini, Visual Studio Yükleyicisi Veri depolama ve işleme iş yükünün bir parçası olarak yüklenir.) SQL Server düğümünü genişletin. LocalDB örneğinize sağ tıklayın ve Yeni Sorgu'yu seçin.

      Sorgu düzenleyicisi penceresi açılır.

    2. Northwind Transact-SQL betiğini panonuza kopyalayın. Bu T-SQL betiği, Northwind veritabanını sıfırdan oluşturur ve verilerle doldurur.

    3. T-SQL betiğini sorgu düzenleyicisine yapıştırın ve ardından Yürüt düğmesini seçin.

      Kısa bir süre sonra sorgunun çalışması tamamlanır ve Northwind veritabanı oluşturulur.

  3. Northwind için yeni bağlantılar ekleyin.

Projeyi yapılandırma

  1. Visual Studio'da yeni bir C# WPF Uygulaması (.NET Framework) projesi oluşturun.

  2. Entity Framework 6 için NuGet paketini ekleyin. Çözüm Gezgini'da proje düğümünü seçin. Ana menüde NuGet Paketlerini Proje>Yönet'i seçin.

  3. NuGet Paket Yöneticisi Gözat bağlantısına tıklayın. Entity Framework muhtemelen listedeki en önemli pakettir. Sağ bölmede Yükle'ye tıklayın ve istemleri izleyin. Çıkış penceresi, yüklemenin ne zaman bittiğini bildirir.

    Entity Framework NuGet Paketi NuGet paketinin ekran görüntüsü.

    Entity Framework NuGet Paketini gösteren ekran görüntüsü.

  4. Artık Northwind veritabanını temel alan bir model oluşturmak için Visual Studio'yu kullanabilirsiniz.

Modeli oluşturma

  1. Çözüm Gezgini'da proje düğümüne sağ tıklayın ve Yeni Öğe Ekle'yi> seçin. Sol bölmede, C# düğümü altında Veri'yi seçin ve orta bölmede Varlık Veri Modeli'ni ADO.NET seçin.

    Entity Framework Modeli Yeni Öğesi'nin ekran görüntüsü.

    Entity Framework Modeli Yeni Öğesi'nin ekran görüntüsü.

  2. Modeli Northwind_model çağırın ve Ekle'yi seçin. Varlık Veri Modeli Sihirbazı açılır. Veritabanından EF Tasarım Aracı'yi seçin ve İleri'ye tıklayın.

    Veritabanından EF Modeli'nin ekran görüntüsü.

  3. Sonraki ekranda LocalDB Northwind bağlantınızı seçin (örneğin, (localdb)\MSSQLLocalDB), Northwind veritabanını belirtin ve İleri'ye tıklayın.

    Bağlantı görmüyorsanız, Yeni Bağlan ion'u seçin, ardından Veri Kaynağı Seç iletişim kutusunda Microsoft SQL Server'ı seçin, Devam'ı seçin ve Bağlan ion Özellikleri iletişim kutusunda Veritabanı (localdb)\MSSQLLocalDB adı seçin veya girin'in altına Northwind'i seçin, ardından Tamam'a basın.

  4. İstenirse, kullanmakta olduğunuz Entity Framework sürümünü seçin.

    Sürüm seçeneklerini gösteren ekran görüntüsü.

  5. Sihirbazın sonraki sayfasında, Entity Framework modeline eklenecek tabloları, saklı yordamları ve diğer veritabanı nesnelerini seçin. Ağaç görünümünde dbo düğümünü genişletin ve Müşteriler, Siparişler ve Sipariş Ayrıntıları'nı seçin. Varsayılan değerleri işaretli bırakın ve Son'a tıklayın.

    Model için veritabanı Nesnelerini seçme işleminin ekran görüntüsü.

  6. Sihirbaz, Entity Framework modelini temsil eden C# sınıflarını oluşturur. Sınıflar düz eski C# sınıflarıdır ve WPF kullanıcı arabirimine veri bağlamamız gereken sınıflardır. Dosya, .edmx sınıfları veritabanındaki nesnelerle ilişkilendiren ilişkileri ve diğer meta verileri açıklar. Dosyalar .tt , model üzerinde çalışan kodu oluşturan ve değişiklikleri veritabanına kaydeden T4 şablonlarıdır. Tüm bu dosyaları Northwind_model düğüm altında Çözüm Gezgini görebilirsiniz:

    Çözüm Gezgini Entity Framework model dosyalarını gösteren ekran görüntüsü.

    Çözüm Gezgini Entity Framework model dosyalarını gösteren ekran görüntüsü

    Dosyanın tasarımcı yüzeyi .edmx , modeldeki bazı özellikleri ve ilişkileri değiştirmenize olanak tanır. Bu kılavuzda tasarımcıyı kullanmayacağız.

  7. Dosyalar .tt genel amaçlıdır ve ObservableCollections gerektiren WPF veri bağlama ile çalışmak için bunlardan birini ayarlamanız gerekir. Çözüm Gezgini'da Northwind_model.tt dosyasını bulana kadar Northwind_model düğümünü genişletin. (Dosyanın hemen altındaki .edmx .Context.tt dosyasında olmadığınıza emin olun.)

  8. Projeyi derlemek ve çalıştırmak için F5 veya Ctrl+F5 tuşlarına basın. Uygulama ilk kez çalıştırıldığında, model sınıfları veri kaynakları sihirbazı tarafından görülebilir.

Artık verileri görüntüleyebilmeniz, gezinebilmeniz ve değiştirebilmeniz için bu modeli XAML sayfasına bağlamaya hazırsınız.

Modeli XAML sayfasına bağlama

Kendi veri bağlama kodunuzu yazmak mümkündür, ancak bunu Sizin yerinize Visual Studio'nun yapmasına izin vermek çok daha kolaydır.

  1. Ana menüden Proje>Yeni veri kaynağı ekle'yi seçerek Veri Kaynağı Yapılandırma Sihirbazı'nı açın. Veritabanını değil model sınıflarını bağladığınız için Nesne'yi seçin:

    Nesne Kaynağı ile Veri Kaynağı Yapılandırma Sihirbazı'nın ekran görüntüsü.

  2. Projenizin düğümünü genişletin ve Müşteri'yi seçin. (Sipariş kaynakları, Müşteri'deki Siparişler gezinti özelliğinden otomatik olarak oluşturulur.)

    Varlık sınıflarını veri kaynağı olarak eklemeyi gösteren ekran görüntüsü.

    Varlık sınıflarını veri kaynağı olarak eklemeyi gösteren ekran görüntüsü.

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

  4. Kod Görünümü'nde MainWindow.xaml'e gidin. XAML'yi bu örneğin amaçları doğrultusunda basit tutuyoruz. MainWindow'un başlığını daha açıklayıcı bir şekilde değiştirin ve Yükseklik ve Genişlik değerini şimdilik 600 x 800 olarak artırın. Daha sonra istediğiniz zaman değiştirebilirsiniz. Şimdi bu üç satır tanımını ana kılavuza ekleyin; gezinti düğmeleri için bir satır, müşterinin ayrıntıları için bir satır ve siparişlerini gösteren kılavuz için bir satır:

        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
  5. Şimdi MainWindow.xaml dosyasını açarak tasarımcıda görüntülemenizi sağlayın. Bu, Veri Kaynakları penceresinin Araç Kutusu'ndaki Visual Studio pencere kenar boşluğunda bir seçenek olarak görünmesine neden olur. Pencereyi açmak için sekmeye tıklayın veya Shift Alt+D tuşuna+basın veya Diğer Windows>Veri Kaynaklarını Görüntüle'yi>seçin. Customers sınıfındaki her özelliği kendi metin kutusunda görüntüleyeceğiz. İlk olarak, Müşteriler birleşik giriş kutusundaki oka tıklayın ve Ayrıntılar'ı seçin. Ardından, tasarımcının orta satıra gitmesini istediğinizi bilmesi için düğümü tasarım yüzeyinin orta kısmına sürükleyin. Yanlış yerleştirdiyseniz, satırı daha sonra XAML' de (Grid.Row="1" ) el ile belirtebilirsiniz. Varsayılan olarak, denetimler bir kılavuz öğesine dikey olarak yerleştirilir, ancak bu noktada, formda istediğiniz gibi düzenleyebilirsiniz. Örneğin, Ad metin kutusunu adresin üstüne yerleştirmek mantıklı olabilir. Bu makalenin örnek uygulaması alanları yeniden sıralar ve iki sütun halinde yeniden düzenler.

    Müşteriler veri kaynağı bağlamasını tek tek denetimlere gösteren ekran görüntüsü.

    Müşteriler veri kaynağı bağlamasını tek tek denetimlere gösteren ekran görüntüsü.

    XAML görünümünde artık üst Kılavuzun 1. satırında (orta satır) yeni Grid bir öğe görebilirsiniz. Üst Kılavuz, öğesine eklenmiş olan öğesine başvuran bir DataContextCollectionViewSource özniteliğine Windows.Resources sahiptir. Bu veri bağlamı göz önünde bulundurulduğunda, ilk metin kutusu Adres'e bağlandığında, bu ad içindeki CollectionViewSourcegeçerli Customer nesnedeki özelliğe eşlenirAddress.

    <Grid DataContext="{StaticResource customerViewSource}">
    
  6. Bir müşteri pencerenin üst yarısında görünür olduğunda, siparişlerini alt yarısında görmek istersiniz. Siparişleri tek bir kılavuz görünümü denetiminde gösterirsiniz. Ana ayrıntı veri bağlamanın beklendiği gibi çalışması için, ayrı Siparişler düğümüne değil Customers sınıfındaki Orders özelliğine bağlamanız önemlidir. Tasarımcının 2. satıra koyabilmesi için Customers sınıfının Orders özelliğini formun alt yarısına sürükleyin:

    Kılavuz olarak sürüklenen ve bırakılan Sipariş sınıflarını gösteren ekran görüntüsü.

    Kılavuz olarak sürüklenen ve bırakılan Sipariş sınıflarını gösteren ekran görüntüsü.

  7. Visual Studio, kullanıcı arabirimi denetimlerini modeldeki olaylara bağlayan tüm bağlama kodunu oluşturdu. Bazı verileri görmek için yapmanız gereken tek şey modeli doldurmak için kod yazmaktır. İlk olarak MainWindow.xaml.cs gidin ve veri bağlamı için MainWindow sınıfına bir veri üyesi ekleyin. Sizin için oluşturulan bu nesne, modeldeki değişiklikleri ve olayları izleyen bir denetim gibi davranır. Ayrıca müşteriler ve siparişler için CollectionViewSource veri üyelerini ve ilişkili oluşturucu başlatma mantığını mevcut oluşturucuya MainWindow()ekleyeceksiniz. Sınıfın üst kısmı şöyle görünmelidir:

    public partial class MainWindow : Window
    {
        NorthwindEntities context = new NorthwindEntities();
        CollectionViewSource custViewSource;
        CollectionViewSource ordViewSource;
    
        public MainWindow()
        {
            InitializeComponent();
            custViewSource = ((CollectionViewSource)(FindResource("customerViewSource")));
            ordViewSource = ((CollectionViewSource)(FindResource("customerOrdersViewSource")));
            DataContext = this;
        }
    

    Henüz orada değilse, uzantı yöntemini kapsama getirmek Load için System.Data.Entity için bir using yönerge ekleyin:

    using System.Data.Entity;
    

    Şimdi aşağı kaydırın ve olay işleyicisini Window_Loaded bulun. Visual Studio'nun bir CollectionViewSource nesnesi eklediğine dikkat edin. Bu, modeli oluştururken seçtiğiniz NorthwindEntities nesnesini temsil eder. Bunu zaten eklediniz, bu nedenle buraya ihtiyacınız yok. Şimdi yönteminin şu şekilde görünmesi için içindeki Window_Loaded kodu değiştirelim:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // 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.Customers.Load();
    
        // After the data is loaded, call the DbSet<T>.Local property    
        // to use the DbSet<T> as a binding source.   
        custViewSource.Source = context.Customers.Local;
    }
    
  8. F5 tuşuna basın. CollectionViewSource'a alınan ilk müşterinin ayrıntılarını görmeniz gerekir. Ayrıca, bunların siparişlerini veri kılavuzunda da görmeniz gerekir. Biçimlendirme harika olmadığından bunu düzeltelim. Ayrıca diğer kayıtları görüntülemenin ve temel oluşturma, okuma, güncelleştirme ve silme (CRUD) işlemlerini gerçekleştirmenin bir yolunu da oluşturabilirsiniz.

Sayfa tasarımını ayarlama ve yeni müşteriler ve siparişler için kılavuzlar ekleme

Visual Studio tarafından üretilen varsayılan düzenleme uygulamanız için ideal değildir, bu nedenle kodunuz içine kopyalamak için burada son XAML'yi sağlayacağız. Ayrıca, kullanıcının yeni bir müşteri veya sipariş eklemesini sağlamak için bazı "formlara" (aslında Kılavuzlar) ihtiyacınız vardır. Yeni müşteri ve sipariş ekleyebilmek için, veriye bağlı olmayan ayrı bir metin kutusu kümesine CollectionViewSourceihtiyacınız vardır. İşleyici yöntemlerinde Visible özelliğini ayarlayarak kullanıcının herhangi bir zamanda hangi kılavuzu göreceğini denetleyebilirsiniz. Son olarak, kullanıcının tek bir siparişi silmesini sağlamak için Siparişler kılavuzundaki her satıra bir Sil düğmesi eklersiniz.

İlk olarak, MainWindow.xaml dosyasındaki Windows.Resourcesöğesine şu stilleri ekleyin:

<Style x:Key="Label" TargetType="{x:Type Label}" BasedOn="{x:Null}">
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Margin" Value="3"/>
    <Setter Property="Height" Value="23"/>
</Style>
<Style x:Key="CustTextBox" TargetType="{x:Type TextBox}" BasedOn="{x:Null}">
    <Setter Property="HorizontalAlignment" Value="Right"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Margin" Value="3"/>
    <Setter Property="Height" Value="26"/>
    <Setter Property="Width" Value="120"/>
</Style>

Ardından, dış Kılavuz'un tamamını şu işaretlemeyle değiştirin:

<Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="auto"/>
         <RowDefinition Height="auto"/>
         <RowDefinition Height="*"/>
     </Grid.RowDefinitions>
     <Grid x:Name="existingCustomerGrid" Grid.Row="1" HorizontalAlignment="Left" Margin="5" Visibility="Visible" VerticalAlignment="Top" Background="AntiqueWhite" DataContext="{StaticResource customerViewSource}">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="Customer ID:" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="customerIDTextBox" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Company Name:" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="companyNameTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact Name:" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="contactNameTextBox" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact title:" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="contactTitleTextBox" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Address:" Grid.Row="4" Style="{StaticResource Label}"/>
         <TextBox x:Name="addressTextBox" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="City:" Grid.Column="1" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="cityTextBox" Grid.Column="1" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Country:" Grid.Column="1" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="countryTextBox" Grid.Column="1" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Fax:" Grid.Column="1" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="faxTextBox" Grid.Column="1" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Phone:" Grid.Column="1" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="phoneTextBox" Grid.Column="1" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Postal Code:" Grid.Column="1" Grid.Row="4" VerticalAlignment="Center" Style="{StaticResource Label}"/>
         <TextBox x:Name="postalCodeTextBox" Grid.Column="1" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Region:" Grid.Column="1" Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="regionTextBox" Grid.Column="1" Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <Grid x:Name="newCustomerGrid" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=newCustomer, UpdateSourceTrigger=Explicit}" Visibility="Collapsed" Background="CornflowerBlue">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="Customer ID:" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_customerIDTextBox" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Company Name:" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_companyNameTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }"/>
         <Label Content="Contact Name:" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_contactNameTextBox" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact title:" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_contactTitleTextBox" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Address:" Grid.Row="4" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_addressTextBox" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="City:" Grid.Column="1" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_cityTextBox" Grid.Column="1" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Country:" Grid.Column="1" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_countryTextBox" Grid.Column="1" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Fax:" Grid.Column="1" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_faxTextBox" Grid.Column="1" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Phone:" Grid.Column="1" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_phoneTextBox" Grid.Column="1" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Postal Code:" Grid.Column="1" Grid.Row="4" VerticalAlignment="Center" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_postalCodeTextBox" Grid.Column="1" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Region:" Grid.Column="1" Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_regionTextBox" Grid.Column="1" Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <Grid x:Name="newOrderGrid" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" DataContext="{Binding Path=newOrder, Mode=TwoWay}" Visibility="Collapsed" Background="LightGreen">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="New Order Form" FontWeight="Bold"/>
         <Label Content="Employee ID:"  Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_employeeIDTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding EmployeeID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Order Date:"  Grid.Row="2" Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_orderDatePicker" Grid.Row="2"  HorizontalAlignment="Right" Width="120"
                 SelectedDate="{Binding OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Required Date:" Grid.Row="3" Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_requiredDatePicker" Grid.Row="3" HorizontalAlignment="Right" Width="120"
                  SelectedDate="{Binding RequiredDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Shipped Date:"  Grid.Row="4"  Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_shippedDatePicker"  Grid.Row="4"  HorizontalAlignment="Right" Width="120"
                 SelectedDate="{Binding ShippedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Ship Via:"  Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_ShipViaTextBox"  Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding ShipVia, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Freight"  Grid.Row="6" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_freightTextBox" Grid.Row="6" Style="{StaticResource CustTextBox}"
                  Text="{Binding Freight, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <DataGrid x:Name="ordersDataGrid" SelectionUnit="Cell" SelectionMode="Single" AutoGenerateColumns="False" CanUserAddRows="false" IsEnabled="True" EnableRowVirtualization="True" Width="auto" ItemsSource="{Binding Source={StaticResource customerOrdersViewSource}}" Margin="10,10,10,10" Grid.Row="2" RowDetailsVisibilityMode="VisibleWhenSelected">
         <DataGrid.Columns>
             <DataGridTemplateColumn>
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <Button Content="Delete" Command="{StaticResource DeleteOrderCommand}" CommandParameter="{Binding}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding CustomerID}" Header="Customer ID" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="employeeIDColumn" Binding="{Binding EmployeeID}" Header="Employee ID" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="freightColumn" Binding="{Binding Freight}" Header="Freight" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="orderDateColumn" Header="Order Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="orderIDColumn" Binding="{Binding OrderID}" Header="Order ID" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="requiredDateColumn" Header="Required Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding RequiredDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="shipAddressColumn" Binding="{Binding ShipAddress}" Header="Ship Address" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipCityColumn" Binding="{Binding ShipCity}" Header="Ship City" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipCountryColumn" Binding="{Binding ShipCountry}" Header="Ship Country" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipNameColumn" Binding="{Binding ShipName}" Header="Ship Name" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="shippedDateColumn" Header="Shipped Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding ShippedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="shipPostalCodeColumn" Binding="{Binding ShipPostalCode}" Header="Ship Postal Code" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipRegionColumn" Binding="{Binding ShipRegion}" Header="Ship Region" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipViaColumn" Binding="{Binding ShipVia}" Header="Ship Via" Width="SizeToHeader"/>
         </DataGrid.Columns>
     </DataGrid>
 </Grid>

Gezinmek, eklemek, güncelleştirmek ve silmek için düğme ekleme

Windows Forms uygulamalarında, veritabanındaki satırlarda gezinmek ve temel CRUD işlemleri yapmak için düğmeler içeren bir BindingNavigator nesnesi alırsınız. WPF BindingNavigator sağlamaz, ancak bir tane oluşturmak yeterince kolaydır. Bunu yatay bir StackPanel içindeki düğmelerle yapar ve düğmeleri arkadaki koddaki yöntemlere bağlı Komutlar ile ilişkilendirirsiniz.

Komut mantığının dört bölümü vardır: (1) komutlar, (2) bağlamalar, (3) düğmeler ve (4) arka planda komut işleyicileri.

XAML'de komut, bağlama ve düğme ekleme

  1. İlk olarak, mainwindow.xaml dosyasındaki komutları öğesinin Windows.Resources içine ekleyin:

    <RoutedUICommand x:Key="FirstCommand" Text="First"/>
    <RoutedUICommand x:Key="LastCommand" Text="Last"/>
    <RoutedUICommand x:Key="NextCommand" Text="Next"/>
    <RoutedUICommand x:Key="PreviousCommand" Text="Previous"/>
    <RoutedUICommand x:Key="DeleteCustomerCommand" Text="Delete Customer"/>
    <RoutedUICommand x:Key="DeleteOrderCommand" Text="Delete Order"/>
    <RoutedUICommand x:Key="UpdateCommand" Text="Update"/>
    <RoutedUICommand x:Key="AddCommand" Text="Add"/>
    <RoutedUICommand x:Key="CancelCommand" Text="Cancel"/>
    
  2. CommandBinding, bir RoutedUICommand olayı arkasındaki koddaki bir yöntemle eşler. Bu CommandBindings öğeyi kapanış etiketinden Windows.Resources sonra ekleyin:

    <Window.CommandBindings>
        <CommandBinding Command="{StaticResource FirstCommand}" Executed="FirstCommandHandler"/>
        <CommandBinding Command="{StaticResource LastCommand}" Executed="LastCommandHandler"/>
        <CommandBinding Command="{StaticResource NextCommand}" Executed="NextCommandHandler"/>
        <CommandBinding Command="{StaticResource PreviousCommand}" Executed="PreviousCommandHandler"/>
        <CommandBinding Command="{StaticResource DeleteCustomerCommand}" Executed="DeleteCustomerCommandHandler"/>
        <CommandBinding Command="{StaticResource DeleteOrderCommand}" Executed="DeleteOrderCommandHandler"/>
        <CommandBinding Command="{StaticResource UpdateCommand}" Executed="UpdateCommandHandler"/>
        <CommandBinding Command="{StaticResource AddCommand}" Executed="AddCommandHandler"/>
        <CommandBinding Command="{StaticResource CancelCommand}" Executed="CancelCommandHandler"/>
    </Window.CommandBindings>
    
  3. Şimdi gezinti, ekleme, silme ve güncelleştirme düğmeleriyle öğesini ekleyin StackPanel . İlk olarak, bu stili öğesine Windows.Resourcesekleyin:

    <Style x:Key="NavButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
        <Setter Property="FontSize" Value="24"/>
        <Setter Property="FontFamily" Value="Segoe UI Symbol"/>
        <Setter Property="Margin" Value="2,2,2,0"/>
        <Setter Property="Width" Value="40"/>
        <Setter Property="Height" Value="auto"/>
    </Style>
    

    İkincisi, bu kodu dış Grid öğe için öğesinin hemen arkasınaRowDefinitions, XAML sayfasının üst kısmına yapıştırın:

    <StackPanel Orientation="Horizontal" Margin="2,2,2,0" Height="36" VerticalAlignment="Top" Background="Gainsboro" DataContext="{StaticResource customerViewSource}" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
        <Button Name="btnFirst" Content="|◄" Command="{StaticResource FirstCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnPrev" Content="◄" Command="{StaticResource PreviousCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnNext" Content="►" Command="{StaticResource NextCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnLast" Content="►|" Command="{StaticResource LastCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnDelete" Content="Delete Customer" Command="{StaticResource DeleteCustomerCommand}" FontSize="11" Width="120" Style="{StaticResource NavButton}"/>
        <Button Name="btnAdd" Content="New Customer" Command="{StaticResource AddCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
        <Button Content="New Order" Name="btnNewOrder" FontSize="11" Width="80" Style="{StaticResource NavButton}" Click="NewOrder_click"/>
        <Button Name="btnUpdate" Content="Commit" Command="{StaticResource UpdateCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
        <Button Content="Cancel" Name="btnCancel" Command="{StaticResource CancelCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
    </StackPanel>
    

MainWindow sınıfına komut işleyicileri ekleme

Ekleme ve silme yöntemleri dışında arka planda kod çok azdır. Gezinti, CollectionViewSource'un View özelliğinde yöntemler çağrılarak gerçekleştirilir. , DeleteOrderCommandHandler bir siparişte art arda silme işleminin nasıl yapılacağını gösterir. Önce kendisiyle ilişkilendirilmiş Order_Details silmemiz gerekir. koleksiyona UpdateCommandHandler yeni bir müşteri veya sipariş ekler ya da mevcut bir müşteriyi veya siparişi kullanıcının metin kutularında yaptığı değişikliklerle güncelleştirir.

Bu işleyici yöntemlerini MainWindow.xaml.cs'daki MainWindow sınıfına ekleyin. Müşteriler için CollectionViewSource tablonuzun farklı bir adı varsa, bu yöntemlerin her birinde adı ayarlamanız gerekir:

private void LastCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    custViewSource.View.MoveCurrentToLast();
}

private void PreviousCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    custViewSource.View.MoveCurrentToPrevious();
}

private void NextCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    custViewSource.View.MoveCurrentToNext();
}

private void FirstCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    custViewSource.View.MoveCurrentToFirst();
}

private void DeleteCustomerCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    // If existing window is visible, delete the customer and all their orders.  
    // In a real application, you should add warnings and allow the user to cancel the operation.  
    var cur = custViewSource.View.CurrentItem as Customer;

    var cust = (from c in context.Customers
                where c.CustomerID == cur.CustomerID
                select c).FirstOrDefault();

    if (cust != null)
    {
        foreach (var ord in cust.Orders.ToList())
        {
            Delete_Order(ord);
        }
        context.Customers.Remove(cust);
    }
    context.SaveChanges();
    custViewSource.View.Refresh();
}

// Commit changes from the new customer form, the new order form,  
// or edits made to the existing customer form.  
private void UpdateCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    if (newCustomerGrid.IsVisible)
    {
        // Create a new object because the old one  
        // is being tracked by EF now.  
        Customer newCustomer = new Customer
        {
            Address = add_addressTextBox.Text,
            City = add_cityTextBox.Text,
            CompanyName = add_companyNameTextBox.Text,
            ContactName = add_contactNameTextBox.Text,
            ContactTitle = add_contactTitleTextBox.Text,
            Country = add_countryTextBox.Text,
            CustomerID = add_customerIDTextBox.Text,
            Fax = add_faxTextBox.Text,
            Phone = add_phoneTextBox.Text,
            PostalCode = add_postalCodeTextBox.Text,
            Region = add_regionTextBox.Text
        };

        // Perform very basic validation  
        if (newCustomer.CustomerID.Length == 5)
        {
            // Insert the new customer at correct position:  
            int len = context.Customers.Local.Count();
            int pos = len;
            for (int i = 0; i < len; ++i)
            {
                if (String.CompareOrdinal(newCustomer.CustomerID, context.Customers.Local[i].CustomerID) < 0)
                {
                    pos = i;
                    break;
                }
            }
            context.Customers.Local.Insert(pos, newCustomer);
            custViewSource.View.Refresh();
            custViewSource.View.MoveCurrentTo(newCustomer);
        }
        else
        {
            MessageBox.Show("CustomerID must have 5 characters.");
        }

        newCustomerGrid.Visibility = Visibility.Collapsed;
        existingCustomerGrid.Visibility = Visibility.Visible;
    }
    else if (newOrderGrid.IsVisible)
    {
        // Order ID is auto-generated so we don't set it here.  
        // For CustomerID, address, etc we use the values from current customer.  
        // User can modify these in the datagrid after the order is entered.  

        Customer currentCustomer = (Customer)custViewSource.View.CurrentItem;

        Order newOrder = new Order()
        {
            OrderDate = add_orderDatePicker.SelectedDate,
            RequiredDate = add_requiredDatePicker.SelectedDate,
            ShippedDate = add_shippedDatePicker.SelectedDate,
            CustomerID = currentCustomer.CustomerID,
            ShipAddress = currentCustomer.Address,
            ShipCity = currentCustomer.City,
            ShipCountry = currentCustomer.Country,
            ShipName = currentCustomer.CompanyName,
            ShipPostalCode = currentCustomer.PostalCode,
            ShipRegion = currentCustomer.Region
        };

        try
        {
            newOrder.EmployeeID = Int32.Parse(add_employeeIDTextBox.Text);
        }
        catch
        {
            MessageBox.Show("EmployeeID must be a valid integer value.");
            return;
        }

        try
        {
            // Exercise for the reader if you are using Northwind:  
            // Add the Northwind Shippers table to the model.
            
            // Acceptable ShipperID values are 1, 2, or 3.  
            if (add_ShipViaTextBox.Text == "1" || add_ShipViaTextBox.Text == "2"
                || add_ShipViaTextBox.Text == "3")
            {
                newOrder.ShipVia = Convert.ToInt32(add_ShipViaTextBox.Text);
            }
            else
            {
                MessageBox.Show("Shipper ID must be 1, 2, or 3 in Northwind.");
                return;
            }
        }
        catch
        {
            MessageBox.Show("Ship Via must be convertible to int");
            return;
        }

        try
        {
            newOrder.Freight = Convert.ToDecimal(add_freightTextBox.Text);
        }
        catch
        {
            MessageBox.Show("Freight must be convertible to decimal.");
            return;
        }

        // Add the order into the EF model  
        context.Orders.Add(newOrder);
        ordViewSource.View.Refresh();
    }

    // Save the changes, either for a new customer, a new order  
    // or an edit to an existing customer or order.
    context.SaveChanges();
}

// Sets up the form so that user can enter data. Data is later  
// saved when user clicks Commit.  
private void AddCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    existingCustomerGrid.Visibility = Visibility.Collapsed;
    newOrderGrid.Visibility = Visibility.Collapsed;
    newCustomerGrid.Visibility = Visibility.Visible;

    // Clear all the text boxes before adding a new customer.  
    foreach (var child in newCustomerGrid.Children)
    {
        var tb = child as TextBox;
        if (tb != null)
        {
            tb.Text = "";
        }
    }
}

private void NewOrder_click(object sender, RoutedEventArgs e)
{
    var cust = custViewSource.View.CurrentItem as Customer;
    if (cust == null)
    {
        MessageBox.Show("No customer selected.");
        return;
    }

    existingCustomerGrid.Visibility = Visibility.Collapsed;
    newCustomerGrid.Visibility = Visibility.Collapsed;
    newOrderGrid.UpdateLayout();
    newOrderGrid.Visibility = Visibility.Visible;
}

// Cancels any input into the new customer form  
private void CancelCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    add_addressTextBox.Text = "";
    add_cityTextBox.Text = "";
    add_companyNameTextBox.Text = "";
    add_contactNameTextBox.Text = "";
    add_contactTitleTextBox.Text = "";
    add_countryTextBox.Text = "";
    add_customerIDTextBox.Text = "";
    add_faxTextBox.Text = "";
    add_phoneTextBox.Text = "";
    add_postalCodeTextBox.Text = "";
    add_regionTextBox.Text = "";

    existingCustomerGrid.Visibility = Visibility.Visible;
    newCustomerGrid.Visibility = Visibility.Collapsed;
    newOrderGrid.Visibility = Visibility.Collapsed;
}

private void Delete_Order(Order order)
{
    // Find the order in the EF model.  
    var ord = (from o in context.Orders.Local
               where o.OrderID == order.OrderID
               select o).FirstOrDefault();

    // Delete all the order_details that have  
    // this Order as a foreign key  
    foreach (var detail in ord.Order_Details.ToList())
    {
        context.Order_Details.Remove(detail);
    }

    // Now it's safe to delete the order.  
    context.Orders.Remove(ord);
    context.SaveChanges();

    // Update the data grid.  
    ordViewSource.View.Refresh();
}

private void DeleteOrderCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    // Get the Order in the row in which the Delete button was clicked.  
    Order obj = e.Parameter as Order;
    Delete_Order(obj);
}

Uygulamayı çalıştırma

Hata ayıklamayı başlatmak için F5 tuşuna basın. Kılavuzda müşteri ve sipariş verilerinin doldurulması ve gezinti düğmelerinin beklendiği gibi çalışması gerekir. Verileri girdikten sonra modele yeni bir müşteri veya sipariş eklemek için İşle'ye tıklayın. Verileri kaydetmeden yeni bir müşteriden veya yeni sipariş formundan çıkmak için İptal'e tıklayın. Mevcut müşteri ve siparişlerde doğrudan metin kutularında düzenlemeler yapabilirsiniz ve bu değişiklikler modele otomatik olarak yazılır.