MVVM - szablony danych WPF
Szablon opisuje ogólny wygląd i wygląd kontrolki. Z każdą kontrolką powiązany jest domyślny szablon, który nadaje wygląd tej kontrolce. W aplikacji WPF można łatwo tworzyć własne szablony, gdy chcesz dostosować zachowanie wizualne i wygląd kontrolki. Łączność między logiką a szablonem można osiągnąć za pomocą powiązania danych.
W MVVM istnieje inna podstawowa forma, która jest znana jako pierwsza konstrukcja ViewModel.
Pierwsze podejście do konstrukcji ViewModel wykorzystuje możliwości niejawnych szablonów danych w WPF.
Niejawne szablony danych mogą automatycznie wybierać odpowiedni szablon z bieżącego słownika zasobów dla elementu, który używa powiązania danych. Robią to na podstawie typu obiektu danych, który jest renderowany przez powiązanie danych. Po pierwsze, musisz mieć jakiś element, który jest powiązany z obiektem danych.
Przyjrzyjmy się ponownie naszemu prostemu przykładowi, w którym zrozumiesz, jak można najpierw wyświetlić model, wykorzystując szablony danych, w szczególności niejawne szablony danych. Oto implementacja naszej klasy StudentViewModel.
using MVVMDemo.Model;
using System.Collections.ObjectModel;
namespace MVVMDemo.ViewModel {
public class StudentViewModel {
public StudentViewModel() {
LoadStudents();
}
public ObservableCollection<Student> Students {
get;
set;
}
public void LoadStudents() {
ObservableCollection<Student> students = new ObservableCollection<Student>();
students.Add(new Student { FirstName = "Mark", LastName = "Allain" });
students.Add(new Student { FirstName = "Allen", LastName = "Brown" });
students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
Students = students;
}
}
}
Widać, że powyższy ViewModel pozostaje niezmieniony. Będziemy kontynuować ten sam przykład z poprzedniego rozdziału. Ta klasa ViewModel po prostu uwidacznia właściwość kolekcji Students i wypełnia ją podczas budowy. Przejdźmy do pliku StudentView.xaml, usuń istniejącą implementację i zdefiniujmy szablon danych w sekcji Zasoby.
<UserControl.Resources>
<DataTemplate x:Key = "studentsTemplate">
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
Teraz Dodaj pole listy i powiązanie danych tego pola listy z właściwością Students, jak pokazano w poniższym kodzie.
<ListBox ItemsSource = "{Binding Students}" ItemTemplate = "{StaticResource studentsTemplate}"/>
W sekcji Resource DataTemplate ma klucz StudentsTemplate, a następnie, aby faktycznie użyć tego szablonu, musimy użyć właściwości ItemTemplate elementu ListBox. Teraz możesz zobaczyć, że poleciliśmy polu listy, aby użyło tego konkretnego szablonu do renderowania tych Studentów. Poniżej znajduje się pełna implementacja pliku StudentView.xaml.
<UserControl x:Class = "MVVMDemo.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMDemo.Views"
xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel"
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
<UserControl.Resources>
<DataTemplate x:Key = "studentsTemplate">
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox
ItemsSource = "{Binding Students}"
ItemTemplate = "{StaticResource studentsTemplate}"/>
</Grid>
</UserControl>
Kiedy powyższy kod zostanie skompilowany i wykonany, zobaczysz następujące okno, które zawiera jeden ListBox. Każdy ListBoxItem zawiera dane obiektu klasy Student, które są wyświetlane w polach TextBlock i Text.
Aby uczynić ten szablon niejawnym, musimy usunąć właściwość ItemTemplate z pola listy i dodać właściwość DataType w naszej definicji szablonu, jak pokazano w poniższym kodzie.
<UserControl.Resources>
<DataTemplate DataType = "{x:Type data:Student}">
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource = "{Binding Students}"/>
</Grid>
W DataTemplate rozszerzenie znaczników x: Type jest bardzo ważne, podobnie jak typ operatora w języku XAML. Zasadniczo musimy więc wskazać typ danych Student, który znajduje się w przestrzeni nazw MVVMDemo.Model. Poniżej znajduje się zaktualizowany kompletny plik XAML.
<UserControl x:Class="MVVMDemo.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMDemo.Views"
xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel"
xmlns:data = "clr-namespace:MVVMDemo.Model"
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
<UserControl.Resources>
<DataTemplate DataType = "{x:Type data:Student}">
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource = "{Binding Students}"/>
</Grid>
</UserControl>
Po ponownym uruchomieniu tej aplikacji nadal uzyskasz to samo renderowanie Studentów z szablonem danych, ponieważ automatycznie mapuje typ renderowanego obiektu, lokalizując odpowiedni DataTemplate.
Zalecamy wykonanie powyższego przykładu metodą krok po kroku w celu lepszego zrozumienia.