擴展UltraGrid控件實現對所有數據行的全選功能

通過對三種Infragistics 控件(UltraToolBarManager、UltraGird和UltraListView)進行擴展,以實現對ToolTip樣式的定義,今天我來介紹如何採用相同的方式實現另外一個更爲常用的功能:在UltraGrid的Header中動態添加CheckBox,從而實現對所有數據行進行全選的功能。

一、我們的目標:在UltraGird的選擇列的Header添加CheckBox實現對所有數據行的全選 

image我們現有的絕大部分UltraGird都具有如下圖(點擊查看大圖)所示的結構:第一行爲UnBound列,單元格中的CheckBox用於對當前行的選擇,即通過勾選相應的CheckBox代表選中某一行。現在的新的要求是:在CheckBox列的列頭添加一個總的CheckBox,用於選中所有數據行,即當勾選CheckBox時,下面所有數據行對應的均自動被勾選,反之,解除現有數據行對應的CheckBox的勾選狀態。

image

 

 

 

 

 

 

 

 

熟悉Infragistics控件的朋友應該知道,UltraGird具有一個很有用的動態分局的特性:你可以將可被用於分組的列通過鼠標拖到最上方的區域(Drag a column header here to group by the column),那麼UltraGird會自動爲你將所有的數據行按照該列的值進行動態分組。這個分組功能爲我們要擴展的UltraGird又增加了一個新的特性:如果在分組狀態,需要在每一個分組行中添加CheckBox,該CheckBox用於對當前組範圍內所有數據行的全選。最後的效果如右圖(點擊查看大圖)所示。

二、關於UIElement和UIElementCreationFilter

在具體介紹實現的之前,我們先來談談相關的一些背景知識:關於UIElement和UIElementFilter。Infragistics 基於Windows Forms應用的控件具有非常高的擴展型。通過合理使用UIElement,開發者可以很容易地添加一些現有控件沒有提供的功能。

基本上所有的Infragistics 控件(這裏我們僅僅指基於Window Forms應用控件)都有一個具有層級關係的UIElement組成。比如,一個UltraTree 由一個UltraTreeUIElement構成,而一個UltraTreeUIElement又包含一組TreeNodeUIElement 對象和NodeConnectorUIElement對象。而TreeNodeUIElements又由一組PreNodeAreaUIElement 和NodeSelectableAreaUIElement組成。對於NodeSelectableAreaUIElements,其組成元素又包含兩種:ExpansionIndicatorUIElements 和NodeTexUIElements。

所有的UIElement相關的操作,比如改變其顯示風格和位置,可以通過兩個Filter對象控制,即CreationFilter和DrawFilter。而CreationFilter還能用於爲現有控件動態的添加或者移除子控件,我們將要實現的對於CheckBox的動態添加就是通過自定義CreationFilter實現的。

三、自定義UIElementCreationFilter實現對CheckBox的動態添加

對現有UltraGrid的擴展的核心在於自定義UIElementCreationFilter實現對CheckBox的動態添加,在具體介紹如何自定義UIElementCreationFilter之前,我們先看看我們擴展出來的UltraGrid的定義。從下面的代碼片段可以看出,擴展控件ExtendedUltraGrid的定義其實很簡單。其中,SelectAllColumnName表示CheckBox列的名稱;而IsGroupMode屬性表示當前是否處於分組模式;CheckState表示在未分組情況下Select-All CheckBox應有的狀態;在構造函數中,我們指定了UltraGrid的CreationFilter屬性。

1: using System.Windows.Forms;

   2: using Infragistics.Win.UltraWinGrid;
   3:  
   4: namespace Artech.ExtendedUltraGrid4SelectAll
   5: {
   6:     public class ExtendedUltraGrid : UltraGrid
   7:     {
   8:         public string SelectAllColumnName{get;set;}
   9:  
  10:         internal bool IsGroupMode
  11:         {
  12:             get
  13:             {
  14:                 foreach (var row in this.Rows)
  15:                 {
  16:                     if (row.IsGroupByRow)
  17:                     {
  18:                         return true;
  19:                     }
  20:                 }
  21:                 return false;
  22:             }
  23:         }
  24:  
  25:         internal CheckState CheckState{ get; set; }
  26:  
  27:         public ExtendedUltraGrid()
  28:         {
  29:             this.CreationFilter = new CheckableHeaderCreationFilter(this);
  30:         }       
  31:     }
  32: }

