今天收到“寒枫天伤 - PSP”的问题(老大,名字能不能简单点,好难打也),询问载体设计的问题,乱谈一下吧,不好你当胡扯蛋了。

载体的设计有俩个思路,一个是表格式的,一个是层次的。

ms的ADO、DataSet就是表格式的,采用行、列组成的表,然后表集合之间建立联系。他更贴近关系型数据库的结构,因此使用简单、可以充分利用已经成熟的大量研究成果。缺点就是他是抽象的,不直观。

通常的xml和O/R的设计就是层次的,局部来说也是行(集合)、列(属性)组成表(对象),区别是表(对象)之间不是平等的关系,而是建立了有点像树一样的结构。好处吗,编写代码的时候看着舒服些罗(不是我打击你),缺点吗,一沓子了,我最头大的是数据跟踪问题。

我无法在一片文章中说明所有的事情,例如序列化、继承原则、CRUD、数据跟踪一大堆要处理的事情。

先说说 IBindList和ICancelAddNew接口吧,IBindList是列表绑定的基础接口,他继承于IList接口,如果你想绑定到某个表格或者列表中,IList基本上够了(实际上数组和ICollection也可以),但IBindList提供是否能新增、编辑和删除的选项,还提供排序、查找等功能(我可没有实现这个复杂的功能,我使用表格本身的功能),最重要的是他提供了ListChanged事件,这个是你通知外界你的集合发生改变的最好途径,所以你的集合最好是实现IBindList,而不紧紧是IList。

ICancelAddNew接口用在表格的编辑中,你使用表格的时候都知道你新建一行的时候可以按ESC键取消新建,实际内部的工作原理是:已经新建了行并添加到行集合,当你按ESC时,删除掉刚才的一行,所以你必须记住刚才新建的行是第多少行。

(如果没有记错的话,.net 1.1是没有这个接口的 ,.net 2.0才有)

下面的代码是部分的集合代码(不能运行的),不要以为我能写多好的程序,其实我是抄System.ComponentModel.Collections.Generic.BindingList<T>的。


Using directives#region Using directives
using System;
using System.Collections;
using System.ComponentModel;
using Mango.Common.Data;
using Mango.Common.Properties;
using System.Reflection;
#endregion

namespace Mango.Common.Data
{
    /**//// <summary> 行集合对象的基础类 </summary>
    public class DataRowCollectionBase : CollectionBase, IBindingList, IList, ICollection, IEnumerable, ICancelAddNew
    {
        // Fields
        private int addNewPos;
        private bool hookingItems;
        private PropertyChangedEventHandler onItemPropertyChanged;
        private bool allowNew;
        private bool allowEdit;
        private bool allowRemove;

        private Type _itemType;
        private object _parent;

        // Events
        public event AddingNewEventHandler AddingNew;
        public event ListChangedEventHandler ListChanged;

        类的初始化方法#region 类的初始化方法
        /**//// <summary> 创建无父对象的集合 </summary>
        public DataRowCollectionBase()
        {
            this.addNewPos = -1;
            this.allowNew = true;
            this.allowEdit = true;
            this.allowRemove = true;
        }

        /**//// <summary> 创建集合,并为集合设置父对象 </summary>
        public DataRowCollectionBase(object parent) :this()
        {
            _parent = parent;
        }
        #endregion

        AddNew相关方法#region AddNew相关方法
        /**//// <summary>
        /// 获取集合类的名细类型
        /// </summary>
        protected virtual Type GetCollectionItemType()
        {
            if (_itemType == null)
            {
                Type collType = this.GetType();
                object[] ps = collType.GetCustomAttributes(typeof(DbCollectionAttribute), true);
                if (ps == null || ps.Length == 0)
                    throw new ApplicationException(string.Format(Resources.Error_NotSetDbCollAtt, collType.Name));
                _itemType = ((DbCollectionAttribute)ps[0]).TypeContainedInCollection;
            }

            return _itemType;
        }

        /**//// <summary> 引发 AddingNew 事件 </summary>
        protected virtual void OnAddingNew(AddingNewEventArgs e)
        {
            if (this.AddingNew != null)
            {
                this.AddingNew(this, e);
            }
        }

        /**//// <summary> 返回新的对象 </summary>
        private object FireAddingNew()
        {
            AddingNewEventArgs addNewArgs = new AddingNewEventArgs(null);
            this.OnAddingNew(addNewArgs);
            return addNewArgs.NewObject;
        }

