MVVM - Plantillas de datos de WPF

Una plantilla describe el aspecto general y el aspecto visual del control. Para cada control hay una plantilla predeterminada asociada que le da la apariencia de ese control. En la aplicación WPF, puede crear fácilmente sus propias plantillas cuando desee personalizar el comportamiento visual y la apariencia visual de un control. La conectividad entre la lógica y la plantilla se puede lograr mediante el enlace de datos.

En MVVM, hay otra forma primaria que se conoce como primera construcción de ViewModel.

  • El primer enfoque de construcción de ViewModel aprovecha las capacidades de las plantillas de datos implícitas en WPF.

  • Las plantillas de datos implícitas pueden seleccionar automáticamente una plantilla adecuada del diccionario de recursos actual para un elemento que utiliza el enlace de datos. Lo hacen en función del tipo de objeto de datos que representa el enlace de datos. Primero, debe tener algún elemento que se vincule a un objeto de datos.

Echemos un vistazo a nuestro ejemplo simple nuevamente en el que comprenderá cómo puede ver primero el modelo aprovechando las plantillas de datos, específicamente las plantillas de datos implícitas. Aquí está la implementación de nuestra clase 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; 
      } 
   } 
}

Puede ver que el ViewModel anterior no ha cambiado. Continuaremos con el mismo ejemplo del capítulo anterior. Esta clase de ViewModel solo expone la propiedad de colección de Estudiantes y la llena durante la construcción. Vayamos al archivo StudentView.xaml, eliminemos la implementación existente y definamos una plantilla de datos en la sección 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>

Ahora agregue un cuadro de lista y enlace de datos ese cuadro de lista a la propiedad de Estudiantes como se muestra en el siguiente código.

<ListBox ItemsSource = "{Binding Students}" ItemTemplate = "{StaticResource studentsTemplate}"/>

En la sección de Recursos, el DataTemplate tiene una clave de StudentsTemplate y luego, para usar esa plantilla, necesitamos usar la propiedad ItemTemplate de un ListBox. Entonces, ahora puede ver que le indicamos al cuadro de lista que use esa plantilla específica para representar a esos Estudiantes. A continuación se muestra la implementación completa del archivo 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>

Cuando se compile y ejecute el código anterior, verá la siguiente ventana, que contiene un ListBox. Cada ListBoxItem contiene los datos del objeto de la clase Student que se muestran en TextBlock y Text boxes.

Para hacer de esto una plantilla implícita, necesitamos eliminar la propiedad ItemTemplate de un cuadro de lista y agregar una propiedad DataType en nuestra definición de plantilla como se muestra en el siguiente código.

<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>

En DataTemplate, la extensión de marcado x: Type es muy importante, que es como un tipo de operador en XAML. Entonces, básicamente necesitamos apuntar al tipo de datos Student que está en el espacio de nombres MVVMDemo.Model. A continuación se muestra el archivo XAML completo actualizado.

<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>

Cuando vuelva a ejecutar esta aplicación, seguirá obteniendo la misma representación de la plantilla Estudiantes con datos porque asigna automáticamente el tipo de objeto que se representa al ubicar la plantilla de datos adecuada.

Le recomendamos que ejecute el ejemplo anterior en un método paso a paso para una mejor comprensión.