http://www.cnblogs.com/clark159/archive/2011/10/10/2205153.html
前言 :
在文章「[.NET] : BindingSource使用模式 - Data Binding基础知识 (一)」。
介绍了如何将对象的属性包装成属性对象 「PropertyDescriptor」,并用它来做存取、监看变更等工作。
将数据对象的属性包装成属性对象是 Data Binding运作基础,在了解这个运作之后。
这边再来讨论,Data Binding时会用到的「数据源」。
在大部分的书里描述,Data Binding透过 ADO.NET里的对象与数据库做互动,用来显示及存取数据库内的数据。
在这架构下,ADO.NET里的物件是一种 Data Binding的数据源。
相关资料 : HOW TO:使用 Windows Form BindingSource 组件排序和筛选 ADO.NET 资料
也有一部份的数据提到的是, Data Binding也可以包装自定义数据对象,来做自定义数据对象的显示及存取。
在这架构下,自定义数据对象包装后也是一种 Data Binding的数据源。
相关资料 : 具有 ADO.NET 和自定义对象的数据系结应用程序
关于 Data Binding的数据源,细分下去有许多不同的实作与定义。
相关数据可以参考 : Windows Form 支援的数据源、 与数据系结相关的接口
本篇文章简略介绍,几个设计开发 Data Binding用来包装数据源用的相关对象。
让软件开发人员在设计 Data Binding相关程序代码时,能对对象运作模式有基础的理解。
BindingList :
在上列文章提供的相关数据里,能找到大量针对 Data Binding的数据源定义的接口。
照着数据文件可以实作出,符合自己需求的数据源对象,但这是一件工作量不小的工作。
在 System.ComponentModel命名空间里,可以找到 BindingList<T>这个物件。
BindingList<T>实作针对 Data Binding的数据源定义的主要接口。
并且 BindingList<T>是一个泛型类别,可以接受类别 T当作自定义数据对象。
开发人员可以使用 BindingList<T>,来将自定义数据对象包装成数据源。
首先建立自定义数据对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class County
{
// Properties
public int CountyID { get; set; }
public string CountyName { get; set; }
public string CountyDescription { get; set; }
// Constructor
public County()
{
this.CountyID = 0;
this.CountyName = string.Empty;
this.CountyDescription = string.Empty;
}
}
}
再来建立 DataGridView、BindingNavigator、BindingSource系结数据
最后建立数据源并系结数据
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BindingList<County> _bindingList = new BindingList<County>();
public Form1()
{
InitializeComponent();
// Add Item
County county1 = new County();
county1.CountyID = 1;
county1.CountyName = "台北市";
county1.CountyDescription = "买不起";
_bindingList.Add(county1);
County county2 = new County();
county2.CountyID = 2;
county2.CountyName = "新北市";
county2.CountyDescription = "还是买不起";
_bindingList.Add(county2);
// Data Binding
this.countyBindingSource.DataSource = _bindingList;
}
}
}
完成,看成果。
使用 BindingList<T>有一个地方需要特别注意的,就是关于 AddingNew事件。
AddingNew事件,主要用来通知要建立一个新的数据对象。
当有处理 AddingNew事件,BindingList<T>会加入 AddingNew事件里带回的 NewObject。
修改本文范例为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class County
{
// Properties
public int CountyID { get; set; }
public string CountyName { get; set; }
public string CountyDescription { get; set; }
// Constructor
public County()
{
this.CountyID = 0;
this.CountyName = string.Empty;
this.CountyDescription = string.Empty;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BindingList<County> _bindingList = new BindingList<County>();
public Form1()
{
InitializeComponent();
// Add Item
County county1 = new County();
county1.CountyID = 1;
county1.CountyName = "台北市";
county1.CountyDescription = "买不起";
_bindingList.Add(county1);
County county2 = new County();
county2.CountyID = 2;
county2.CountyName = "新北市";
county2.CountyDescription = "还是买不起";
_bindingList.Add(county2);
// EventHandler
_bindingList.AddingNew += new AddingNewEventHandler(_bindingList_AddingNew);
// Data Binding
this.countyBindingSource.DataSource = _bindingList;
}
void _bindingList_AddingNew(object sender, AddingNewEventArgs e)
{
County county3 = new County();
county3.CountyID = 3;
county3.CountyName = "桃园县";
county3.CountyDescription = "依然买不起";
e.NewObject = county3;
}
}
}
编译执行后,按下bindingNavigator上的『+』按钮看成果。
当没有处理 AddingNew事件并且数据对象有默认建构函式,BindingList<T>会加入数据对象默认建构函式建立新对象。
修改本文范例为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class County
{
// Properties
public int CountyID { get; set; }
public string CountyName { get; set; }
public string CountyDescription { get; set; }
// Constructor
public County()
{
this.CountyID = 4;
this.CountyName = "新竹市";
this.CountyDescription = "园区无敌贵";
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BindingList<County> _bindingList = new BindingList<County>();
public Form1()
{
InitializeComponent();
// Add Item
County county1 = new County();
county1.CountyID = 1;
county1.CountyName = "台北市";
county1.CountyDescription = "买不起";
_bindingList.Add(county1);
County county2 = new County();
county2.CountyID = 2;
county2.CountyName = "新北市";
county2.CountyDescription = "还是买不起";
_bindingList.Add(county2);
// Data Binding
this.countyBindingSource.DataSource = _bindingList;
}
}
}
编译执行后,按下bindingNavigator上的『+』按钮看成果。
当没有处理 AddingNew事件并且数据对象没有默认建构函式,BindingList<T>会将自己的 AllowNew属性设定为 false,不允许新增对象。
修改本文范例为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class County
{
// Properties
public int CountyID { get; set; }
public string CountyName { get; set; }
public string CountyDescription { get; set; }
// Constructor
public County(int countyID)
{
this.CountyID = countyID;
this.CountyName = string.Empty;
this.CountyDescription = string.Empty;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BindingList<County> _bindingList = new BindingList<County>();
public Form1()
{
InitializeComponent();
// Add Item
County county1 = new County(1);
county1.CountyName = "台北市";
county1.CountyDescription = "买不起";
_bindingList.Add(county1);
County county2 = new County(2);
county2.CountyName = "新北市";
county2.CountyDescription = "还是买不起";
_bindingList.Add(county2);
// Data Binding
this.countyBindingSource.DataSource = _bindingList;
}
}
}
编译执行后,会发现禁止按下bindingNavigator上的『+』按钮,不允许新增。
相关资料 : BindingList(Of T)、 BindingSource.AddingNew
ITypedList :
Data Binding在运作的时候,会依照数据源解析出数据对象,再将数据对象的属性包装成属性对象 PropertyDescriptor。
运作模式的相关数据可以参考 : [.NET] : BindingSource使用模式 - Data Binding基础知识 (一)。
当开发人员要在 Data Binding时使用自定义 PropertyDescriptor来做属性的存取显示时,实作 ITypedList接口就可以取代默认的运作流程。
首先建立自定义 PropertyDescriptor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace WindowsFormsApplication1
{
public class SamplePropertyDescriptor : PropertyDescriptor
{
// Properties
private readonly PropertyDescriptor _component = null;
// Constructor
public SamplePropertyDescriptor(PropertyDescriptor component)
: base(component)
{
#region Require
if (component == null) throw new ArgumentNullException("component");
#endregion
_component = component;
}
// Properties
public override Type ComponentType
{
get
{
return _component.ComponentType;
}
}
public override TypeConverter Converter
{
get
{
return _component.Converter;
}
}
public override bool IsLocalizable
{
get
{
return _component.IsLocalizable;
}
}
public override bool IsReadOnly
{
get
{
return _component.IsReadOnly;
}
}
public override Type PropertyType
{
get
{
return _component.PropertyType;
}
}
// Methods
public override object GetValue(object component)
{
return (component as County).CountyDescription + "$$$$$$$$";
}
public override void SetValue(object component, object value)
{
_component.SetValue(component, (value as string).Replace("$$$$$$$$", string.Empty));
}
public override void ResetValue(object component)
{
_component.ResetValue(component);
}
public override bool CanResetValue(object component)
{
return _component.CanResetValue(component);
}
public override bool ShouldSerializeValue(object component)
{
return _component.ShouldSerializeValue(component);
}
public override object GetEditor(Type editorBaseType)
{
return _component.GetEditor(editorBaseType);
}
public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
{
return _component.GetChildProperties(instance, filter);
}
public override void AddValueChanged(object component, EventHandler handler)
{
_component.AddValueChanged(component, handler);
}
public override void RemoveValueChanged(object component, EventHandler handler)
{
_component.RemoveValueChanged(component, handler);
}
}
}
再来建立继承 BindingList及实作 ITypedList的自定义BindingList
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace WindowsFormsApplication1
{
public class SampleBindingList : BindingList<County>, ITypedList
{
public string GetListName(PropertyDescriptor[] listAccessors)
{
return typeof(County).Name;
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
if (listAccessors != null && listAccessors.Length > 0)
{
throw new InvalidOperationException();
}
else
{
// Result
List<PropertyDescriptor> propertyDescriptorCollection = new List<PropertyDescriptor>();
// Create
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(typeof(County)))
{
if (propertyDescriptor.Name == "CountyDescription")
{
propertyDescriptorCollection.Add(new SamplePropertyDescriptor(propertyDescriptor));
}
else
{
propertyDescriptorCollection.Add(propertyDescriptor);
}
}
// Return
return new PropertyDescriptorCollection(propertyDescriptorCollection.ToArray());
}
}
}
}
最后修改本文范例为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class County
{
// Properties
public int CountyID { get; set; }
public string CountyName { get; set; }
public string CountyDescription { get; set; }
// Constructor
public County()
{
this.CountyID = 0;
this.CountyName = string.Empty;
this.CountyDescription = string.Empty;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
SampleBindingList _bindingList = new SampleBindingList();
public Form1()
{
InitializeComponent();
// Add Item
County county1 = new County();
county1.CountyID = 1;
county1.CountyName = "台北市";
county1.CountyDescription = "买不起";
_bindingList.Add(county1);
County county2 = new County();
county2.CountyID = 2;
county2.CountyName = "新北市";
county2.CountyDescription = "还是买不起";
_bindingList.Add(county2);
// Data Binding
this.countyBindingSource.DataSource = _bindingList;
}
}
}
完成,看成果。
相关资料 : ITypedList、 HOW TO:实作 ITypedList 界面
期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。