        /**//// <summary> 在向 DataRowCollectionBase 实例中插入新元素之前执行其他自定义进程。 </summary>
        protected override void OnInsert(int index, object value)
        {
            //检查新对象的父对象
            DataRowBase row = value as DataRowBase;
            if (row != null)
            {
                if (row.Parent != null)
                    throw new ArgumentException(Resources.Error_ColHaveParent);
            }

            this.EndNew(this.addNewPos);
            this.HookItem(value, true);

            base.OnInsert(index, value);
        }

        /**//// <summary> 在向 DataRowCollectionBase 实例中插入新元素之后执行其他自定义进程。 </summary>
        protected override void OnInsertComplete(int index, object value)
        {
            //设置新对象的父对象
            DataRowBase row = value as DataRowBase;
            if (row != null)
                row.SetParent(_parent);

            base.OnInsertComplete(index, value);
            this.FireListChanged(ListChangedType.ItemAdded, index);
        }

        /**//// <summary> 将新项添加到列表。</summary>
        object IBindingList.AddNew()
        {
            object newObject = this.AddNewCore();
            this.addNewPos = (newObject != null) ? base.List.IndexOf(newObject) : -1;
            return newObject;
        }

        /**//// <summary> 将新项添加到列表。 </summary>
        protected virtual object AddNewCore()
        {
            object newObject = this.FireAddingNew();
            if (newObject == null)
            {
                newObject = Activator.CreateInstance(GetCollectionItemType());
                //自动填充关键字
                IDataRow dataRow = newObject as IDataRow;
                if (dataRow != null)
                {
                    DataRowType t = dataRow.GetDataRowType();
                    PropertyInfo pi = t.GetPrimaryKeyProperty();
                    pi.SetValue(dataRow, Guid.NewGuid().ToString("N"), null);
                }
            }
            base.List.Add(newObject);
            return newObject;
        }
        #endregion

        ListChanged事件的支持#region ListChanged事件的支持
        /**//// <summary> 引发 ListChanged 事件 </summary>
        protected virtual void OnListChanged(ListChangedEventArgs e)
        {
            if (this.ListChanged != null)
            {
                this.ListChanged(this, e);
            }
        }

        //内部引发ListChanged事件
        private void FireListChanged(ListChangedType listChangedType, int index)
        {
            this.OnListChanged(new ListChangedEventArgs(listChangedType, index));
        }

        //内部引发ListChanged事件
        private void FireListChanged(ListChangedType listChangedType, int index,string propertyName)
        {
            PropertyDescriptor propDesc = TypeDescriptor.CreateProperty(GetCollectionItemType(), propertyName,typeof(string), null);
            this.OnListChanged(new ListChangedEventArgs(listChangedType, index,propDesc));
        }

        /**//// <summary> 返回/设置是否引发ListChanged中ItemChanged项目 </summary>
        public bool RaiseItemChangedEvents
        {
            get
            {
                return this.hookingItems;
            }
            set
            {
                if (this.hookingItems != value)
                {
                    this.HookItems(false);
                    this.hookingItems = value;
                    this.HookItems(true);
                }
            }
        }

        /**//// <summary> 引发重新更新事件 </summary>
        public void ResetBindings()
        {
            this.FireListChanged(ListChangedType.Reset, -1);
        }

        /**//// <summary> 引发某个元素的改动事件 </summary>
        public void ResetItem(int position)
        {
            this.FireListChanged(ListChangedType.ItemChanged, position);
        }

        //拦截/取消元素
        private void HookItem(object item, bool hook)
        {
            if (!this.hookingItems)
            {
                return;
            }
            if (this.onItemPropertyChanged == null)
            {
                this.onItemPropertyChanged = new PropertyChangedEventHandler(this.OnItemPropertyChanged);
            }

            IPropertyChange tmp = item as IPropertyChange;
            if (tmp != null)
            {
                if (hook)
                    tmp.PropertyChanged += this.onItemPropertyChanged;
                else
                    tmp.PropertyChanged -= this.onItemPropertyChanged;
            }
        }

        //拦截/取消指定索引的元素
        private void HookItemAt(int index, bool hook)
        {
            if ((this.hookingItems && (index >= 0)) && (index < base.Count))
            {
                this.HookItem(base.List[index], hook);
            }
        }

        //拦截/取消所有元素
        private void HookItems(bool hook)
        {
            if (!this.hookingItems)
                return;

            IEnumerator e = base.GetEnumerator();
            while (e.MoveNext())
            {
                object tmp = e.Current;
                this.HookItem(tmp, hook);
            }
        }

