您的位置:首页 > 其它

Designing and Implement Lookup Control for Windows Forms

2007-12-18 21:37 453 查看
 Designing and Implement Lookup Control for Windows Forms  文/黃忠成 What’s Lookup Control  前篇所開發的OrpButtonEdit控件,雖然已經達到了初步的需求,但使用這個控件,設計師仍然必須自行設計開出的查詢視窗、處理選取的資料、回填至ButtonEdit控件中等課題,然而這些動作都是可規格化的,本文中所開發的Lookup Control將針對此問題,做出更便利的選取資料介面。事實上,Lookup Control在很早期的商用應用程式就已出現,她是一個類似ComboBox的控件,只是拉出的視窗不僅僅顯示單欄資料,而是顯示出一個Grid,讓使用者可以看到一整筆資料,而非僅僅單一欄位,見圖1。圖1

設計這樣的控件,有兩個不可缺的關鍵控件,一是DataGridView控件,用來顯示可選取的資料,二是Form控件,DataGridView控件必須存活於Container Control中,例如Panel或是Form,多數情況下,為了得到更大的控制權,3rd Patrt廠商多會選擇使用Form而非Panel,做為DataGridView控件的Container。  Requirement  Lookup Control的需求很簡單,其必須提供DataSource/DataMember等資料繫結所需的屬性,讓設計者設定欲顯示的資料,同時也必須提供一個Columns Collection,允許設計者選取欲列出的欄位。不過由於列出的欄位數量不等,所以可能會出現拉下的視窗太小,不足以顯示所有欄位的問題,因此,Lookup Control必須提供一個屬性,讓設計者可以設定拉下視窗的寬度,至於高度,就不需要設計者插手,由Lookup Control視目前視窗的高度來計算最佳顯示高度即可。 Problem  Lookup Control唯一會遭遇的技術困難是,Form在Windows Forms架構中屬於容器型控件,每個Form都是單獨的個體,而Lookup Control所拉出的Form,必須受控於Lookup Control所在的Form,也就是當Lookup Control所在的Form移動時,這個拉下的Form也要跟著移動,這個問題有兩種解法,一種是MDI介面,不過此種方法雖可達到目的,但卻會引發其它的問題,就控件角度來說,我們不應該要求放Lookup Control的Form一定要是MDI Parent,就UI角度而言,變成MDI介面後會有許多限制。因此能用的方法只剩一個,那就是Form所提供的AddOwnedForm函式,呼叫此函式將欲受此Form管轄的Form傳入,就可以解決此處所遭遇的問題。 Designing  曾看過『深入剖析 ASP.NET組件設計』一書的讀者,應該都還記得,我於該書中撰寫了一個WebComboBox控件,於其中加入了ItemBuilder概念,允許設計師以Plug-In的方式,改變下拉視窗中的內容。現在,我將這個概念運用於此Lookup Control中,讓Lookup Control的層級更抽象化,不僅可以拉下DataGridView控件,也可以拉下各式各樣的控件,圖2是此控件的設計圖。圖2

