Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
Jeśli używasz programu Visual Studio 2022, upewnij się, że używasz wersji 17.3 lub nowszej na potrzeby tego samouczka.
W tym samouczku pokazano, jak utworzyć podstawowe formularze w aplikacji danych w programie Visual Studio. Aplikacja używa bazy danych SQL Server LocalDB, bazy danych Northwind, programu Entity Framework 6 (nie Entity Framework Core) i programu Windows Presentation Foundation (WPF) dla programu .NET Framework (nie .NET Core lub .NET 5 lub nowszego). Pokazuje, jak wykonać podstawowe powiązanie danych za pomocą widoku master-detail i zawiera niestandardową kontrolkę BindingNavigator z przyciskami, które wykonują następujące czynności: przejście do pierwszego, przejście do poprzedniego, przejście dalej, przejście do ostatniego, usunięcie, dodanie, ustawienie nowej kolejności, aktualizacja i anulowanie.
Ten samouczek koncentruje się na używaniu narzędzi do obsługi danych w programie Visual Studio i nie próbuje wyjaśnić podstawowych technologii w żadnej głębi. Przyjęto założenie, że masz podstawową znajomość języka Extensible Application Markup Language (XAML), Entity Framework i SQL. Mimo że kod w tym samouczku nie demonstruje architektury model-View-ViewModel (MVVM), która jest standardem dla aplikacji WPF, możesz skopiować kod z kilkoma modyfikacjami do własnej aplikacji MVVM.
Aby wyświetlić końcowy kod dla tego samouczka, zobacz Przykłady samouczków programu Visual Studio — EF6.
W tym samouczku nauczysz się następujących rzeczy:
- Instalowanie i nawiązywanie połączenia z usługą Northwind
- Konfigurowanie projektu aplikacji WPF
- Tworzenie modelu danych jednostki ADO.NET
- Dane wiążą model ze stroną XAML
- Dostosowywanie projektu strony i dodawanie siatki
- Dodawanie przycisków do nawigowania, dodawania, aktualizowania i usuwania
- Uruchamianie aplikacji WPF
Wymagania wstępne
Zainstalowany program Visual Studio z zainstalowanym pakietem roboczym Programowanie aplikacji klasycznych platformy .NET oraz zainstalowanym składnikiem Windows Communication Foundation. Aby go zainstalować:
- Otwórz aplikację Instalator programu Visual Studio lub wybierz pozycję NarzędziaPobierz narzędzia >i funkcje z menu programu Visual Studio.
- W Instalatorze programu Visual Studio wybierz pozycję Modyfikuj obok wersji programu Visual Studio, którą chcesz zmodyfikować.
- Wybierz kartę Poszczególne składniki , a następnie wybierz pozycję Windows Communication Foundation w obszarze Działania programistyczne.
- Wybierz pozycję Modyfikuj.
SQL Server Express LocalDB. Jeśli nie masz bazy danych SQL Server Express LocalDB, możesz zainstalować ją ze strony pobierania programu SQL Server. Możesz też zainstalować ją za pomocą aplikacji Instalatora programu Visual Studio jako pojedynczego składnika.
Eksplorator obiektów programu SQL Server. Aby go zainstalować, zainstaluj obciążenie Magazyn danych i przetwarzanie w aplikacji Instalatora programu Visual Studio .
Narzędzia platformy Entity Framework 6. Jest to zwykle instalowane podczas instalowania obciążenia .NET Dektop Development .
Instalowanie i nawiązywanie połączenia z usługą Northwind
W poniższym przykładzie użyto bazy danych SQL Server Express LocalDB i przykładowej bazy danych Northwind. Jeśli dostawca danych ADO.NET dla tego produktu obsługuje program Entity Framework, powinien również współpracować z innymi produktami bazy danych SQL.
Zainstaluj przykładową bazę danych Northwind, wykonując następujące kroki:
W programie Visual Studio otwórz okno Eksplorator obiektów programu SQL Server z menu Widok . Rozwiń węzeł SQL Server. Kliknij prawym przyciskiem myszy wystąpienie bazy danych LocalDB i wybierz pozycję Nowe zapytanie.
Zostanie otwarte okno edytora zapytań.
Skopiuj skrypt Northwind Transact-SQL (T-SQL) do schowka systemowego.
Wklej skrypt języka T-SQL do edytora zapytań, a następnie wybierz pozycję Wykonaj.
Zapytanie skryptu języka T-SQL tworzy bazę danych Northwind i wypełnia ją danymi.
Dodaj nowe połączenia dla bazy danych Northwind.
Konfigurowanie projektu aplikacji WPF
Aby skonfigurować projekt aplikacji WPF, wykonaj następujące kroki:
W programie Visual Studio utwórz nowy projekt WPF (aplikacji .NET Framework) .
Dodaj pakiet NuGet dla programu Entity Framework 6. W eksploratorze rozwiązań wybierz węzeł projektu. W menu głównym wybierz pozycję Project>Zarządzaj pakietami NuGet.
W Menedżerze pakietów NuGet wybierz link Przeglądaj . Wyszukaj i wybierz pakiet EntityFramework . Wybierz pozycję Zainstaluj w okienku po prawej stronie i postępuj zgodnie z monitami.
W oknie Dane wyjściowe zostanie wyświetlony postęp i zostanie wyświetlony komunikat o zakończeniu instalacji.
Teraz możesz użyć programu Visual Studio do utworzenia modelu opartego na bazie danych Northwind.
Tworzenie modelu danych jednostki ADO.NET
Aby utworzyć model danych jednostki ADO.NET, wykonaj następujące kroki:
Kliknij prawym przyciskiem myszy węzeł projektu aplikacji WPF w Eksploratorze rozwiązań i wybierz polecenie Dodaj>nowy element. W lewym okienku, w węźle C#, wybierz Dane, a w środkowym okienku wybierz ADO.NET Entity Data Model.
Wprowadź Northwind_modelw polu Nazwa, a następnie wybierz pozycję Dodaj.
W Kreatorze modelu danych jednostki wybierz pozycję EF Designer z bazy danych, a następnie wybierz przycisk Dalej.
W obszarze Wybierz połączenie danych wybierz połączenie LocalDB Northwind (na przykład (localdb)\MSSQLLocalDB), a następnie wybierz przycisk Dalej.
Jeśli nie widzisz połączenia:
Wybierz pozycję Nowe połączenie. Jeśli program Microsoft SQL Server nie jest wybrany jako źródło danych w oknie dialogowym Właściwości połączenia , wybierz pozycję Zmień. W oknie dialogowym Wybieranie źródła danych wybierz pozycję Microsoft SQL Server, a następnie wybierz przycisk OK.
W oknie dialogowym Właściwości połączenia wprowadź (localdb)\MSSQLLocalDB jako nazwę serwera.
W obszarze Wybierz lub wprowadź nazwę bazy danych, wybierz pozycję Northwind, a następnie wybierz przycisk OK.
W opcji Wybierz połączenie danych wybierz swoje połączenie LocalDB Northwind, po czym kliknij opcję Dalej.
Jeśli zostanie wyświetlony monit, wybierz używaną wersję programu Entity Framework, a następnie wybierz pozycję Dalej.
Na następnej stronie kreatora wybierz tabele, procedury składowane, i inne obiekty bazy danych, które chcesz uwzględnić w modelu Entity Framework. Rozwiń węzeł dbo znajdujący się pod węzłem Tabele w widoku drzewa. Wybierz pozycję Klienci, Szczegóły zamówienia i Zamówienia. Pozostaw zaznaczone wartości domyślne i wybierz pozycję Zakończ.
Kreator generuje klasy języka C#, które reprezentują model platformy Entity Framework i do których dane są wiązane przez Visual Studio w interfejsie użytkownika WPF. Spowoduje to utworzenie następujących plików w projekcie:
W pliku
.edmxopisano relacje i inne metadane, które kojarzą klasy z obiektami w bazie danych.Pliki
.ttto szablony T4, które generują kod działający na modelu i zapisuje zmiany w bazie danych.
Te pliki są widoczne w Eksploratorze rozwiązań w węźle Northwind_model :
Projektant formularzy dla pliku
.edmxnie jest używany w tym samouczku, ale za jego pomocą można modyfikować niektóre właściwości i relacje w modelu.
Pliki .tt są ogólnego przeznaczenia i należy edytować jeden z nich, aby pracować z powiązaniem danych WPF, co wymaga ObservableCollection obiektów. Wykonaj te kroki:
W Eksploratorze rozwiązań rozwiń węzeł Northwind_model do momentu znalezienia Northwind_model.tt. Kliknij dwukrotnie ten plik i wprowadź następujące zmiany:
Zastąp dwa wystąpienia ICollection na ObservableCollection<T>.
Zastąp pierwsze wystąpienie HashSet<T> przez ObservableCollection<T> w pobliżu wiersza 51. Nie zamieniaj drugiego wystąpienia elementu HashSet.
Zastąp jedyne wystąpienie ciągu System.Collections.Generic (w pobliżu wiersza 431) ciągiem System.Collections.ObjectModel.
Naciśnij F5, aby skompilować i uruchomić projekt. Gdy aplikacja jest uruchamiana po raz pierwszy, klasy modelu są widoczne dla kreatora źródeł danych.
Teraz możesz podłączyć ten model do strony XAML, aby móc wyświetlać, nawigować i modyfikować dane.
Dane wiążą model ze stroną XAML
Chociaż istnieje możliwość napisania własnego kodu powiązania danych, łatwiej jest umożliwić programowi Visual Studio wykonywanie go za Ciebie. W tym celu wykonaj następujące kroki:
W menu głównym wybierz pozycję Projekt>Dodaj nowe źródło danych , aby wyświetlić Kreatora konfiguracji źródła danych. Ponieważ wiążesz się z klasami modeli, a nie z bazą danych, wybierz pozycję Obiekt. Wybierz Dalej.
Rozwiń węzeł projektu, wybierz obiekt Klient , a następnie wybierz pozycję Zakończ. Źródła obiektów Order są generowane automatycznie na podstawie właściwości nawigacji Orders w kliencie.
W Eksploratorze rozwiązań kliknij dwukrotnie plik MainWindow.xaml w projekcie, aby edytować kod XAML. Zmień
Titlez MainWindow na coś bardziej opisowego i zwiększHeightiWidthna 600 i 800 (w razie potrzeby możesz zmienić te wartości później).Dodaj te trzy definicje wierszy do głównej siatki, jeden wiersz dla przycisków nawigacji, jeden dla szczegółów klienta i jeden dla siatki, która pokazuje ich zamówienia:
<Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions>
Następnie wyświetlasz każdą właściwość w klasie Customers w jej własnym, indywidualnym polu tekstowym. Wykonaj te kroki:
W Eksploratorze rozwiązań kliknij dwukrotnie plik MainWindow.xaml , aby otworzyć go w projektancie.
Karta Źródła danych zostanie wyświetlona w lewym okienku programu Visual Studio w pobliżu przybornika.
Aby otworzyć okno Źródła danych, wybierz kartę Źródła danych lub wybierz pozycję Wyświetl> inneźródła danych systemu> z menu.
W obszarze Źródła danych wybierz pozycję Klienci, a następnie wybierz pozycję Szczegóły z listy rozwijanej.
Przeciągnij węzeł do środkowego wiersza obszaru projektowego. Jeśli go zgubisz, możesz później ręcznie określić wiersz w języku XAML, wybierając
Grid.Row="1"pozycję.Domyślnie kontrolki są umieszczane w pionie w elemecie siatki, ale można je rozmieścić tak, jak chcesz w formularzu. Można na przykład umieścić pole tekstowe Nazwa nad adresem. Przykładowa aplikacja tego samouczka zmienia kolejność pól i zmienia ich rozmieszczenie w dwie kolumny.
W widoku XAML można teraz zobaczyć nowy
Gridelement w wierszu 1 (środkowy wiersz) siatki nadrzędnej. Siatka nadrzędna ma atrybutDataContext, który odwołuje się do CollectionViewSource należącego do elementuWindows.Resources. Biorąc pod uwagę kontekst danych, gdy pierwsze pole tekstowe wiąże się z Adres, ta nazwa jest mapowana na właściwośćAddressw bieżącym obiekcieCustomerwCollectionViewSource.<Grid DataContext="{StaticResource customerViewSource}">Przeciągnij właściwość obiektu klasy
Orderdo dolnej połowy formularza, tak aby projektant umieścił ją w wierszu 2.Gdy klient jest widoczny w górnej połowie formularza, chcesz zobaczyć swoje zamówienia w dolnej połowie. Zamówienia są wyświetlane w jednej kontrolce widoku siatki. Aby powiązanie danych master-detail działało zgodnie z oczekiwaniami, ważne jest, aby wiązać się z właściwością
OrderswCustomersklasie, a nie z oddzielnymOrderswęzłem.
Program Visual Studio generuje teraz cały kod powiązania, który łączy kontrolki interfejsu użytkownika z zdarzeniami w modelu.
Aby wyświetlić niektóre dane, napisz kod w celu wypełnienia modelu. Przejdź do
MainWindow.xaml.csi dodaj członka danych do klasyMainWindowdla kontekstu danych.Ten obiekt, który został wygenerowany dla Ciebie, działa jak kontrolka śledząca zmiany i zdarzenia w modelu.
Dodaj członków danych
CollectionViewSourcedla klientów i zamówień oraz logikę inicjalizacji konstruktora do istniejącego konstruktoraMainWindow(). Pierwsza część klasy powinna wyglądać następująco: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; }Jeśli nie istnieje, dodaj dyrektywę
usingdlaSystem.Data.Entity, aby przenieść metodę rozszerzeniaLoaddo zakresu:using System.Data.Entity;Przewiń w dół i znajdź procedurę obsługi zdarzenia
Window_Loaded. Zwróć uwagę, że program Visual Studio dodałCollectionViewSourceobiekt. Ten obiekt reprezentujeNorthwindEntitiesobiekt wybrany podczas tworzenia modelu. Ponieważ został już dodany, nie potrzebujesz go tutaj. Zastąp kod wWindow_Loaded, aby metoda wyglądała następująco: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; }Naciśnij F5.
Powinny zostać wyświetlone szczegóły dla pierwszego klienta, który został pobrany do obiektu
CollectionViewSource, oraz jego zamówienia w siatce danych. Formatowanie zostanie naprawione w następnej sekcji. Możesz również utworzyć sposób wyświetlania innych rekordów i wykonywania podstawowych operacji tworzenia, odczytu, aktualizowania i usuwania (CRUD).
Dostosowywanie projektu strony i dodawanie siatek dla nowych klientów i zamówień
Domyślny układ utworzony przez program Visual Studio nie jest idealny dla Twojej aplikacji, dlatego udostępniamy w tym miejscu ostateczny kod XAML, aby skopiować go do kodu. Potrzebujesz również niektórych siatek, aby umożliwić użytkownikowi dodanie nowego klienta lub zamówienia.
Aby dodać nowego klienta i zamówienie, utwórz oddzielny zestaw pól tekstowych, które nie są powiązane z CollectionViewSource. Określasz siatkę, którą użytkownik widzi w dowolnym momencie, ustawiając właściwość Visible w metodach obsługi. Na koniec do każdego wiersza w siatce Orders (Zamówienia) dodasz przycisk Usuń, aby umożliwić użytkownikowi usunięcie pojedynczego zamówienia.
Otwórz
MainWindow.xamli dodaj następujące style doWindows.Resourceselementu:<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>Zastąp całą siatkę zewnętrzną następującym znacznikiem:
<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>
Dodawanie przycisków do nawigowania, dodawania, aktualizowania i usuwania
W aplikacji Windows Forms otrzymujesz obiekt z przyciskami BindingNavigator, które umożliwiają nawigację po wierszach w bazie danych i wykonywanie podstawowych operacji CRUD. Mimo że WPF nie udostępnia BindingNavigator, można go łatwo utworzyć, tworząc przyciski wewnątrz poziomego StackPanel i kojarząc przyciski z poleceniami powiązanymi z metodami w pliku kodu-behind.
Logika poleceń to cztery części:
- Komendy
- Powiązania
- Przyciski
- Obsługa poleceń w kodzie-behind
Dodawanie poleceń, powiązań i przycisków w języku XAML
W pliku
MainWindow.xaml, dodaj polecenia do elementuWindows.Resourcesw następujący sposób:<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"/>Komponent
CommandBindingmapuje zdarzenieRoutedUICommanddo metody w kodzie. Dodaj tenCommandBindingselement po taguWindows.Resourceszamykającym w następujący sposób:<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>Dodaj element
StackPanelza pomocą przycisków nawigacji, dodawania, usuwania i aktualizowania. Dodaj ten styl do :Windows.Resources<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>Wklej ten kod tuż po elemecie
RowDefinitionszewnętrznymGridw górnej części strony XAML:<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>
Dodawanie programów obsługi poleceń do klasy MainWindow
Kod w elemecie MainWindow.xaml.cs jest minimalny z wyjątkiem metod dodawania i usuwania:
Aby nawigować, wywołaj metody na właściwości
ViewobiektuCollectionViewSource.Aby wykonać usuwanie kaskadowe w kolejności, użyj elementu
DeleteOrderCommandHandler, jak pokazano w przykładzie kodu. Należy jednak najpierw usunąć skojarzoneOrder_Detailszamówienie.Użyj elementu
UpdateCommandHandler, aby dodać klienta lub zamówienie do kolekcji, albo zaktualizować istniejącego klienta lub zamówienie przy użyciu zmian, które użytkownik wprowadza w polach tekstowych.Dodaj te metody obsługi do klasy
MainWindowwMainWindow.xaml.cs. JeśliCollectionViewSourcedla tabeli Customers ma inną nazwę, musisz dostosować nazwę w każdej z metod.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); }
Uruchamianie aplikacji WPF
Aby rozpocząć debugowanie, naciśnij F5. Sprawdź, czy dane klienta i zamówienia są zawarte w tabeli, a przyciski nawigacji działają zgodnie z oczekiwaniami.
Wybierz pozycję Zatwierdź , aby dodać nowego klienta lub zamówienie do modelu po wprowadzeniu danych.
Wybierz pozycję Anuluj , aby wycofać nowego klienta lub nowego formularza zamówienia bez zapisywania danych.
Aby dokonać edycji istniejących klientów i zamówień bezpośrednio, użyj pól tekstowych, które automatycznie zapisują te zmiany w modelu.
Powiązana zawartość
- narzędzia danych programu Visual Studio dla .NET
- dokumentacji programu Entity Framework