• 【MVVM Dev】DataColumn中的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告诉我们这个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

  • 相关阅读:
    kendoui 时间选择框
    vue+webpack+win10搭建项目
    arcgis for javascript 自定义infowindow
    如何将 Microsoft Bot Framework 机器人部署以及网页应用
    STM32Cube_FW_F1_V1.0.0固件库学习(五) Systick
    STM32Cube_FW_F1_V1.0.0固件库学习(四)外部中断 下
    STM32Cube_FW_F1_V1.0.0固件库学习(四)外部中断 中
    STM32Cube_FW_F1_V1.0.0固件库学习(二)工程设置
    STM32Cube_FW_F1_V1.0.0固件库学习(四)中断概念 上
    STM32Cube_FW_F1_V1.0.0固件库学习(三)GPIO LED&KEY
  • 原文地址:https://www.cnblogs.com/lovecsharp094/p/6189517.html
Copyright © 2020-2023  润新知