MVVM - Modelos de Dados WPF
Um modelo descreve a aparência geral e a aparência visual do controle. Para cada controle, há um modelo padrão associado a ele que dá a aparência a esse controle. No aplicativo WPF, você pode criar facilmente seus próprios modelos quando quiser personalizar o comportamento visual e a aparência visual de um controle. A conectividade entre a lógica e o modelo pode ser alcançada por vinculação de dados.
No MVVM, há outra forma primária que é conhecida como construção inicial do ViewModel.
A primeira abordagem de construção do ViewModel alavanca os recursos de modelos de dados implícitos no WPF.
Os modelos de dados implícitos podem selecionar automaticamente um modelo apropriado do dicionário de recursos atual para um elemento que usa vinculação de dados. Eles fazem isso com base no tipo de objeto de dados que é processado pela vinculação de dados. Primeiro, você precisa ter algum elemento que esteja vinculado a um objeto de dados.
Vamos dar uma olhada em nosso exemplo simples novamente, no qual você entenderá como pode fazer o modelo de visualização primeiro aproveitando os modelos de dados, especificamente os modelos de dados implícitos. Aqui está a implementação de nossa 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;
}
}
}
Você pode ver que o ViewModel acima não foi alterado. Continuaremos com o mesmo exemplo do capítulo anterior. Esta classe ViewModel apenas expõe a propriedade da coleção Students e a preenche na construção. Vamos para o arquivo StudentView.xaml, remover a implementação existente e definir um modelo de dados na seção Recursos.
<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>
Agora adicione uma caixa de listagem e vincule os dados a essa caixa de listagem à propriedade Students conforme mostrado no código a seguir.
<ListBox ItemsSource = "{Binding Students}" ItemTemplate = "{StaticResource studentsTemplate}"/>
Na seção Resource, o DataTemplate tem uma chave de studentsTemplate e então para realmente usar esse modelo, precisamos usar a propriedade ItemTemplate de um ListBox. Agora você pode ver que instruímos a caixa de listagem a usar esse modelo específico para renderizar esses alunos. A seguir está a implementação completa do arquivo 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 o código acima for compilado e executado, você verá a seguinte janela, que contém um ListBox. Cada ListBoxItem contém os dados do objeto da classe Student que são exibidos nas caixas TextBlock e Text.
Para tornar este um modelo implícito, precisamos remover a propriedade ItemTemplate de uma caixa de listagem e adicionar uma propriedade DataType em nossa definição de modelo, conforme mostrado no código a seguir.
<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>
No DataTemplate, a extensão de marcação x: Type é muito importante, que é como um tipo de operador em XAML. Portanto, basicamente precisamos apontar para o tipo de dados Student que está no namespace MVVMDemo.Model. A seguir está o arquivo XAML completo atualizado.
<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>
Ao executar este aplicativo novamente, você ainda obterá a mesma renderização dos Alunos com o modelo de dados, porque ele está mapeando automaticamente o tipo do objeto sendo renderizado ao localizar o DataTemplate apropriado.
Recomendamos que você execute o exemplo acima em um método passo a passo para melhor compreensão.