在構造函數中指定的Creation屬性就是我們上面介紹的自定義的UIElementCreationFilter:CheckableHeaderCreationFilter。所有的UIElementCreationFilter均實現接口IUIElementCreationFilter,該接口具有兩個方法BeforeCreateChildElements和AfterCreateChildElements。
1: using Infragistics.Win;

   2: public class MyUltraExplorerBarCreationFilter : IUIElementCreationFilter
   3: {
   4:     public void AfterCreateChildElements(UIElement parent)
   5:     {
   6:         // called for a UIElement (parent) after it creates its child elements.
   7:     }
   8:     public bool BeforeCreateChildElements(UIElement parent)
   9:     {
  10:         // called for a UIElement (parent) before it creates its child elements.
  11:         return false;
  12:     }
  13: }

在CheckableHeaderCreationFilter中,我們將在Select列的列頭添加CheckBox的操作實現在AfterCreateChildElements方法中。其主要的邏輯是:通過parent的類型(必須是HeaderUIElement)、Column的類型(比如是Boolean)和Column Name(必須是在ExtendedUltraGrid的SelectAllColumnName屬性指定)確定parent正是我們需要位置添加Check子控件的UIElement。然後創建CheckBoxUIElement,並將其添加到parent中,並通過Rect屬性確定其顯示的位置。然後我們會根據分組行(UltraGridGroupByRow)的Tag(這個會在自定義CheckBoxUIElement中設置)設置新創建的CheckBoxUIElement的CheckState狀態,如果沒有在分組模式下,我們根據ExtendedUltraGrid的CheckState屬性指定該CheckBoxUIElement的狀態。

1: using System;

   2: using System.Collections.Generic;
   3: using System.Drawing;
   4: using System.Windows.Forms;
   5: using Infragistics.Win;
   6: using Infragistics.Win.UltraWinGrid;
   7:  
   8: namespace Artech.ExtendedUltraGrid4SelectAll
   9: {
  10:     public class CheckableHeaderCreationFilter : IUIElementCreationFilter
  11:     {
  12:         public ExtendedUltraGrid Control
  13:         { get; private set; }
  14:  
  15:         public CheckableHeaderCreationFilter( ExtendedUltraGrid control)
  16:         {          
  17:             if (null == control)
  18:             {
  19:                 throw new ArgumentNullException("control");
  20:             }
  21:             this.Control = control;
  22:         }
  23:  
  24:         public void AfterCreateChildElements(UIElement parent)
  25:         {
  26:             //Filter the HeaderUIElement element.
  27:             HeaderUIElement headerUIElement = parent as HeaderUIElement;
  28:             if (null == headerUIElement)
  29:             {
  30:                 return;
  31:             }
  32:  
  33:             //Filter by DataType and SelectAll column name.
  34:             if (headerUIElement.Header.Column.DataType != typeof(bool) || headerUIElement.Header.Column.Key != this.Control.SelectAllColumnName)
  35:             {
  36:                 return;
  37:             }
  38:  
  39:             //Check the exitence of CheckBoxUIElement.
  40:             //If not, create a new one and wrap it with a WeakReference.
  41:             CheckBoxUIElement checkBoxUIElement = parent.GetDescendant(typeof(CheckBoxUIElement)) as CheckBoxUIElement;
  42:             if (null == checkBoxUIElement)
  43:             {
  44:                 checkBoxUIElement = new ExtendedCheckBoxUIElement(parent);              
  45:             }
  46:             //Add the CheckBoxUIElement and set its position.
  47:             parent.ChildElements.Add(checkBoxUIElement);
  48:             checkBoxUIElement.Rect = new Rectangle(
  49:                         parent.Rect.X + (parent.Rect.Width - checkBoxUIElement.CheckSize.Width) / 2 + 1,
  50:                         parent.Rect.Y + ((parent.Rect.Height - checkBoxUIElement.CheckSize.Height) / 2),
  51:                         checkBoxUIElement.CheckSize.Width,
  52:                         checkBoxUIElement.CheckSize.Height
  53:                         );           
  54:             //For GroupRow, set the Tag as the current CheckState.
  55:             UltraGridRow ultraGridRow = headerUIElement.GetContext(typeof(UltraGridRow)) as UltraGridRow;
  56:             UltraGridGroupByRow parentRow = ultraGridRow.ParentRow as UltraGridGroupByRow;
  57:             if (null != parentRow && null != parentRow.Tag)
  58:             {
  59:                 checkBoxUIElement.CheckState = (CheckState)parentRow.Tag;
  60:             }
  61:  
  62:             if (!this.Control.IsGroupMode)
  63:             {
  64:                 checkBoxUIElement.CheckState = this.Control.CheckState;
  65:             }
  66:         }
  67:  
  68:         public bool BeforeCreateChildElements(UIElement parent)
  69:         {
  70:             return false;
  71:         }
  72:     }
  73: }

