自订类的属性与字段如何枚举并提供控件作为系结来源?

我在“ 数组详论”与“Enum详论”两篇文章中曾经介绍过如何将数组以及 Enum 项目当作系结控件的数据来源。然而,无论是数组或是 Enum 项目, 它们都有设定和使用上的巨大限制。其中, Enum 的每个项目都必须是常值, 换句话说, 项目的值无法动能控制。而数组的值虽然可以动态变更, 但无法提供设计时的 Intellisense 支持...

我在“ 数组详论”与“Enum详论”两篇文章中曾经介绍过如何将数组以及 Enum 项目当作系结控件的数据来源。然而,无论是数组或是 Enum 项目, 它们都有设定和使用上的巨大限制。其中, Enum 的每个项目都必须是常值, 换句话说, 项目的值无法动能控制。而数组的值虽然可以动态变更, 但无法提供设计时的 Intellisense 支持。

建立自订类

如果你想综合所有的优点, 你就必须使用自订类, 如下例:

public class clsPeriodForQuery

{

?? public int 今天 { get { return 0; } }

?? public int 今天跟昨天 { get { return 1; } }

?? public int 最近三天 { get { return 2; } }

?? public int 这个礼拜 { get { return (int)DateTime.Now.DayOfWeek; } }

?? public int 最近两个礼拜 { get { return 这个礼拜 + 7; } }

?? public int 最近三个礼拜 { get { return 这个礼拜 + 14; } }

?? public int 最近四个礼拜 { get { return 这个礼拜 + 21; } }

?? public int 这个月 { get { return DateTime.Now.Day - 1; } }

?? public int 最近两个月

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-1).Month, 1);

?????????? return span.Duration().Days - 1;

?????? }

?? }

?? public int 最近半年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-6).Month, 1);

?????????? return span.Duration().Days;

?????? }

?? }

?? public int 今年 { get { return DateTime.Now.DayOfYear - 1; } }

?? public int 最近一年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = (new DateTime(today.Year, 12, 31) - new DateTime(today.Year, 1, 1));

?????????? return span.Duration().Days - 1;

?????? }

?? }

}

以上这个类内含“今天”、“今天跟昨天”、“最近三天”、“这个礼拜”、“最近两个礼拜”、“最近三个礼拜”、“最近四个礼拜”、“这个月”、“最近两个月”、“最近半年”、“今年”与“最近一年”等项目, 其值就是距离今天的天数。如同你可以看见的, 在以上各个项目中, 有些是常值(Constant), 有些必须经过运算才能得到。像这种结构, 你无法以 Enum 来表示。当然你可以改用数组或集合(Collection)对象, 但是在设计时期却无法枚举。但如果设计成自订类, 就可以达成所有的功能。

实践 IListSource 以作为数据来源

但是, 一般的自订类是无法直接提供给系结控件作为数据来源的。要让一个自订类当作数据来源, 你的类必须实践 IListSource、IEnumerable 或 IDataSource 才行。实践 IListSource 大概是最简单、最容易的; 以下我展示一个已经写好可用的范例:

using System.Reflection;

using System.ComponentModel;

...

public class clsPeriods :? IListSource

{

?? public int 今天 { get { return 0; } }

?? public int 今天跟昨天 { get { return 1; } }

?? public int 最近三天 { get { return 2; } }

?? public int 这个礼拜 { get { return (int)DateTime.Now.DayOfWeek; } }

?? public int 最近两个礼拜 { get { return 这个礼拜 + 7; } }

?? public int 最近三个礼拜 { get { return 这个礼拜 + 14; } }

?? public int 最近四个礼拜 { get { return 这个礼拜 + 21; } }

?? public int 这个月 { get { return DateTime.Now.Day - 1; } }

?? public int 最近两个月

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-1).Month, 1);

?????????? return span.Duration().Days - 1;

?????? }

?? }

?? public int 最近半年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-6).Month, 1);