這張設計圖中,披露了兩個主要的元素,一是OrpCustomEmbedControlEdit,這是一個繼承自OrpCustomButtonEdit的控件,她負責建立下拉視窗,也就是Form容器,並呼叫第二個元素:OrpEmbedEditControl來填入容器中的內容,OrpEmbedEditControl是一個元件,其定義如程式1。程式1
public abstract class EmbedEditControl : Component     {         private Form _clientForm;         private OrpCustomEmbedControlEdit _editControl;         private int _clientFormWidth = -1;           protected Form ClientForm         {             get             {                 return _clientForm;             }         }           [Category("Appearance")]         public int ClientFormWidth         {             get             {                 return _clientFormWidth;             }             set             {                 _clientFormWidth = value;             }         }           [Browsable(false)]         public OrpCustomEmbedControlEdit EditControl         {             get             {                 return _editControl;             }         }           public virtual void InitializeControl(Form clientForm, OrpCustomEmbedControlEdit editControl)         {             _clientForm = clientForm;             _editControl = editControl;         }           public abstract void ParseValue(object value);         public abstract object GetInputValue();         public abstract void ClientFormClosed();           public void CloseClientForm(bool isCancel)         {             EditControl.CloseClientForm(isCancel);         }     }
如你所見,這是一個抽象類別,其中定義了InitializeControl、ParseValue、GetInputValue、ClientFormClosed等函式,當OrpCustomEmbedControlEdit啟動下拉動作時,會建立一個Form,然後呼叫InitializeControl函式,OrpEmbedEditControl必須在此將欲顯示於該下拉視窗中的控件填入,接著ParseValue函式會被呼叫,此處必須依據傳入的值,調整視窗的內容,讓使用者可以看到原本所選取的值,然後必須處理選取資料的動作,當使用者選取資料後,下拉視窗會被關閉,此時GetInputValue函式會被呼叫,其必須傳回使用者所選取的值,最後ClientFormClosed函式會被呼叫,此處可以進行視窗關閉後的後續工作,整個流程圖示如圖3。圖3

