【MVVM DEV】DataColumn中的TextBox與ComboBox的並存

来源:http://www.cnblogs.com/lovecsharp094/archive/2016/12/17/6189517.html
-Advertisement-
Play Games

一、前言 在WPF編程中,有時候我們使用DataGrid會需要在一個DataColumn中既有TextBox,也要有ComboBox或者TextBlock等其他數據顯示樣式。 這個時候我們就需要DataGridTemplateColumn去自定義我們的Column樣式,通過數據類型去判斷該信息是以T ...


一、前言

      在WPF編程中,有時候我們使用DataGrid會需要在一個DataColumn中既有TextBox,也要有ComboBox或者TextBlock等其他數據顯示樣式。

       這個時候我們就需要DataGridTemplateColumn去自定義我們的Column樣式,通過數據類型去判斷該信息是以TextBox顯示還是以ComboBox來顯示。

 

        PS:初入WPF-MVVM模式編程的童鞋可以先瞭解一下what is MVVM

 

二、從資料庫出發

      所謂兵馬未到,糧草先行。資料庫的欄位應該明確告訴我們該條數據是哪個數據類型?是字元串型還是多選型?是否可編輯?

       這些清晰的信息都能為我們之後的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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 實現微信上網頁的圖片點擊後全屏還可以可以縮放,這個功能是別人做的,可是捏點擊後屏幕直接黑屏了,圖片沒有顯示出來。這個代碼在網上搜一下,挺多類似的。 先上代碼。 在微信web 開發者工具調試,網頁上斷點調試發現圖片路徑 json 格式化了兩次!!! 最後解決的方法是沒有調用 arrayToJson() ...
  • 異常與處理 C# 語言的異常處理功能可幫助您處理程式運行時出現的任何意外或異常情況。 異常處理使用 try、catch 和 finally 關鍵字嘗試某些操作,以處理失敗情況,儘管這些操作有可能失敗,但如果您確定需要這樣做,且希望在事後清理資源,就可以嘗試這樣做。 公共語言運行時 (CLR)、.NE ...
  • 本人經常與webservice打交道,特意寫了個小工具來調用Webservice方便測試,還有待進一步完善。使用方法如下 : 填寫完webservice的wsdl地址後點擊載入,將在方法那一側列出該服務所包含的方法,選中方法後在右側列出該方法所需參數,填完參數值後點擊調用在下方顯示結果,在標題欄顯示 ...
  • 方法不能跟變數一樣當參數傳遞,怎麼辦,C#定義了委托,就可以把方法當變數一樣傳遞了,為了簡單,匿名方法傳遞,省得再聲明方法了;再簡單,lambda表達式傳遞,比匿名方法更直觀。 public delegate int delegateArithmetic(int a, int b); //委托作為參 ...
  • 裝箱是將值類型轉換為 object 類型或由此值類型實現的任何介面類型的過程。 當 CLR 對值類型進行裝箱時,會將該值包裝到 System.Object 內部,再將後者存儲在托管堆上。 取消裝箱將從對象中提取值類型。 裝箱是隱式的;拆箱是顯式的。 裝箱和拆箱的概念是類型系統 C# 統一視圖的基礎, ...
  • 線程池的作用線程池,顧名思義,線程對象池。Task和TPL都有用到線程池,所以瞭解線程池的內幕有助於你寫出更好的程式。由於篇幅有限,在這裡我只講解以下核心概念: 線程池的大小 如何調用線程池添加任務 線程池如何執行任務 Threadpool也支持操控IOCP的線程,但在這裡我們不研究它,和task以 ...
  • 初學者,採用簡單三層架構,本來想用autofac依賴註入,只用sql server,沒打算遷移到別的資料庫,因此,簡單一點,就不用了。先做用戶管理模塊,登錄註冊等,客戶端cooke存儲,利用DESCryptoServiceProvider加密,源代碼下載地址:https://github.com/J ...
  • 最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。 十年河東十年河西,莫欺少年窮 學無止境,精益求精 C#洗牌演算法如下: 採用的是交換位置法,程式執行54次。效率還是頗高滴! @陳卧龍的博客 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...