        //在元素发生改变时调用
        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.FireListChanged(ListChangedType.ItemChanged, base.List.IndexOf(sender), e.PropertyName);
        }

        #endregion

        Clear相关方法#region Clear相关方法
        /**//// <summary> 在清除 DataRowCollectionBase 中所有实例之前执行其他自定义进程。</summary>
        protected override void OnClear()
        {
            this.EndNew(this.addNewPos);
            this.HookItems(false);

            //删除父对象关联,注意:这里不能会滚操作
            DataRowBase row;
            foreach (object item in InnerList)
            {
                row = item as DataRowBase;
                if (row != null)
                    row.SetParent(null);
            }

            base.OnClear();
        }

        /**//// <summary> 在清除 DataRowCollectionBase 中所有实例之后执行其他自定义进程。 </summary>
        protected override void OnClearComplete()
        {
            base.OnClearComplete();
            this.FireListChanged(ListChangedType.Reset, -1);
        }
        #endregion

        Remove相关方法#region Remove相关方法
        /**//// <summary> 在向 DataRowCollectionBase 实例中移出元素之前执行其他自定义进程。 </summary>
        protected override void OnRemove(int index, object value)
        {
            this.EndNew(this.addNewPos);
            this.HookItemAt(index, false);
            base.OnRemove(index, value);
        }

        /**//// <summary> 在向 DataRowCollectionBase 实例中移出元素之后执行其他自定义进程。 </summary>
        protected override void OnRemoveComplete(int index, object value)
        {
            //删除父对象关联
            DataRowBase row = value as DataRowBase;
            if (row != null)
                row.SetParent(null);

            base.OnRemoveComplete(index, value);
            this.FireListChanged(ListChangedType.ItemDeleted, index);
        }

        #endregion

        Set相关方法#region Set相关方法
        /**//// <summary> 当在 DataRowCollectionBase 实例中设置值后执行其他自定义进程。</summary>
        protected override void OnSetComplete(int index, object oldValue, object newValue)
        {
            //删除旧对象的父对象
            DataRowBase oldRow = oldValue as DataRowBase;
            if (oldRow != null)
                oldRow.SetParent(null);

            //设置新对象的父对象
            DataRowBase newRow = newValue as DataRowBase;
            if (newRow != null)
                newRow.SetParent(_parent);

            base.OnSetComplete(index, oldValue, newValue);
            this.FireListChanged(ListChangedType.ItemChanged, index);
        }
        #endregion

        ICancelAddNew支持#region ICancelAddNew支持
        /**//// <summary> 取消新建的行 </summary>
        public void CancelNew(int itemIndex)
        {
            if ((this.addNewPos >= 0) && (this.addNewPos == itemIndex))
            {
                this.RemoveAt(this.addNewPos);
                this.addNewPos = -1;
            }
        }

        /**//// <summary> 结束新建行的编辑 </summary>
        public void EndNew(int itemIndex)
        {
            if ((this.addNewPos >= 0) && (this.addNewPos == itemIndex))
            {
                this.addNewPos = -1;
            }
        }

        #endregion

        集合是否可以改动的支持#region 集合是否可以改动的支持
        /**//// <summary> 获取/设置是否可以使用 AddNew 向列表中添加项。 </summary>
        public bool AllowNew
        {
            get
            {
                return ((IBindingList)this).AllowNew;
            }
            set
            {
                this.allowNew = value;
            }
        }

        /**//// <summary> 获取是否可以使用 AddNew 向列表中添加项。 </summary>
        bool IBindingList.AllowNew
        {
            get
            {
                return this.AllowNewCore;
            }
        }

        /**//// <summary> 获取是否可以使用 AddNew 向列表中添加项。 </summary>
        protected virtual bool AllowNewCore
        {
            get
            {
                return this.allowNew;
            }
        }

        /**//// <summary> 获取/设置是否可更新列表中的项。 </summary>
        public bool AllowEdit
        {
            get
            {
                return ((IBindingList)this).AllowEdit;
            }
            set
            {
                this.allowEdit = value;
            }
        }

        /**//// <summary> 获取是否可更新列表中的项。</summary>
        bool IBindingList.AllowEdit
        {
            get
            {
                return this.AllowEditCore;
            }
        }

        /**//// <summary> 获取是否可更新列表中的项。 </summary>
        protected virtual bool AllowEditCore
        {
            get
            {
                return this.allowEdit;
            }
        }