?????????? return span.Duration().Days;

?????? }

?? }

?? public int 今年 { get { return DateTime.Now.DayOfYear - 1; } }

?? public int 最近一年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = (new DateTime(today.Year, 12, 31) - new DateTime(today.Year, 1, 1));

?????????? return span.Duration().Days - 1;

?????? }

?? }

?? public clsPeriods() { } // Constructor

?? bool IListSource.ContainsListCollection

?? {

?????? get { return false; }

?? }

?? IList IListSource.GetList()

?? {

?????? BindingList list = new BindingList();

?????? PropertyInfo[] pInfos = typeof(clsPeriods).GetProperties();

?????? foreach (PropertyInfo info in pInfos)

?????? {

?????????? string text = info.Name;

?????????? clsPeriodscls = new clsPeriods();

?????????? object obj = info.GetValue(cls, null);

?????????? int value = 0;

?????????? if (int.TryParse(obj.ToString(), out value))

?????????????? list.Add(new pair(text, value));

?????? }

?????? return (IList) list;

?? }

}

public class pair

{

?? string _Key;

?? int _Value;

?? public string Key

?? {

?????? get { return _Key; }

?????? set { _Key = value; }

?? }

?? public int Value

?? {

?????? get { return _Value; }

?????? set { _Value = value; }

?? }

?? public pair() { }

?? public pair(string k, int v) {

?????? Key = k;

?????? Value = v;

?? }

}

在上例中, 我必须另外建立名为 pair 的自订类, 它只是一个单纯用来存放 Key/Value Pair 的容器而已。在 VS2008/.Net Framework 3.5 中, 这种类的写法可以再简化一点:

public class pair

{

?? public string Key { set; get; } // Only on VS2008

?? public int Value { set; get; } // Only on VS2008

?? public pair() { }

?? public pair(string k, int v) {

?????? Key = k;

?????? Value = v;

?? }

}

此外, 为了在执行时期取出设计时期加入的类资讯 (在这里指的是类的 Properties 项目资讯), 所以我们必须用到 Reflection 命名空间下的方法, 所以请记得加上 using System.Reflection; 命令。同时, 为了实践 IListSource, 我们也必须引用 ComponentModel 命名空间。

实践 IListSource 界面时, 你必须同时实践 ContainsListCollection 这个 Property, 并实践 GetList() 方法以返回一个 IList 实例, 如范例中所示。

现在, 我们已经能将这个自订类当作系结控件的数据来源了:

clsPeriods cls = new clsPeriods();

ddlPeriods.DataSource = cls;

ddlPeriods.DataTextField = "Key";

ddlPeriods.DataValueField = "Value";

ddlPeriods.DataBind();

透过这种方式, 我们就能够使用自订类以取代 Enum 以提供可以动态变更内容的系结来源。

更简单的做法

在上面的范例中, 为了提供像 DropDownList 之类具有 TextField 与 ValueField 的控件以作为数据来源, 我们又另外制作了称为 pair 的自订类型。从好的方向想, 这种做法提供了很大的弹性, 你可以以这个模型为基础, 继续发展更多的应用。不过话说回来, 我原来只是想稍为增强 Enum 功能而已, 我并不想因为这个目的, 而需要特别去维护一个类型。我难道不能简单的使用 .Net 已经提供的既有类型吗?

.Net 有很多很好用的集合类型可以使用, 如果你不想自己创建一个自订类型的话, 我们可以从现有的 .Net 类型中挑选一个来使用。以下是使用 SortedList 类型的范例:

using System.Reflection;

...

public class clsPeriods

{

?? public int 今天 { get { return 0; } }

?? public int 今天跟昨天 { get { return 1; } }

?? public int 最近三天 { get { return 2; } }

?? public int 这个礼拜 { get { return (int)DateTime.Now.DayOfWeek; } }

?? public int 最近两个礼拜 { get { return 这个礼拜 + 7; } }

?? public int 最近三个礼拜 { get { return 这个礼拜 + 14; } }

?? public int 最近四个礼拜 { get { return 这个礼拜 + 21; } }

?? public int 这个月 { get { return DateTime.Now.Day - 1; } }

?? public int 最近两个月

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-1).Month, 1);

