Designing and Implement Lookup Control for Windows Forms

发布时间:2016-12-8 10:10:39 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Designing and Implement Lookup Control for Windows Forms",主要涉及到Designing and Implement Lookup Control for Windows Forms方面的内容,对于Designing and Implement Lookup Control for Windows Forms感兴趣的同学可以参考一下。

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。圖3Implement  完成了設計圖後,實作就不難了,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 : ListListItem>     {         public int FindValue(string value)         {             for (int i = 0; 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);            Liststring> list = new Liststring>();             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)             {                 Liststring> list = new Liststring>();                 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

上一篇:Inside ObjectBuilder Part 4
下一篇:珍惜自已的爱, 世界上没有後悔药 [转载收藏]

相关文章

相关评论