Implement  完成了設計圖後,實作就不難了,OrpCustomEmbedControlEdit的工作在於建立下拉視窗,然後呼叫EmbedEditControl元件來填入內容物,這裡會遭遇到一個實作上的困擾,就是何時關閉視窗?這有幾種情況,一是使用者在拉下視窗後,又按下了下拉按鈕,此時自然得關閉視窗,這是Cancel模式,使用者選取的值不會填回OrpCustomEmbedControlEdit中。二是使用者於拉下視窗後,將焦點移到其它控件上,此時一樣視為Cancel模式,關閉視窗。三是使用者調整了含有OrpCustomEmbedControlEdit控件Form的大小,或是於其上點選了滑鼠,這一樣視為Cacnel模式。程式2為OrpCustomEmbedControlEdit的原始碼列表,讀者可於其中看到處理視窗何時開啟、何時關閉的程式碼。程式2
[ToolboxItem(false)]     public class OrpCustomEmbedControlEdit : OrpCustomButtonEdit     {         private EmbedEditControl _embedEditControl = null;         private Form _clientForm = null;         private bool _skipLostFocus = false;         private int _clientFormWidth = -1;         private DateTime _closeTime = DateTime.Now;           [Category("Appearance")]         public int ClientFormWidth         {             get             {                 return _clientFormWidth;             }             set             {                 _clientFormWidth = value;             }         }           protected Form ClientForm         {             get             {                 if (_clientForm == null)                     _clientForm = CreateClientForm();                 return _clientForm;             }         }           protected bool Droped         {             get             {                 return (_clientForm != null);             }         }           protected EmbedEditControl EmbedEditControl         {             get             {                 return _embedEditControl;             }             set             {                 _embedEditControl = value;             }         }           protected virtual Form CreateClientForm()         {             return new Form();         }           protected internal virtual void CloseClientForm(bool isCancel)         {             if (_clientForm != null)             {                 Form ownerForm = FindForm();                 if (ownerForm != null)                 {                     ownerForm.MouseClick -= new MouseEventHandler(ownerForm_MouseClick);                     ownerForm.Activated -= new EventHandler(ownerForm_Activated);                     ownerForm.Resize -= new EventHandler(ownerForm_Resize);                     ownerForm.RemoveOwnedForm(_clientForm);                 }                 if (EmbedEditControl != null)                 {                     if (!isCancel)                         Text = (string)EmbedEditControl.GetInputValue();                     EmbedEditControl.ClientFormClosed();                 }                 _clientForm.Close();                 _clientForm.Dispose();                 _clientForm = null;             }         }           private void ShowClientForm()         {             Point pt = PointToScreen(new Point(Left, Top));             ClientForm.Location = new Point(pt.X - Left - 2, pt.Y - Top + Height - 1);             ClientForm.Width = Width;             ClientForm.Height = Screen.PrimaryScreen.Bounds.Height - ClientForm.Top - 30;             ClientForm.FormBorderStyle = FormBorderStyle.None;             ClientForm.Font = (Font)Font.Clone();             ClientForm.BackColor = SystemColors.Window;             if (ClientForm.Height > 160)                 ClientForm.Height = 160;             ClientForm.StartPosition = FormStartPosition.Manual;             ClientForm.ShowInTaskbar = false;             Form ownerForm = FindForm();             if (ownerForm != null)             {                 ownerForm.AddOwnedForm(ClientForm);                 ownerForm.MouseClick += new MouseEventHandler(ownerForm_MouseClick);                 ownerForm.Activated += new EventHandler(ownerForm_Activated);                 ownerForm.Resize += new EventHandler(ownerForm_Resize);             }               if (EmbedEditControl != null && EmbedEditControl.ClientFormWidth != -1)                 ClientForm.Width = EmbedEditControl.ClientFormWidth;             else if (ClientFormWidth != -1)                 ClientForm.Width = ClientFormWidth;         }           void ownerForm_Resize(object sender, EventArgs e)         {             CloseClientForm(true);         }           void ownerForm_Activated(object sender, EventArgs e)         {             if (((Form)sender).ActiveControl != this)                 CloseClientForm(true);         }           protected override void OnLostFocus(EventArgs e)         {             base.OnLostFocus(e);             if (Droped)             {                 if (_skipLostFocus)                     _skipLostFocus = false;                 else                     CloseClientForm(true);                 _closeTime = DateTime.Now;             }         }           void ownerForm_MouseClick(object sender, MouseEventArgs e)         {            CloseClientForm(true);         }           protected override void EmbedButtonClick(EventArgs args)         {             if (Droped)                 CloseClientForm(false);             else             {                 TimeSpan ts = DateTime.Now - _closeTime;                 if (ts.TotalMilliseconds > 200)                 {                     _skipLostFocus = true;                     ShowClientForm();                     if (EmbedEditControl != null)                     {                         EmbedEditControl.InitializeControl(ClientForm, this);                         EmbedEditControl.ParseValue(Text);                     }                     ClientForm.Visible = true;                 }             }         }     }
OrpCustomEmbedControlEdit控件不是一個可顯示於Toolbox Pattern上的控件,其繼承者:OrpEmbedControlEdit才是。程式3
[ToolboxItem(true)]     public class OrpEmbedControlEdit : OrpCustomEmbedControlEdit     {         [Category("Behavoir")]         public EmbedEditControl EditControl         {             get            {                 return EmbedEditControl;             }             set             {                 EmbedEditControl = value;             }         }     }
 Implement ComboBox  完成了OrpCustomEmbedControlEdit這個基底控件後,現在我們可以將焦點放在如何設計可用的EmbedEditControl元件:一個類似ComboBox的控件,她與一般的ComboBox控件不同的是,其內容是可以切換的,舉個例來說,設計師可以放一個OrpEmbedControlEdit控件到Form上,放兩個ListEmbedEditControl元件到Form上,此時該OrpEmbedControlEdit可以動態的切換要使用那個ListEmbedEditControl來顯示可選取的資料,如圖4。圖4