?????????? return span.Duration().Days - 1;

?????? }

?? }

?? public int 最近半年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = today - new DateTime(today.Year, today.AddMonths(-6).Month, 1);

?????????? return span.Duration().Days;

?????? }

?? }

?? public int 今年 { get { return DateTime.Now.DayOfYear - 1; } }

?? public int 最近一年

?? {

?????? get

?????? {

?????????? DateTime today = DateTime.Now;

?????????? TimeSpan span = (new DateTime(today.Year, 12, 31) - new DateTime(today.Year, 1, 1));

?????????? return span.Duration().Days - 1;

?????? }

?? }

}

public SortedList slPeriods

{

?? get

?? {

?????? SortedList list = new SortedList();

?????? PropertyInfo[] pInfos = typeof(clsPeriodForQuery).GetProperties();

?????? foreach (PropertyInfo info in pInfos)

?????? {

?????????? string text = info.Name;

?????????? clsPeriodForQuery cls = new clsPeriodForQuery();

?????????? object value = info.GetValue(cls, null);

?????????? list.Add(value, text);

?????? }

?????? return list;

?? }

}

在上面范例中, 我只是很简单的使用 Reflection 命名空间下的功能, 把 clsPeriods 的 Properties 撷取出来并填入一个 SortedList 对象并回传而已。由于使用的是 SortedList 对象, 我们取出枚举数值的时候, 它都是自动排列的。所以这个范例和上个范例不同, 我们取到的值都是按天数多寡排过顺序的。同时, 由于我在塞入 SortedList 的 Text 与 Value 字段对调过了, 所以它被用作数据系结控件的数据来源时, DropDownList 的字段也必须对调:

ddlPeriods.DataSource = slPeriods;

ddlPeriods.DataTextField = "Value";

ddlPeriods.DataValueField = "Key";

ddlPeriods.DataBind();

如果你不希望排序的话, 你可以把 SortedList 类型改成 HashTable 类型, 它就不会排序了。

总结

以上两个范例都用在 TextField 与 ValueField 不一样的场合。如果你不需要这样做, 你可以无需自订 pair 类型, 使用字符串即可。.Net 就是这样, 对于同样一种需求, 你可能可以使用两百种做法来实现, 就看你最熟悉哪种做法, 或是哪种做法最有效率。

一般而言, 写死在程序里面的东西效率通常最好, 但是也最没有弹性; 如果可以写进数据库, 那么它的效率最低, 但是很容易修改。在本文范例中, 其实你也可以把列表由数据库直接产生(使用 Stored Procedure 来撰写程序逻辑), 然后使用 ADO.NET 工具读取出来并填入容器对象。但如此一来, 如果数据系结动作很频繁, 难免会影响到性能。

折衷之道, 就是如范例般写在自订类里面。这个自订类可以放在外部的类库(Class Library)项目里面, 如果有更改, 也不会导致网站项目需要重新编译, 如此弹性也会比较大。



Dev 2Share @ 点部落

原文:大专栏  自订类的属性与字段如何枚举并提供控件作为系结来源?

原文地址:https://www.cnblogs.com/petewell/p/11510010.html

时间: 2024-10-14 09:22:42

自订类的属性与字段如何枚举并提供控件作为系结来源?的相关文章

Django中ORM模型总结(二)[模型类的对应关系,模型类的属性,字段类型]

模型类的对应关系 多对多 创建模型类----->新闻类型类 class TypeInfo(models.Model): """创建新闻模型类""" tname = models.CharField(max_length=20) 创建模型类----->新闻内容类 class NewInfo(models.Model): """闯将新闻内容类""" ntitle = models