四、自定義CheckBoxUIElement

從CheckableHeaderCreationFilter的定義我們可以看到:動態添加的CheckBoxUIElement的類型爲ExtendedCheckBoxUIElement,這是我們自定義的類型。我們通過該類型來設置分組行或者整個UltraGrid(沒有在分組模式下)應有的狀態,並最終對相應的數據行(在分組模式下爲當前分組的所有行,而沒有分組情況下爲整個UltraGrid的所有行)的Check狀態。所有的實現具有體現在重寫的OnCheckStateChange上面。

1: using System.Windows.Forms;

   2: using Infragistics.Win;
   3: using Infragistics.Win.UltraWinGrid;
   4:  
   5: namespace Artech.ExtendedUltraGrid4SelectAll
   6: {
   7:     public class ExtendedCheckBoxUIElement : CheckBoxUIElement
   8:     { 
   9:         public ExtendedCheckBoxUIElement(UIElement parent)
  10:             : base(parent)
  11:         {
  12:             this.ThreeState = false;
  13:         }
  14:  
  15:         public override CheckState CheckState
  16:         {
  17:             get
  18:             {
  19:                 return base.CheckState;
  20:             }
  21:             set
  22:             {
  23:                 CheckState checkState = this.CheckState;
  24:                 base.CheckState = value;
  25:                 if (checkState != value)
  26:                 {
  27:                     this.OnCheckStateChange();
  28:                 }
  29:             }
  30:         }
  31:  
  32:         protected override void OnCheckStateChange()
  33:         {
  34:             base.OnCheckStateChange();
  35:             ExtendedUltraGrid ultraGrid = this.Control as ExtendedUltraGrid;
  36:             HeaderUIElement headerUIElement = this.GetAncestor(typeof(HeaderUIElement))as HeaderUIElement;
  37:             UltraGridRow ultraGridRow = headerUIElement.GetContext(typeof(UltraGridRow))as UltraGridRow;
  38:             UltraGridGroupByRow parentRow = ultraGridRow.ParentRow as UltraGridGroupByRow;
  39:             if (null != parentRow)
  40:             {
  41:                 parentRow.Tag = this.CheckState;
  42:                 this.SetAllGridRowSelected(parentRow.Rows, this.CheckState);
  43:             }
  44:             else
  45:             {
  46:                 this.SetAllGridRowSelected((this.Control as UltraGrid).Rows, this.CheckState);
  47:             }
  48:  
  49:             if (!ultraGrid.IsGroupMode)
  50:             {
  51:                 ultraGrid.CheckState = this.CheckState;
  52:             }
  53:         }
  54:  
  55:         private void SetAllGridRowSelected(RowsCollection rows, CheckState state)
  56:         {
  57:             foreach (var row in rows)
  58:             {
  59:                 if (row.IsGroupByRow)
  60:                 {
  61:                     row.Tag = this.CheckState;
  62:                     SetAllGridRowSelected(((UltraGridGroupByRow)row).Rows, state);
  63:                 }
  64:                 else
  65:                 {
  66:                     string selectAllColumnName = (this.Control as ExtendedUltraGrid).SelectAllColumnName;
  67:                     if (row.Activation == Activation.Disabled) continue;
  68:                     if (!row.Band.Columns.Exists(selectAllColumnName)) continue;
  69:                     if (row.Band.Columns[selectAllColumnName].CellActivation == Activation.Disabled) continue;
  70:                     if (null == row.Cells) continue;
  71:                     row.Cells[selectAllColumnName].Value = state;
  72:                     row.Update();
  73:                 }
  74:             }
  75:         }
  76:     }
  77: }

作者:Artech
出處:http://artech.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章