聰明的你,是否看出OrpEmbedEditControl這個設計的真正意含?是的!可動態切換的下拉視窗內容,可以讓設計師只用一個控件,應對不同的情況。程式4是ListEmbedEditControl元件的原始碼。程式4
using System; using System.Drawing.Design; using System.ComponentModel; using System.Collections; using System.Collections.Generic; using System.Text; using System.Windows.Forms;   namespace LookupComboBox {     [TypeConverter(typeof(ListItemConverter)),      Serializable]     public sealed class ListItem     {         private string _text, _value;           public string Text         {             get             {                 return _text;             }             set             {                 _text = value;             }         }           public string Value         {             get             {                 return _value;             }             set             {                 _value = value;             }         }           public ListItem(string text, string value)         {             _text = text;             _value = value;         }           public ListItem()         {         }     }       [Serializable]     public class ListItems : List     {         public int FindValue(string value)         {             for (int i = 0; i < Count; i++)             {                 if (this[i].Value.Equals(value))                     return i;             }             return -1;         }     }       public class ListEmbedEditControl : EmbedEditControl     {         private ListItems _items;         private ListBox _innerListBox = null;         private object _dataSource;         private string _displayMember, _valueMember;           [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]         [Category("Data")]         public ListItems Items         {             get             {                 if (_items == null)                     _items = new ListItems();                 return _items;             }         }           [AttributeProvider(typeof(IListSource))]         [Category("Data")]         public object DataSource         {             get             {                 return _dataSource;             }             set             {                 if (((value != null) && !(value is IList)) && !(value is IListSource))                     throw new ArgumentException("only implement IList or IListSource can be set.");                 _dataSource = value;             }         }           [DefaultValue(""), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]         [Category("Data")]         public string DisplayMember         {             get             {                 return _displayMember;             }             set             {                 _displayMember = value;             }         }           [DefaultValue(""), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]         [Category("Data")]         public string ValueMember         {             get             {                 return _valueMember;             }             set             {                 _valueMember = value;             }         }           public override void InitializeControl(Form clientForm, OrpCustomEmbedControlEdit editControl)         {             base.InitializeControl(clientForm, editControl);             _innerListBox = new ListBox();             _innerListBox.Click += new EventHandler(_innerListBox_Click);             _innerListBox.KeyDown += new KeyEventHandler(_innerListBox_KeyDown);                        _innerListBox.Dock = DockStyle.Fill;             if (DataSource == null)             {                 foreach (ListItem item in Items)                     _innerListBox.Items.Add(item);                 _innerListBox.DisplayMember = "Text";                 _innerListBox.ValueMember = "Value";             }             else             {                 _innerListBox.DataSource = DataSource;                 _innerListBox.DisplayMember = DisplayMember;                 _innerListBox.ValueMember = ValueMember;             }             _innerListBox.BorderStyle = BorderStyle.Fixed3D;             clientForm.Controls.Add(_innerListBox);         }           void _innerListBox_KeyDown(object sender, KeyEventArgs e)         {             if (e.KeyCode == Keys.Return)                 CloseClientForm(false);             else if (e.KeyCode == Keys.Escape)                 CloseClientForm(true);         }           void _innerListBox_Click(object sender, EventArgs e)         {             CloseClientForm(false);         }           public override void ParseValue(object value)         {             int index = Items.FindValue((string)value);             if (index != -1)                 _innerListBox.SelectedIndex = index;         }           public override object GetInputValue()         {             if (_innerListBox != null && _innerListBox.SelectedItem != null)             {                 if (_innerListBox.SelectedItem is ListItem)                     return ((ListItem)_innerListBox.SelectedItem).Value;                 else if(_innerListBox.SelectedValue != null)                     return _innerListBox.SelectedValue.ToString();             }             return string.Empty;         }           public override void ClientFormClosed()         {             if (_innerListBox != null)             {                 _innerListBox.Click -= new EventHandler(_innerListBox_Click);                 _innerListBox.KeyDown -= new KeyEventHandler(_innerListBox_KeyDown);             }         }     }       [ToolboxItem(true)]     public class OrpComboBox : OrpCustomEmbedControlEdit     {         [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]         [Category("Data")]         public ListItems Items         {             get             {                 return ((ListEmbedEditControl)EmbedEditControl).Items;             }         }           [AttributeProvider(typeof(IListSource))]         [Category("Data")]         public object DataSource         {             get             {                 return ((ListEmbedEditControl)EmbedEditControl).DataSource;             }             set             {                 ((ListEmbedEditControl)EmbedEditControl).DataSource = value;             }         }           [DefaultValue(""), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]         [Category("Data")]         public string DisplayMember         {             get             {                 return ((ListEmbedEditControl)EmbedEditControl).DisplayMember;             }             set             {                 ((ListEmbedEditControl)EmbedEditControl).DisplayMember = value;             }         }           [DefaultValue(""), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]         [Category("Data")]         public string ValueMember         {             get             {                 return ((ListEmbedEditControl)EmbedEditControl).ValueMember;             }             set             {                 ((ListEmbedEditControl)EmbedEditControl).ValueMember = value;             }         }           public OrpComboBox()             : base()         {             EmbedEditControl = new ListEmbedEditControl();         }     } }  
關於ListItems、DesignerSerializationVisibility及TypeConverter部份,請參考拙著:『深入剖析 ASP.NET組件設計』一書,此處就不再贅述。ListEmbedEditControl元件的重點只有一個,那就是InitializeControl函式,此處建立了一個ListBox控件,並放入由OrpCustomEmbedControlEdit所傳入的Form中,剩下的動作就是如何與其互動罷了,圖5是執行畫面。

