MVVM – WPF 数据模板



模板描述了控件的整体外观和视觉效果。每个控件都与其关联了一个默认模板,该模板赋予该控件外观。在 WPF 应用程序中,当您想要自定义控件的视觉行为和视觉外观时,可以轻松创建自己的模板。逻辑和模板之间的连接可以通过数据绑定来实现。

在 MVVM 中,还有另一种主要形式,称为 ViewModel 优先构建。

  • ViewModel 优先构建方法利用了 WPF 中隐式数据模板的功能。

  • 隐式数据模板可以根据使用数据绑定呈现的数据对象类型,自动从当前资源字典中为使用数据绑定的元素选择合适的模板。首先,您需要有一些绑定到数据对象的元素。

让我们再次看看我们简单的示例,您将了解如何利用数据模板(特别是隐式数据模板)来实现 ViewModel 优先。以下是我们 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; 
      } 
   } 
}

您可以看到上面的 ViewModel 没有改变。我们将继续使用上一章中的相同示例。此 ViewModel 类仅公开 Students 集合属性,并在构造时填充它。让我们转到 StudentView.xaml 文件,删除现有的实现并在 Resources 部分定义一个数据模板。

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

现在添加一个列表框并将该列表框数据绑定到 Students 属性,如下面的代码所示。

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

在 Resource 部分,DataTemplate 的键为 studentsTemplate,然后要实际使用该模板,我们需要使用 ListBox 的 ItemTemplate 属性。因此,现在您可以看到我们指示列表框使用该特定模板来呈现这些 Students。以下是 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>

编译并执行上述代码后,您将看到以下窗口,其中包含一个 ListBox。每个 ListBoxItem 包含 Student 类对象数据,这些数据显示在 TextBlock 和文本框中。

WPF Data Templates Main Window

要将其设为隐式模板,我们需要从列表框中删除 ItemTemplate 属性并在模板定义中添加 DataType 属性,如下面的代码所示。

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

在 DataTemplate 中,x:Type 标记扩展非常重要,它类似于 XAML 中的操作符。因此,基本上我们需要指向 MVVMDemo.Model 命名空间中的 Student 数据类型。以下是更新后的完整 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>

当您再次运行此应用程序时,您仍然会获得相同的数据模板的学生呈现,因为它通过查找合适的 DataTemplate 自动映射正在呈现的对象的类型。

Data Templates

我们建议您逐步执行上述示例以更好地理解。

广告