MVVM DEVDataColumn中的TextBox与ComboBox的并存
Posted airforce094
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MVVM DEVDataColumn中的TextBox与ComboBox的并存相关的知识,希望对你有一定的参考价值。
一、前言
在WPF编程中,有时候我们使用DataGrid会需要在一个DataColumn中既有TextBox,也要有ComboBox或者TextBlock等其他数据显示样式。
这个时候我们就需要DataGridTemplateColumn去自定义我们的Column样式,通过数据类型去判断该信息是以TextBox显示还是以ComboBox来显示。
二、从数据库出发
所谓兵马未到,粮草先行。数据库的字段应该明确告诉我们该条数据是哪个数据类型?是字符串型还是多选型?是否可编辑?
这些清晰的信息都能为我们之后的MVVM绑定带来极大的便利。
数据库的字段可以大致这样:
1. ID
2. Keyword
3. Name
4. Value
5. ItemsValue (用来告知有哪些选择项)
6. DataType (是字符串型,还是多选型,还是其他?)
7. IsAcceptInput (显示在界面上后是否可编辑)
范例:
我们可以从上表看出,第1与第2条数据应该是TextBox显示,而第3与第4条则是ComboBox显示。
三、在代码中准备好相应的枚举
当我们准备完数据库的数据时,在代码中我们会用Dapper, EF, Nhibernate等等将数据库字段映射为相应的数据类型:
public Class ExampleInfoData { public long Id {get;set;} public string Keyword {get;set;} public string PropertyName {get;set;} public DataItem PropertyValue {get;set;} public List<DataItem> ItemValues {get;set;} public int DataType {get;set;} public bool IsAcceptInput {get;set;} }
这里我们看到有个类叫 DataItem, 这是为了什么呢?我们看下范例:
public class DataItem { public string DisplayName { get; set; } //显示值 用来在界面上显示用的 public string ItemValue { get; set; } //原始值 //这个方法是为了能让界面正常显示从数据库读取的值,不用这个方法的话就算数据库中存有默认值,绑定之后它也不会正常显示在界面上 public override bool Equals(object obj) { if (!(obj is DataItem)) { return false; } DataItem di = obj as DataItem; return di != null && di.ItemValue == ItemValue; } public override int GetHashCode() //配合Equals方法,两者一起使用 { return ItemValue.GetHashCode(); } }
对于多选型的数据,我们也应该准备好相应的枚举值,有了Description能方便的给之前的DisplayName提供值。
public enum ProjectType { [Description("类型一")] T_1 = 0, [Description("类型二")] T_2 = 1, [Description("类型三")] T_3 = 2, } public enum MemberType { [Description("成员类型一")] M_1 = 0, [Description("成员类型二")] M_2 = 1, [Description("成员类型三")] M_3 = 2, }
四、ViewModel的准备
准备好上述工作,我们就要开始使用MVVM了,首先要把ViewModel的数据填充上,这里我不详写代码,看清套路就能自己开车了。
using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using DevExpress.Mvvm; namespace Example { public class ProjectSettingViewModel : ViewModelBase { public ObservableCollection<ExampleInfoData> ProjectInfo { get; set; } public New_ProjectSettingViewModel() { ProjectInfo = new ObservableCollection<ExampleInfoData>(FillProjectInfo()); } public List<ExampleInfoData> FillProjectInfo() { List<ExampleInfoData> projectSettingInfoList = new List<ExampleInfoData>(); var dB_projectSettingInfo = projectSettingDB.GetAll(); //get Data From DB foreach (var item in dB_projectSettingInfo) { ExampleInfoData projectSettingInfo = new ExampleInfoData (); projectSettingInfo.Id = item.Id; projectSettingInfo.KeyWord = item.Keyword; projectSettingInfo.PropertyName = item.Name; projectSettingInfo.TabId = item.TabId; projectSettingInfo.DataType = item.DataType; projectSettingInfo.AcceptInput = item.AcceptInput; if (item.ItemValues == null) { DataItem smText = new DataItem(); smText.DisplayName = smText.ItemValue = item.Value; projectSettingInfo.ProjectSettingValue = smText; projectSettingInfo.ItemValues = null; } else { DataItem smCombox = new DataItem(); smCombox.ItemValue = item.Value; smCombox.DisplayName = JudgeType(item.Value); // 这个函数判断是哪种枚举类型的!!!并返回相应的Description projectSettingInfo.ProjectSettingValue = smCombox; projectSettingInfo.ItemValues = new List<DataItem>(); foreach (var iv in item.ItemValues.Split(\',\')) { DataItem sm = new DataItem(); sm.ItemValue = iv; sm.DisplayName = JudgeType(iv); projectSettingInfo.ItemValues.Add(sm); } } projectSettingInfoList.Add(projectSettingInfo); }
return projectSettingInfoList; }
public string JudgeType(string strValue)
{
if (!string.IsNullOrEmpty(strValue))
{
string strType = strValue.Split(\'_\')[0];
if (string.Equals(strType, "T", StringComparison.CurrentCultureIgnoreCase))
{
return GetDescriptionFromEnumValue((ProjectType)Enum.Parse(typeof(ProjectType), strValue)); //获取Description的方法各位自己写
}
else if (string.Equals(strType, "M", StringComparison.CurrentCultureIgnoreCase))
{
return GetDescriptionFromEnumValue((MemberType)Enum.Parse(typeof(MemberType), strValue));
}
else
{
return null;
}
}
return null;
} } }
五、View的准备
<UserControl x:Class="Example" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="../../Controls/ProjectSettingDataGrid.xaml"/> !!!Here </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources> <Grid Margin="0,15,0,0"> <DataGrid x:Name="dgPJInfo" CanUserSortColumns="False" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" AlternatingRowBackground="#EBEBEB" Background="White" ItemsSource ="{Binding ProjectInfo}"> <DataGrid.Columns> <DataGridTextColumn Width=".4*" IsReadOnly="True" Header="属性名称" FontSize="15" Binding="{Binding PropertyName}"></DataGridTextColumn> <DataGridTemplateColumn Width=".4*" Header="属性值" CellTemplateSelector="{StaticResource DataGridTemplateSelector}"></DataGridTemplateColumn> !!!Here </DataGrid.Columns> </DataGrid> </Grid> </UserControl>
上面这个View告诉我们这个DataGridTemplateColumn的CellTemplateSelector是
绑定到<ResourceDictionary Source="../../Controls/ProjectSettingDataGrid.xaml"/>里的DataGridTemplateSelector
那么ProjectSettingDataGrid.xaml 该怎么写呢?
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Example.Controls" xmlns:view="clr-namespace:Example.UI.View"> <DataTemplate x:Key="TextBoxTemplate"> //TextBox的Template <TextBox Text="{Binding PropertyValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" FontSize="15"/> </DataTemplate> <DataTemplate x:Key="TextBlockTemplate"> //TextBlock的Template <TextBlock Text="{Binding PropertyValue}" FontSize="15"/> </DataTemplate> <DataTemplate x:Key="ComboBoxTemplate"> //Combobox的Template <ComboBox ItemsSource="{Binding ItemValues}" FontSize="15" IsEditable="{Binding IsAcceptInput}"
SelectedItem="{Binding PropertyValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="DisplayName"/> !!!注意这里的DisplayMemberPath !!! </DataTemplate> <controls:DataGridTemplateSelector x:Key="DataGridTemplateSelector" TextBoxDataTemplate="{StaticResource TextBoxTemplate}" TextBlockDataTemplate="{StaticResource TextBlockTemplate}" ComboBoxDataTemplate="{StaticResource ComboBoxTemplate}"/> </ResourceDictionary>
这下好了,定义好了各种Template,我剩下的事就是根据数据,判断采用哪种Template,
ProjectSettingDataGrid.xaml.cs可以这样写:
using System; using System.Windows; using System.Windows.Controls; using Example.ProjectSetting; namespace Example.Controls { public partial class PropertyDataGrid : DataGrid { public PropertyDataGrid() { } } public class DataGridTemplateSelector : DataTemplateSelector { public DataTemplate TextBoxDataTemplate { get; set; } public DataTemplate TextBlockDataTemplate { get; set; } public DataTemplate ComboBoxDataTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) //这里的object item传进来的就是ViewModel中ProjectInfo的一条条数据!!! { if (null == item) { return null; } if (item is ExampleInfoData) { ExampleInfoData projectInfo = item as ExampleInfo; if (projectInfo.DataType == (int) ((DataEnum) Enum.Parse(typeof (DataEnum), "DATA_ENUM"))) !!!注意这里,在数据库定义的DataType此时就起到了判断Template的作用!!! { return ComboBoxDataTemplate; } else { return TextBoxDataTemplate; } } // else if (item is OtherInfoData) // { // //do something // }
else { return null; } } } }
六、总结
以上内容就是所有的套路,
简单的说就是:
1. 数据库字段
2. 映射字段
3. 枚举类对应
4. ViewModel 数据填充
5. DataGridTemplateColumn的绑定
6. 定义各种Template并作出判断选择哪种Template
以上是关于MVVM DEVDataColumn中的TextBox与ComboBox的并存的主要内容,如果未能解决你的问题,请参考以下文章