DevExpress技术交流群3:700924826 欢迎一起进群讨论
DevExpress WPF 拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。
使用模型视图ViewModel(MVVM)架构模式设计WPF应用程序时,可能需要描述模型或ViewModel中的列。 网格可以绑定到包含列设置的对象集合,该对象设置在Model或ViewModel中进行了描述,从而最大限度地减少了“隐藏代码”的需求。
实现视图模型
假设一个雇员视图模型,它包括以下类:
- Employee - 包含员工信息(例如名字和姓氏,职务等)的数据对象。
- ViewModel - 员工视图模型。
- EmployeeData - 提供要在网格控件中显示的员工信息。
- Column - 描述网格列,此类提供的属性对应于所有类型的网格列的通用设置。
- ComboBoxColumn - 对应于ComboBoxEdit in-place编辑器的网格列,此类提供Source属性,其中包含组合框项目的列表(在此示例中,这些城市)。
- SettingsType - 枚举用于编辑单元格值的in-place编辑器的可能类型。
C#
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace Model { public class ViewModel { public List<string> Cities { get; private set; } // Returns a list of employees so that they can be bound to the grid control. public List<Employee> Source { get; private set; } // The collection of grid columns. public ObservableCollection<Column> Columns { get; private set; } public ViewModel() { Source = EmployeeData.DataSource; List<string> _cities = new List<string>(); foreach (Employee employee in Source) { if (!_cities.Contains(employee.City)) _cities.Add(employee.City); } Cities = _cities; Columns = new ObservableCollection<Column>() { new Column() { FieldName = "FirstName", Settings = SettingsType.Default }, new Column() { FieldName = "LastName", Settings = SettingsType.Default }, new Column() { FieldName = "JobTitle", Settings = SettingsType.Default }, new Column() { FieldName = "BirthDate", Settings = SettingsType.Default }, new ComboColumn() { FieldName = "City", Settings = SettingsType.Combo, Source = Cities } }; } } // The data item. public class Employee { public string FirstName { get; set; } public string LastName { get; set; } public string JobTitle { get; set; } public string City { get; set; } public DateTime BirthDate { get; set; } } public class EmployeeData : List<Employee> { public static List<Employee> DataSource { get { List<Employee> list = new List<Employee>(); list.Add(new Employee() { FirstName = "Nathan", LastName = "White", City = "NY", JobTitle = "Sales Manager", BirthDate = new DateTime(1970, 1, 10) }); return list; } } } public class Column { // Specifies the name of a data source field to which the column is bound. public string FieldName { get; set; } // Specifies the type of an in-place editor used to edit column values. public SettingsType Settings { get; set; } } // Corresponds to a column with the combo box in-place editor. public class ComboColumn : Column { // The source of combo box items. public IList Source { get; set; } } public enum SettingsType { Default, Combo } }
注意:如果将Columns集合分配给网格控件后可能会更改,则它应实现INotifyCollectionChanged,以便网格中可自动反映View Model内所做的更改。
列模板和选择器
网格控件基于列模板生成列,创建多个模板,每种列类型一个模板。使用单个模板,您可以在无限数量的网格控件中创建无限数量的列。 在此示例中,有两个列模板:DefaultColumnTemplate和ComboColumnTemplate。
为避免绑定到列属性时的性能问题,请使用dxci:DependencyObjectExtensions.DataContext附加属性,请参见下面的示例。
XAML
<!----> xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal" <!----> <DataTemplate x:Key="DefaultColumnTemplate"> <ContentControl> <dxg:GridColumn FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}" Header="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Header, RelativeSource={RelativeSource Self}}" Width="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Width, RelativeSource={RelativeSource Self}}" /> </ContentControl> </DataTemplate>
要根据列的类型选择所需的模板,请使用模板选择器。 在此示例中,模板选择器由ColumnTemplateSelector类表示。
XAML
<Window x:Class="WpfApplication10.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal" xmlns:model="clr-namespace:Model" xmlns:view="clr-namespace:View"> <Window.DataContext> <model:ViewModel/> </Window.DataContext> <Window.Resources> <view:ColumnTemplateSelector x:Key="ColumnTemplateSelector"/> <DataTemplate x:Key="DefaultColumnTemplate"> <ContentControl> <dxg:GridColumn FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"/> </ContentControl> </DataTemplate> <DataTemplate x:Key="ComboColumnTemplate"> <ContentControl> <dxg:GridColumn FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"> <dxg:GridColumn.EditSettings> <dxe:ComboBoxEditSettings ItemsSource="{Binding Source}"/> </dxg:GridColumn.EditSettings> </dxg:GridColumn> </ContentControl> </DataTemplate> </Window.Resources> <Grid> </Grid> </Window>
C#
using System.Windows; using System.Windows.Controls; using Model; namespace View { public class ColumnTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { Column column = (Column)item; return (DataTemplate)((Control)container).FindResource(column.Settings + "ColumnTemplate"); } } }
注意:如果可以使用单个模板描述所有网格列,则无需创建列模板选择器,而是将此模板分配给网格的DataControlBase.ColumnGeneratorTemplate属性。
注意:您可以创建一种样式来指定使用不同模板生成的所有列共有的设置,您可以在样式内指定对ViewModel属性的绑定(请参见下面的FieldName):
XAML
<Window.Resources> <Style x:Key="ColumnStyle" TargetType="dxg:GridColumn"> <Setter Property="FilterPopupMode" Value="CheckedList"/> <Setter Property="FieldName" Value="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"/> </Style> </Window.Resources>
该样式应分配给DataControlBase.ColumnGeneratorStyle属性。
自定义WPF DXGrid
最后,指定网格的DataControlBase.ItemsSource,DataControlBase.ColumnsSource和DataControlBase.ColumnGeneratorTemplateSelector。DataControlBase.ItemsSource属性指定网格的数据源,DataControlBase.ColumnsSource属性指定网格从中生成列的源,DataControlBase.ColumnGeneratorTemplateSelector属性指定列模板选择器,该选择器根据其类型为每个列返回一个模板。
XAML
<Grid> <dxg:GridControl Name="grid" ItemsSource="{Binding Source}" ColumnsSource="{Binding Columns}" ColumnGeneratorTemplateSelector="{StaticResource ColumnTemplateSelector}"> <dxg:GridControl.View> <dxg:TableView Name="tableView1" AutoWidth="True" NavigationStyle="Cell" /> </dxg:GridControl.View> </dxg:GridControl> </Grid>
下图显示了结果。