你也可以使用前面所開發的OrpEmbedControlEdit控件,而非OrpComboBox(這是一個整合了OrpEmbedControlEdit控件及ListEmbedEditControl元件的控件),圖6是其設計時期畫面。圖6

 Implement LookupEdit  如果你可以看懂ListEmbedEditControl元件,那麼接下來的GridEmbedEditControl元件也就不難了,重點同樣在InitializeControl函式,只是從ListBox變成DataGridView而已。程式5
using System; using System.Drawing; using System.Drawing.Design; using System.ComponentModel; using System.Collections; using System.Collections.Generic; using System.Text; using System.Windows.Forms;   namespace LookupComboBox {     [TypeConverter(typeof(LookupColumnItemConverter)),      Serializable]     public class LookupColumnItem     {         private string _header = string.Empty, _displayMember;         private int _width;         [NonSerialized]         private LookupColumnItems _owner;           protected internal LookupColumnItems Owner         {             get             {                 return _owner;             }             set             {                 _owner = value;             }         }           public string Header         {             get             {                 return _header;             }             set             {                 _header = value;             }         }           [TypeConverter(typeof(LookupColumnNameConverter))]         public string DisplayMember         {             get             {                 return _displayMember;             }             set             {                 _displayMember = value;                 if (Header == string.Empty)                     Header = value;             }         }           public int Width         {             get             {                 return _width;             }             set             {                 _width = value;             }         }           public LookupColumnItem(string header, string displayMember, int width)         {             _header = header;             _displayMember = displayMember;             _width = width;         }           public LookupColumnItem()         {         }     }       [Serializable]     public class LookupColumnItems : CollectionBase     {         private GridEmbedEditControl _owner;           public LookupColumnItem this[int index]         {             get             {                 return (LookupColumnItem)base.List[index];             }             set             {                 base.List[index] = value;             }         }           internal GridEmbedEditControl Owner         {             get             {                 return _owner;             }         }           public void Add(LookupColumnItem value)         {             ((IList)this).Add(value);         }           public void AddRange(LookupColumnItem[] values)         {             foreach (LookupColumnItem item in values)                 Add(item);         }           protected override void OnInsertComplete(int index, object value)         {             base.OnInsertComplete(index, value);             ((LookupColumnItem)value).Owner = this;         }           public LookupColumnItems(GridEmbedEditControl owner)             : base()         {             _owner = owner;         }     }       public class GridEmbedEditControl : EmbedEditControl     {         private object _dataSource;         private string _dataMember;         private BindingSource _bindingSource;         private LookupColumnItems _items;         private DataGridView _gridView = null;           [AttributeProvider(typeof(IListSource))]         [Category("Data")]         public object DataSource         {             get             {                 return _dataSource;             }             set             {                 if (((value != null) && !(value is IList)) && !(value is IListSource))                     throw new ArgumentException("only implement IList or IListSource can be set.");                 _dataSource = value;             }         }           [TypeConverter(typeof(DataMemberConverter))]         [Category("Data")]         public string DataMember         {             get             {                 return _dataMember;             }             set             {                 _dataMember = value;             }         }           [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]         [Category("Data")]         public LookupColumnItems Items         {             get             {                 if (_items == null)                     _items = new LookupColumnItems(this);                 return _items;             }         }           public override void InitializeControl(Form clientForm, OrpCustomEmbedControlEdit editControl)         {             bool hasCustomColumnSize = false;             base.InitializeControl(clientForm, editControl);             _bindingSource = new BindingSource();             _bindingSource.DataSource = _dataSource;             _bindingSource.DataMember = _dataMember;             _gridView = new DataGridView();             _gridView.AutoGenerateColumns = false;             _gridView.AllowUserToAddRows = false;             _gridView.AllowUserToDeleteRows = false;             _gridView.AllowUserToOrderColumns = false;             _gridView.AllowUserToResizeColumns = false;             _gridView.AllowUserToResizeRows = false;             _gridView.BorderStyle = System.Windows.Forms.BorderStyle.None;             _gridView.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;             _gridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;             _gridView.GridColor = System.Drawing.SystemColors.Control;             _gridView.MultiSelect = false;             _gridView.ReadOnly = true;             _gridView.RowHeadersVisible = false;             _gridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;             _gridView.RowTemplate.Height = 24;             _gridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;             _gridView.TabIndex = 1;             _gridView.Dock = DockStyle.Fill;             _gridView.BorderStyle = BorderStyle.Fixed3D;             _gridView.CellClick += new DataGridViewCellEventHandler(_gridView_CellClick);             _gridView.KeyDown += new KeyEventHandler(_gridView_KeyDown);             foreach (LookupColumnItem item in Items)             {                 DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();                 column.HeaderText = item.Header;                 column.DataPropertyName = item.DisplayMember;                 if (column.Width != 0)                 {                     hasCustomColumnSize = true;                     column.Width = item.Width;                 }                    _gridView.Columns.Add(column);             }             if (!hasCustomColumnSize)                 _gridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;             _gridView.DataSource = _bindingSource;             _gridView.Font = (Font)editControl.Font.Clone();             clientForm.Controls.Add(_gridView);             clientForm.ActiveControl = _gridView;         }           void _gridView_KeyDown(object sender, KeyEventArgs e)         {             if (e.KeyCode == Keys.Return)                 CloseClientForm(false);             else if (e.KeyCode == Keys.Escape)                 CloseClientForm(true);         }           void _gridView_CellClick(object sender, DataGridViewCellEventArgs e)         {             CloseClientForm(false);         }           public override void ParseValue(object value)         {             if (Items.Count > 0)             {                 try                 {                     int index = _bindingSource.Find(Items[0].DisplayMember, value);                     if (index != -1)                         _bindingSource.Position = index;                     else                         _bindingSource.Position = 0;                 }                 catch (Exception)                 {                 }             }         }           public override object GetInputValue()         {             if (Items.Count > 0)             {                 object data = _bindingSource.Current;                 if (data != null)                 {                     PropertyDescriptor pd = TypeDescriptor.GetProperties(data).Find(Items[0].DisplayMember, false);                     if (pd != null)                     {                         object value = pd.GetValue(data);                         if (value != null)                             return value.ToString();                     }                   }             }             return string.Empty;         }           public override void ClientFormClosed()         {             if (_gridView != null)             {                 _gridView.CellClick -= new DataGridViewCellEventHandler(_gridView_CellClick);                 _gridView.KeyDown -= new KeyEventHandler(_gridView_KeyDown);                 _gridView.DataSource = null;                                if(_bindingSource != null)                     _bindingSource.Dispose();             }         }     }           [ToolboxItem(true)]     public class OrpLookupEdit : OrpCustomEmbedControlEdit     {         [AttributeProvider(typeof(IListSource))]         [Category("Data")]         public object DataSource         {             get             {                 return ((GridEmbedEditControl)EmbedEditControl).DataSource;             }             set             {                 ((GridEmbedEditControl)EmbedEditControl).DataSource = value;             }         }           [TypeConverter(typeof(DataMemberConverter))]         [Category("Data")]         public string DataMember         {             get             {                 return ((GridEmbedEditControl)EmbedEditControl).DataMember;             }             set             {                 ((GridEmbedEditControl)EmbedEditControl).DataMember = value;             }         }           [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]         [Category("Data")]         public LookupColumnItems Items         {             get             {                 return ((GridEmbedEditControl)EmbedEditControl).Items;             }         }           public OrpLookupEdit()             : base()         {             EmbedEditControl = new GridEmbedEditControl();         }     } }  
程式7是這兩個元件所用到的Design-Time程式碼列表。程式7
using System; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Globalization; using System.Windows.Forms;   namespace LookupComboBox {     sealed class ListItemConverter : ExpandableObjectConverter     {         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)         {             if (destinationType == typeof(InstanceDescriptor))             {                 return true;             }             else             {                 return base.CanConvertTo(context, destinationType);             }         }           public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)         {             if (destinationType == null)             {                 throw new Exception("destination type is null.");             }             if (destinationType == typeof(InstanceDescriptor) && value is ListItem)             {                 ListItem item = (ListItem)value;                 ConstructorInfo constructorInfo = typeof(ListItem).GetConstructor(new Type[] { typeof(string), typeof(string) });                 if (constructorInfo != null)                 {                     return new InstanceDescriptor(constructorInfo, new object[] { item.Text, item.Value });                 }             }             return base.ConvertTo(context, culture, value, destinationType);         }     }       sealed class LookupColumnItemConverter : ExpandableObjectConverter     {         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)         {             if (destinationType == typeof(InstanceDescriptor))             {                 return true;             }             else             {                 return base.CanConvertTo(context, destinationType);             }         }           public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)         {             if (destinationType == null)             {                 throw new Exception("destination type is null.");             }             if (destinationType == typeof(InstanceDescriptor) && value is LookupColumnItem)             {                 LookupColumnItem item = (LookupColumnItem)value;                 ConstructorInfo constructorInfo = typeof(LookupColumnItem).GetConstructor(new Type[] { typeof(string), typeof(string), typeof(int) });                 if (constructorInfo != null)                     return new InstanceDescriptor(constructorInfo, new object[] { item.Header, item.DisplayMember, item.Width });             }             return base.ConvertTo(context, culture, value, destinationType);         }     }       sealed class LookupColumnNameConverter : StringConverter     {         public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)         {             GridEmbedEditControl control = (GridEmbedEditControl)((LookupColumnItems)((LookupColumnItem)context.Instance).Owner).Owner;             PropertyDescriptorCollection cols = ListBindingHelper.GetListItemProperties(control.DataSource, control.DataMember, null);            List list = new List();             foreach (PropertyDescriptor pd in cols)                 list.Add(pd.Name);             StandardValuesCollection retCols = new StandardValuesCollection(list);             return retCols;         }           public override bool GetStandardValuesSupported(ITypeDescriptorContext context)         {             return true;         }     }       sealed class DataMemberConverter : StringConverter     {         public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)         {             PropertyDescriptor pd = TypeDescriptor.GetProperties(context.Instance).Find("DataSource", true);             if (pd != null)             {                 List list = new List();                 object dataSource = pd.GetValue(context.Instance);                 PropertyDescriptorCollection cols = ListBindingHelper.GetListItemProperties(dataSource);                 foreach (PropertyDescriptor pdItem in cols)                    list.Add(pdItem.Name);                 StandardValuesCollection retCols = new StandardValuesCollection(list);                 return retCols;             }             return base.GetStandardValues(context);         }           public override bool GetStandardValuesSupported(ITypeDescriptorContext context)         {             return true;         }     } }  
 It’s Flexable?  無疑的,OrpEmbedControlEdit及OrpEmbedEditControl的搭配,將這種控件的延展性發揮到一個極致,當然!如果你問我,還有可以增進的空間嗎?我的答案會是有,只是目前尚未想到罷了。 Conclusion  在這兩篇文章中,我跳過了許多的基礎知識,不談Design-Time部份的處理,將重點放在了設計與問題的解決上,這使得這兩篇文章的易讀性降低不少,不過換來的是,你得到了兩個可以立即運用在現實專案上的控件。v 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1145846
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: