您的位置:首页 > 其它

【MVVM Dev】DataColumn中的TextBox与ComboBox的并存

2016-12-17 14:32 369 查看

一、前言

      在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告诉我们这个DataGridTemplateColumnCellTemplateSelector

         绑定到<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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: