介绍 我是谁?我在Co
deProject做什么?好吧,我将自己回答所有这些问题和其他问题。 我是一个ComboView控件。你可能会想,那是什么?我是一个组合框,具有在列表视图中显示柱状项目的能力。嗯,你可能会问,还有很多类似的控件可用,那我有什么特别的呢?没什么,唯一不同的是我要向你们讲述我是如何被赋予生命的,以及在我被创造的过程中,我的创造者学到的教训。 在开始的时候 几天前,一个疯狂的开发人员想要创造我。这不是出于对我的爱,而是出于贪婪。对学习的渴望,对理解控制发展的复杂性的渴望等等。所以,你看一个人是很贪婪的。他为自己的需要做任何事。 好吧,让我们看看他计划创造我的时候脑子里都在想些什么。 他需要学习。net中的控件创建(特别是c#)。 他需要了解如何创建复合控件。 他需要理解ListView的工作方式。 他需要了解如何提供自定义数据绑定的细节。 他需要了解如何使用定制事件。 等等…… 我得承认一件事。我不是最好的控制者,甚至不是最接近他们的。但我很高兴,因为在某种程度上,正是通过我,我的创造者理解了上述所有目标(或者我认为他理解了)。 让我们剖析一下我自己,在这个旅程中,你和我可以学到一些东西。 解剖自己 先做重要的事。为了我的存在,我需要有一个父母。开发人员决定用户控件应该是我的父控件。 因此,我继承自System.Windows.Forms.Usercontrol。这意味着我将拥有我的父类(UserControl)的所有属性和行为。隐藏,复制Code
public class MyCombo : System.Windows.Forms.UserControl {
因为我是一个ComboView,为了我的存在,我需要一些其他控件的支持,特别是,一个按钮,一个列表视图和一个文本框。隐藏,复制Code
private System.Windows.Forms.ListView lvObject; private System.Windows.Forms.TextBox txtObject; private System.Windows.Forms.Button btnDropDown;
好的,我将解释为什么以上三种控制是必需的: ListView将用于以多栏形式显示数据。 文本框将用于显示所选的值。 这钮扣可以把我钻上钻下。 然后开发人员需要某些变量来控制我的行为。所以,他在自己的区域宣布。隐藏,复制Code
#region MyCombo Variables private object _dataSource; private string _dataMember; private string _displayMember; private string _valueMember; protected ArrayList _columnHeader = new ArrayList(); private object _selectedValue; private object _selectedText; //Size const int MIN_WIDTH = 140; const int MIN_HEIGHT = 22; #endregion
让我告诉你这些变量对我来说意味着什么,其他的很明显。(稍后,我们将为上述变量分别添加set/get属性。) _dataSource 我需要能够填充来自不同来源的数据,如自定义类,数据库,XML文件等。使用此属性分配数据源。 _dataMember 一个_dataSource可以包含多个表。通过这个属性指定我应该从哪个表中获取数据。 _displayMember 因为我将以多列格式显示自己,所以通过这个属性指定要在文本框中显示哪一列。 _valueMember 理想情况下,这应该是单行数据中每个数据元素的惟一ID。你需要这个值来查询,保存等等。 _selectedValue 这将返回来自_valueMember变量的值。 _selectedText 这将返回_displayMember变量的值。 _columnHeader 这是一个ArrayList。这将保留列的标题。 现在是事件部分。事件是必要的,以便控件的用户知道什么时候发生了事情。现在,开发人员只提供了一个自定义事件。隐藏,复制Code
#region MyCombo Events public delegate void SelectedItemChangedEventHandler(object sender, EventArgs e); public event SelectedItemChangedEventHandler OnSelectedItemChangedHandler; #endregion
每当用户从ListView中选择列表项时,OnSelectedItemChangedHandler就会被触发。 正如我所承诺的,下面是相应的get/set访问器。我的用户会看到这个属性,而不是我们上面看到的变量。隐藏,收缩,复制Code
public string DisplayMember { get { return _displayMember; } set { _displayMember = value; } } public string ValueMember { get { return _valueMember; } set { _valueMember = value; } } public string DataMember { get { return _dataMember; } set { _dataMember = value; } } public object DataSource { get { return _dataSource; } set { _dataSource = value; OnDataBind(); } } public object SelectedText { get { return _selectedText; } set { _selectedText=value; } } public object SelectedValue { get { return _selectedValue; } set { _selectedValue = value; } }
在DataSource属性中,您会看到一个方法OnDataBind()。这将在我们进一步解释。 现在,应该有一种机制可以让我的用户将列分配给我。这由下面的函数来处理。该函数接受两个参数,列的名称和列的宽度。这个函数只是将列名添加到我们在上面看到的ArrayList中。隐藏,复制Code
public void Columns(string columnName, int colWidth) { _columnHeader.Add(columnName); OnHeaderBind(columnName,colWidth); }
现在,让我们看看OnHeaderBind()函数。这个函数将columnName添加到实际的ListView对象中,并设置它的宽度。隐藏,复制Code
protected void OnHeaderBind(object v, int colWidth) { lvObject.Columns.Add(v.ToString(), colWidth, HorizontalAlignment.Left); }
还应该提供手动向me添加数据的条款,而不是使用数据源和数据成员。这可以通过以下函数实现。这个函数接受一个ID和一个要添加到ListView的项目数组。因此,我的用户可以向我添加一个项目,如:Hide Code
<instance of me>.Add ("101","Rajesh","23)
Hide副本,复制Code
public void Add(string id, params string [] items) { ListViewItem lvi = new ListViewItem(id); foreach(string s in items) { lvi.SubItems.Add(s); } lvObject.Items.Add(lvi); }
现在,如前所述,让我们来讨论OnDataBind() method。每当您将数据源分配给我时,就会调用此方法。这个方法只会在ListView中填充来自数据源的信息。隐藏,复制Code
protected void OnDataBind() { if (_dataSource == null) return; IList iList = InnerDataSource(); Type type = iList.GetType(); string s; for (int i = 0; i < iList.Count ; i++) { s= GetField(RuntimeHelpers.GetObjectValue(iList[i]),_valueMember); ListViewItem lvi = new ListViewItem(s); for (int j = 1; j < _columnHeader.Count; j++) { lvi.SubItems.Add(GetField(RuntimeHelpers.GetObjectValue(iList[i]), _columnHeader[j].ToString())); } lvObject.Items.Add(lvi); } }
runtimehelper . getobjectvalue (obj)做什么?如果它是一个值类,它会返回一个obj的盒装副本;否则会返回obj本身。 函数的作用是:返回与数据源关联的IList对象。稍后,我们可以为IList对象包含的每个列表值枚举它。隐藏,收缩,复制Code
private IList InnerDataSource() { IList iList; if (_dataSource is DataSet) { if (_dataMember.Length > 0) { iList = ((IListSource) ((DataSet)_dataSource).Tables[_dataMember]).GetList(); } else { iList = ((IListSource)((DataSet)_dataSource).Tables[0]).GetList(); } } else if (_dataSource is IListSource) { iList = ((IListSource)_dataSource).GetList(); } else if (_dataSource is ICollection) { object[] objs = new object[((ICollection)_dataSource).Count]; ((ICollection)_dataSource).CopyTo(objs,0); iList = objs; } else { iList = (IList)_dataSource; } return iList; }
IListSource:该接口为对象提供了返回可绑定到数据源的列表的功能。 ICollection:此接口为所有集合定义大小、枚举器和同步方法。 编译我,添加一个测试项目和添加对我的参考,我准备面对世界。 现在对我来说就这些了。有很多事情需要对我做。也许,那是以后的事了。 我希望你喜欢读我的书。任何建议、批评、想法都应该直接给创造我的人,这样他才能提高我或者多学习一点。 要获得完整的源代码,请查看随本文上传的示例项目。 那再见了, ComboView 学分 内部数据源和相关函数->这些函数是从代码项目/或互联网上的某个地方获得的。如果有人知道原作者,请给我发个评论,我很感谢他。 修订历史 12-28-2003:原文。 本文转载于:http://www.diyabc.com/frontweb/news341.html