MVVM - Modelli di dati WPF
Un modello descrive l'aspetto generale e l'aspetto visivo del controllo. Ad ogni controllo è associato un modello predefinito che conferisce l'aspetto a quel controllo. Nell'applicazione WPF è possibile creare facilmente i propri modelli quando si desidera personalizzare il comportamento visivo e l'aspetto visivo di un controllo. La connettività tra la logica e il modello può essere ottenuta mediante l'associazione dei dati.
In MVVM, esiste un'altra forma primaria nota come prima costruzione ViewModel.
Il primo approccio alla costruzione di ViewModel sfrutta le funzionalità dei modelli di dati impliciti in WPF.
I modelli di dati impliciti possono selezionare automaticamente un modello appropriato dal dizionario delle risorse corrente per un elemento che utilizza l'associazione dati. Lo fanno in base al tipo di oggetto dati di cui viene eseguito il rendering dal data binding. Innanzitutto, è necessario disporre di un elemento che si lega a un oggetto dati.
Diamo nuovamente un'occhiata al nostro semplice esempio in cui capirai come puoi visualizzare prima il modello sfruttando i modelli di dati, in particolare i modelli di dati impliciti. Ecco l'implementazione della nostra classe 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;
}
}
}
Puoi vedere che il ViewModel sopra è rimasto invariato. Continueremo con lo stesso esempio del capitolo precedente. Questa classe ViewModel espone semplicemente la proprietà della raccolta Students e la popola durante la costruzione. Andiamo al file StudentView.xaml, rimuoviamo l'implementazione esistente e definiamo un modello di dati nella sezione Risorse.
<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>
Ora aggiungi una casella di riepilogo e associa i dati a tale casella di riepilogo alla proprietà Studenti come mostrato nel codice seguente.
<ListBox ItemsSource = "{Binding Students}" ItemTemplate = "{StaticResource studentsTemplate}"/>
Nella sezione Risorsa, DataTemplate ha una chiave di studentsTemplate e quindi per utilizzare effettivamente quel modello, dobbiamo usare la proprietà ItemTemplate di un ListBox. Quindi ora puoi vedere che istruiamo la casella di riepilogo a utilizzare quel modello specifico per il rendering di quegli Studenti. Di seguito è riportata l'implementazione completa del file 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>
Quando il codice sopra viene compilato ed eseguito, vedrai la seguente finestra, che contiene un ListBox. Ogni ListBoxItem contiene i dati dell'oggetto della classe Student che vengono visualizzati in TextBlock e nelle caselle di testo.
Per renderlo un modello implicito, è necessario rimuovere la proprietà ItemTemplate da una casella di riepilogo e aggiungere una proprietà DataType nella definizione del modello come mostrato nel codice seguente.
<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>
In DataTemplate, l'estensione di markup x: Type è molto importante che è come un tipo di operatore in XAML. Quindi, in pratica, dobbiamo puntare al tipo di dati Student che si trova nello spazio dei nomi MVVMDemo.Model. Di seguito è riportato il file XAML completo aggiornato.
<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>
Quando si esegue nuovamente questa applicazione, si otterrà comunque lo stesso rendering degli Studenti con il modello di dati perché esegue automaticamente la mappatura del tipo di oggetto sottoposto a rendering individuando il DataTemplate appropriato.
Ti consigliamo di eseguire l'esempio precedente in un metodo passo passo per una migliore comprensione.