        /**//// <summary> 获取/设置是否可以使用 Remove 或 RemoveAt 从列表中移除项。 </summary>
        public bool AllowRemove
        {
            get
            {
                return ((IBindingList)this).AllowRemove;
            }
            set
            {
                this.allowRemove = value;
            }
        }

        /**//// <summary> 获取是否可以使用 Remove 或 RemoveAt 从列表中移除项。 </summary>
        bool IBindingList.AllowRemove
        {
            get
            {
                return this.AllowRemoveCore;
            }
        }

        /**//// <summary> 获取是否可以使用 Remove 或 RemoveAt 从列表中移除项。 </summary>
        protected virtual bool AllowRemoveCore
        {
            get
            {
                return this.allowRemove;
            }
        }
        #endregion

        排序和查询功能的支持#region 排序和查询功能的支持
        /**//// <summary> 获取当列表更改或列表中的项更改时是否引发 ListChanged 事件。 </summary>
        public bool SupportsChangeNotification
        {
            get
            {
                return this.SupportsChangeNotificationCore;
            }
        }

        /**//// <summary> 获取当列表更改或列表中的项更改时是否引发 ListChanged 事件。 </summary>
        protected virtual bool SupportsChangeNotificationCore
        {
            get
            {
                return true;
            }
        }

        /**//// <summary> 获取列表是否支持使用 Find 方法进行搜索。 </summary>
        public bool SupportsSearching
        {
            get
            {
                return this.SupportsSearchingCore;
            }
        }

        /**//// <summary> 获取列表是否支持使用 Find 方法进行搜索。 </summary>
        protected virtual bool SupportsSearchingCore
        {
            get
            {
                return false;
            }
        }

        /**//// <summary> 获取列表是否支持排序 </summary>
        public bool SupportsSorting
        {
            get
            {
                return this.SupportsSortingCore;
            }
        }

        /**//// <summary> 获取列表是否支持排序 </summary>
        protected virtual bool SupportsSortingCore
        {
            get
            {
                return false;
            }
        }

        /**//// <summary> 获取是否对列表中的项进行排序。</summary>
        public bool IsSorted
        {
            get
            {
                return this.IsSortedCore;
            }
        }

        /**//// <summary> 获取是否对列表中的项进行排序。 </summary>
        protected virtual bool IsSortedCore
        {
            get
            {
                return false;
            }
        }

        /**//// <summary> 获取正在用于排序的 PropertyDescriptor。 </summary>
        public PropertyDescriptor SortProperty
        {
            get
            {
                return this.SortPropertyCore;
            }
        }

        /**//// <summary> 获取正在用于排序的 PropertyDescriptor。 </summary>
        protected virtual PropertyDescriptor SortPropertyCore
        {
            get
            {
                return null;
            }
        }

        /**//// <summary> 获取排序的方向。 </summary>
        public ListSortDirection SortDirection
        {
            get
            {
                return this.SortDirectionCore;
            }
        }

        /**//// <summary> 获取排序的方向。</summary>
        protected virtual ListSortDirection SortDirectionCore
        {
            get
            {
                return ListSortDirection.Ascending;
            }
        }

        /**//// <summary> 根据 PropertyDescriptor 和 ListSortDirection 对列表进行排序。 </summary>
        public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
        {
            this.ApplySortCore(property, direction);
        }

        /**//// <summary> 根据 PropertyDescriptor 和 ListSortDirection 对列表进行排序。 </summary>
        protected virtual void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
        {
            throw new NotSupportedException();
        }

        /**//// <summary> 使用 ApplySort 移除任何已应用的排序。 </summary>
        public void RemoveSort()
        {
            this.RemoveSortCore();
        }

        /**//// <summary> 使用 ApplySort 移除任何已应用的排序。</summary>
        protected virtual void RemoveSortCore()
        {
            throw new NotSupportedException();
        }

        /**//// <summary> 返回具有给定 PropertyDescriptor 的行的索引。 </summary>
        public int Find(PropertyDescriptor property, object key)
        {
            return this.FindCore(property, key);
        }

        /**//// <summary> 返回具有给定 PropertyDescriptor 的行的索引。 </summary>
        protected virtual int FindCore(PropertyDescriptor property, object key)
        {
            throw new NotSupportedException();
        }

        /**//// <summary> 将 PropertyDescriptor 添加到用于搜索的索引 </summary>
        void IBindingList.AddIndex(PropertyDescriptor property)
        {
            //
        }