FineUI 3升级4.1.1时,SingleClickExpand属性改什么了? (树控件单击展开)

private Tree InitTreeMenu(List<Menu> menus) { Tree treeMenu = new Tree(); treeMenu.ID = "treeMenu"; treeMenu.EnableArrows = true; treeMenu.ShowBorder = false; treeMenu.ShowHeader = false; treeMenu.EnableIcons = false; treeMenu.AutoScroll =

Xtrareport 报表的一些属性及控件

报表结构 整个报表是由多个绑定带区组成,绑定带区如下: 绑定带区 说明 TopMarginBand 每个页面上面都显示的空白(天头),在PageHeaderBand或者ReportHeaderBand上面 ReportHeaderBand 在报表起始位置(报表头), 此带区被设计用于显示某些概述信息,例如报表的封面. PageHeaderBand 在每个页面的上方(页眉),在TopMarginBand或者ReportHeaderBand下方 GroupHeaderBand 在每组的起始位置,或者

C#控件方法及属性大全,望补充

C#控件及常用设计整理 1.窗体 常用属性 (1)Name属性:用来获取或设置窗体的名称,在应用程序中可通过Name属性来引用窗体. (2) WindowState属性: 用来获取或设置窗体的窗口状态. 取值有三种: Normal (窗体正常显示). Minimized (窗体以最小化形式显示)和 Maximized(窗体以最大化形式显示). (3)StartPosition属性:用来获取或设置运行时窗体的起始位置. (4)Text属性:该属性是一个字符串属性,用来设置或返回在窗口标题栏中显示的

C#控件事件属性大全

C#控件及常用设计整 1.窗体... 1 2.Label 控件... 3 3.TextBox 控件... 4 4.RichTextBox控件... 5 5.NumericUpDown 控件... 7 6.Button 控件... 7 7.GroupBox 控件... 7 8.RadioButton控件... 8 9.CheckBox 控件... 8 10.ListBox 控件... 9 11.ComboBox 控件... 10 12.CheckedListBox 控件... 10 13.Pict

WPF控件自绘——基础,Control类的定义

用于记录自己的学习WPF控件,大神请飘过... [WPF控件类继承关系图] 所有可以自定义模版的控件都是从Control继承,所以我们来看看Contorl类里面到底有些什么.为以后的控件自定义模版做好准备.废话少说先来看看WPF中Control类的定义 1 namespace System.Windows.Controls 2 { 3 public class Control : FrameworkElement 4 { 5 public static readonly DependencyPr

第一篇:初识ASP.NET控件开发_第一节:控件类及其继承关系

1)System.Web.UI.Control(以下简称Control) Control 类是包括自定义控件.用户控件和页在内的所有 ASP.NET 服务器控件的基类..定义由所有 ASP.NET 服务器控件共享的属性.方法和事件. 命名空间:System.Web.UI程序集:System.Web(在 system.web.dll 中) 2)System.Web.UI.WebControls.WebControl(以下简称WebControl) WebControl 类是 System.Web.

visual studio开发工具的C#主流控件属性一览表

visual studio开发工具的C#主流控件属性一览表 详细的介绍了各控制属性的详细中文介绍 C#控件及常用设计整理 1.窗体 1.常用属性 (1)Name属性:用来获取或设置窗体的名称,在应用程序中可通过Name属性来引用窗体. (2) WindowState属性: 用来获取或设置窗体的窗口状态. 取值有三种: Normal (窗体正常显示). Minimized(窗体以最小化形式显示)和 Maximized(窗体以最大化形式显示). (3)StartPosition属性:用来获取或设置运

【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)

原文网址:http://www.jizhuomi.com/software/153.html 前两讲中鸡啄米为大家讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.鸡啄米再声明下,生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数等. 因为鸡啄米给大家的例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDITION_DIALOG,并自动生成了对话框类CAdditionDlg,它是从CDialogEx类派生的.大家用过VC++6.0