        /**//// <summary> 从用于搜索的索引中移除 PropertyDescriptor。 </summary>
        void IBindingList.RemoveIndex(PropertyDescriptor property)
        {
            //
        }
        #endregion
    }
}

回复 寒枫天伤 - PSP 的问题相关推荐

  1. 关于PagedDataSource

    原文地址:关于PagedDataSource 作者:秋天の风 关于PagedDataSource,非常好用的一个分页属性!  Asp.net提供了三个功能强大的列表控件:DataGrid.DataLi ...

  2. 基类与接口混合继承的声明问题 [C#, Design] -Allen Lee's Magic

    Updated on Friday, November 19, 2004 Written by Allen Lee 1. 问题初现 今天,查看<接口继承的声明问题>一文的反馈,发现Ninp ...

  3. 遍历ArrayList易犯错误

    场景: 将ArrayList中符合条件的记录删掉,第一时间写出的程序如下: foreach (string aStr in  aList)             {                  ...

  4. windows网络服务之配置网络负载均衡(NLB)群集

    O首页51CTO博客我的博客搜索 每日博报 社区:学院论坛博客下载更多            登录注册 家园 学院 博客 论坛 下载 自测 门诊 周刊 读书 技术圈 曾垂鑫的技术专栏 http://5 ...

  5. 体育门户里杀出的程咬金:虎扑凭什么?

    概述:与新浪在体育报道领域扮演的"传统媒体"角色相比,虎扑也许算是体育报道界的"先知".早在十年前,虎扑就在发展论坛和大大小小的线下活动,尝试挖掘新媒体特性来获 ...

  6. 写在马哥教育第八期开始之前

    "你不能剥夺别人思考的权力"!记得读研期间一位导师在谈到"传道.授业.解惑"时特地强调.当时身为学生,并未能完全.真切地理解这位导师表述的真正意图.而当自己独立 ...

  7. 灵动微电子逐飞 智能车支持计划汇总

    ▌灵动技术培训   直播简介:MM32 MCU系列产品简介和MM32SPIN27PF. MM32F3277G9P产品的详细介绍,MM32 MCU开发工具与智能车大赛的入门指导,包括MM32 MCU资料 ...

  8. 安装oracle 11gR2单实例+ASM

    安装oracle11gR2单实例+ASM,让新手走向数据库管理员 一.介绍 因业务需要,最近在主系统的基础上搭建一套mini系统,本文只讲ORACLE数据库+ASM磁盘管理工具的安装: 1.服务器系统 ...

  9. 弱鸡儿长乐爆肝旅Day8

    T1远征(expedition) [题目描述] 寒枫将军将要带领他的部队去圣雪山消灭那里的冰龙. 部队分成了若干个小队,属于同一个小队的人兵种相同.寒枫将军有着杰出的指挥能力,在战斗的时候,寒枫将军能 ...

最新文章

  1. MySql 查询表字段数
  2. (转)详解css3弹性盒模型(Flexbox)
  3. 最喜欢随机森林?周志华团队DF21后,TensorFlow开源决策森林库TF-DF
  4. linq TO XML 基础
  5. Linux系统调用的运行过程【转】
  6. poj 1845 Sumdiv (算数基本定理+逆元)
  7. Python 把较长的一行代码分成多行的技巧
  8. BOM--window对象
  9. Sql UNION 合并多个结果集并排序
  10. android 扫雷小游戏
  11. linux阅读文件格式,Linux下安装boox viewer阅读pdg格式文件
  12. python用实现FGO自动挂机战斗思路
  13. *新手看php手册的正确姿势
  14. 大数据影响下的专题地图编制
  15. Shell 千分 逗号隔开
  16. cad能整体比例缩小吗_cad怎么把原尺寸图缩小几倍
  17. 为什么程序员应该写博客?用什么博客系统?在哪写?
  18. 遇见Laravel Migrations的migrate与rollback
  19. 京东云加速扩展“朋友圈” 火力全开大展生态“云”图
  20. 生命的法则——植渝轩语录

热门文章

  1. verdi bin工具
  2. 网络安全法今日实施 互联网企业对隐私政策重视不足
  3. iOS开发之UIWindow
  4. Oracle11gExp导出空表方法
  5. 不装.net Framework 也能运行WinForm程序,用飞信(转)
  6. XML表示的数据库数据
  7. css3学习 之 css选择器(结构性伪类选择器)
  8. 使用VS搭建三层结构
  9. Xcode clang-omp openmp开发
  10. 十进制数和二进制数之间的转换