【转载】[Windows Forms] : BindingSource使用模式 - 加强版BindingList<T>
原文链接:http://www.cnblogs.com/clark159/archive/2011/10/10/2205156.html
前言 :
一般使用 BindingSource做 Data Binding的工作,不管是用 ADO.NET对象或是自定义数据对象当作数据源。
运作流程大多类似
1.读取数据并将数据填写进 DataSet(or BindingList)
2.将DataSet(or BindingList)系结至BindingSource
3.画面Control触发事件时,操作数据库(or 集合)变更数据,并且操作BindingSource显示数据。
这样的运作流程,因为靠画面Control触发的事件,来当作操作函式的进入点。
把这样的软件架构,会显得各层之间的职责略显模糊。
职责模糊范例程序 : 按此下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 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; using System.Data; using System.Data.SqlClient; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Fill BindingList<County> bindingList = new BindingList<County>(); foreach (County county in this .GetList()) { bindingList.Add(county); } // Binding countyBindingSource.DataSource = bindingList; } private void bindingNavigatorAddNewItem_Click( object sender, EventArgs e) { // Operate County item = countyBindingSource.Current as County; if (item != null ) { this .Add(item); MessageBox.Show( "Database Added" ); } } private const string _connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True;User Instance=True" ; public void Add(County item) { #region Require if (item == null ) throw new ArgumentNullException(); #endregion SqlCommand command; using (SqlConnection connection = new SqlConnection(_connectionString)) { // Connection connection.Open(); // Insert County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "INSERT INTO [CountyTable](CountyID, CountyName, CountyDescription) VALUES (@CountyID, @CountyName, @CountyDescription)" ; command.Parameters.AddWithValue( "@CountyID" , item.CountyID); command.Parameters.AddWithValue( "@CountyName" , item.CountyName); command.Parameters.AddWithValue( "@CountyDescription" , item.CountyDescription); command.ExecuteNonQuery(); } } } public IEnumerable<County> GetList() { SqlCommand command; using (SqlConnection connection = new SqlConnection(_connectionString)) { // Connection connection.Open(); // Result List<County> itemCollection = new List<County>(); // Select County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "SELECT * FROM [CountyTable]" ; using (SqlDataReader dataReader = command.ExecuteReader()) { while (dataReader.Read()) { County item = new County(); item.CountyID = Convert.ToInt32(dataReader[ "CountyID" ]); item.CountyName = Convert.ToString(dataReader[ "CountyName" ]); item.CountyDescription = Convert.ToString(dataReader[ "CountyDescription" ]); itemCollection.Add(item); } } } // Return return itemCollection; } } } } |
本篇文章介绍如何开发加强版BindingList<T>,用来将 Data Binding的运作流程作封装。
将原本各层之间模糊不清的职责,做一定程度的分派。
让开发人员在设计 Data Binding相关程序代码时,能将焦点集中在数据对象的操作工作上。
相关资料 :
[.NET] : BindingSource使用模式 - Data Binding基础知识 (一)
[.NET] : BindingSource使用模式 - Data Binding基础知识 (二)
实作 :
首先看看开发人员如何使用加强版BindingList<T>完成工作。
主要使用的接口及对象为
•StandardBindingList<T>类别,将Data Binding的运作流程封装在内,用来取代 .NET内建提供的 System.ComponentModel.BindingList<T>。
•IStandardBindingListStrategy<T>接口,开发人员实作 IStandardBindingListStrategy<T>并且注入后,就完成 Data Binding的数据源的开发工作。
加强版BindingList<T>范例程序 : 按此下载
先展示实际使用的程序代码及成果。
可以看到开发人员,只需要建立跟数据库沟通的对象,就可以完成画面到数据库一连串的开发工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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; using CLK.ComponentModel; namespace StandardBindingListSample { public partial class Form1 : Form { // Properties private const string _connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\CountyBindingListStrategyDatabase.mdf;Integrated Security=True;User Instance=True" ; // Constructor public Form1() { InitializeComponent(); this .countyBindingSource.DataSource = new StandardBindingList<County>( new SqlCountyBindingListStrategy(_connectionString)); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using CLK.ComponentModel; namespace StandardBindingListSample { public class SqlCountyBindingListStrategy : IStandardBindingListStrategy<County> { // Properties private readonly string _connectionString = string .Empty; // Constructor public SqlCountyBindingListStrategy( string connectionString) { #region Require if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentNullException(); #endregion _connectionString = connectionString; } // Methods private SqlConnection CreateConnection() { return new SqlConnection(_connectionString); } public void Add(County item) { #region Require if (item == null ) throw new ArgumentNullException(); #endregion SqlCommand command; using (SqlConnection connection = this .CreateConnection()) { // Connection connection.Open(); // Insert County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "INSERT INTO [CountyTable](CountyID, CountyName, CountyDescription) VALUES (@CountyID, @CountyName, @CountyDescription)" ; command.Parameters.AddWithValue( "@CountyID" , item.CountyID); command.Parameters.AddWithValue( "@CountyName" , item.CountyName); command.Parameters.AddWithValue( "@CountyDescription" , item.CountyDescription); command.ExecuteNonQuery(); } } } public void Modify(County item) { #region Require if (item == null ) throw new ArgumentNullException(); #endregion SqlCommand command; using (SqlConnection connection = this .CreateConnection()) { // Connection connection.Open(); // Update County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "UPDATE [CountyTable] SET CountyName=@CountyName, CountyDescription=@CountyDescription WHERE CountyID=@CountyID" ; command.Parameters.AddWithValue( "@CountyID" , item.CountyID); command.Parameters.AddWithValue( "@CountyName" , item.CountyName); command.Parameters.AddWithValue( "@CountyDescription" , item.CountyDescription); command.ExecuteNonQuery(); } } } public void Remove(County item) { #region Require if (item == null ) throw new ArgumentNullException(); #endregion SqlCommand command; using (SqlConnection connection = this .CreateConnection()) { // Connection connection.Open(); // Delete County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "DELETE FROM [CountyTable] WHERE CountyID=@CountyID" ; command.Parameters.AddWithValue( "@CountyID" , item.CountyID); command.ExecuteNonQuery(); } } } public IEnumerable<County> GetList() { SqlCommand command; using (SqlConnection connection = this .CreateConnection()) { // Connection connection.Open(); // Result List<County> itemCollection = new List<County>(); // Select County using (command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = "SELECT * FROM [CountyTable]" ; using (SqlDataReader dataReader = command.ExecuteReader()) { while (dataReader.Read()) { County item = new County(); item.CountyID = Convert.ToInt32(dataReader[ "CountyID" ]); item.CountyName = Convert.ToString(dataReader[ "CountyName" ]); item.CountyDescription = Convert.ToString(dataReader[ "CountyDescription" ]); itemCollection.Add(item); } } } // Return return itemCollection; } } } } |
再来展开StandardBindingList的软件架构图,并且建立架构图里的类别。
首先是 StandardBindingObject<T>类别。
-StandardBindingObject<T>封装实际要做 Data Binding的数据对象 T,让后续的程序代码能够取得数据对象 T。
-StandardBindingObject<T>提供多个属性,让 StandardBindingList<T>将发生过的 Data Binding流程做纪录。
-StandardBindingObject<T>也聆听,有实做INotifyPropertyChanged的数据对象 T,用来记录数据变更的流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | public class StandardBindingObject<T> where T : class , new () { // Properties private PropertyChangedEventHandler PropertyChangedDelegate { get ; set ; } public T NativeBindingObject { get ; private set ; } public bool IsEmptyTrack { get { if ( this .IsDirty == true ) return false ; if ( this .IsInsertItem == true ) return false ; if ( this .IsRemoveItem == true ) return false ; if ( this .IsSetItem == true ) return false ; if ( this .IsClearItems == true ) return false ; if ( this .IsCancelNew == true ) return false ; if ( this .IsEndNew == true ) return false ; return true ; } } public bool IsDirty { get ; set ; } public bool IsInsertItem { get ; set ; } public bool IsRemoveItem { get ; set ; } public bool IsSetItem { get ; set ; } public bool IsClearItems { get ; set ; } public bool IsCancelNew { get ; set ; } public bool IsEndNew { get ; set ; } // Constructor public StandardBindingObject() : this ( new T()) { } public StandardBindingObject(T nativeBindingObject) { #region Require if (nativeBindingObject == null ) throw new ArgumentNullException( "nativeBindingObject" ); #endregion // Properties this .PropertyChangedDelegate = delegate ( object sender, PropertyChangedEventArgs e) { this .IsDirty = true ; }; this .NativeBindingObject = nativeBindingObject; this .ResetTrack(); } // Methods public void ResetTrack() { this .IsDirty = false ; this .IsInsertItem = false ; this .IsRemoveItem = false ; this .IsSetItem = false ; this .IsClearItems = false ; this .IsCancelNew = false ; this .IsEndNew = false ; } public void HookPropertyChanged() { // INotifyPropertyChanged INotifyPropertyChanged notifyPropertyChanged = this .NativeBindingObject as INotifyPropertyChanged; if (notifyPropertyChanged != null ) notifyPropertyChanged.PropertyChanged += this .PropertyChangedDelegate; } public void UnhookPropertyChanged() { // INotifyPropertyChanged INotifyPropertyChanged notifyPropertyChanged = this .NativeBindingObject as INotifyPropertyChanged; if (notifyPropertyChanged != null ) notifyPropertyChanged.PropertyChanged -= this .PropertyChangedDelegate; } } |
再来是 StandardBindingPropertyDescriptor<T>类别。
-StandardBindingPropertyDescriptor<T>封装实际要做 Data Binding的数据对象 T的属性对象 PropertyDescriptor,让自己对外表现的就跟被封装的对象一样。
-StandardBindingPropertyDescriptor<T>内部存取数据对象的属性时,是读取 StandardBindingObject<T>封装的数据对象 T的属性。
-StandardBindingPropertyDescriptor<T>透过 PropertyDescriptor的机制,聆听没有实做INotifyPropertyChanged的数据对象 T的属性数据变更,并用StandardBindingObject<T>来记录变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | public sealed class StandardBindingPropertyDescriptor<T> : PropertyDescriptor where T : class , new () { // Properties private readonly PropertyDescriptor _nativeBindingPropertyDescriptor = null ; private readonly bool _raiseStandardBindingObjectSetDirty = false ; // Constructor public StandardBindingPropertyDescriptor(PropertyDescriptor nativeBindingPropertyDescriptor) : base (nativeBindingPropertyDescriptor) { #region Require if (nativeBindingPropertyDescriptor == null ) throw new ArgumentNullException( "component" ); #endregion _nativeBindingPropertyDescriptor = nativeBindingPropertyDescriptor; if ( typeof (INotifyPropertyChanged).IsAssignableFrom( typeof (T)) == false ) _raiseStandardBindingObjectSetDirty = true ; } // Properties public override Type ComponentType { get { return _nativeBindingPropertyDescriptor.ComponentType; } } public override TypeConverter Converter { get { return _nativeBindingPropertyDescriptor.Converter; } } public override bool IsLocalizable { get { return _nativeBindingPropertyDescriptor.IsLocalizable; } } public override bool IsReadOnly { get { return _nativeBindingPropertyDescriptor.IsReadOnly; } } public override Type PropertyType { get { return _nativeBindingPropertyDescriptor.PropertyType; } } // Methods private void GetBindingObject( object component, out StandardBindingObject<T> standardBindingObject, out T nativeBindingObject) { #region Require if (component == null ) throw new ArgumentNullException( "component" ); #endregion // StandardBindingObject standardBindingObject = component as StandardBindingObject<T>; if (standardBindingObject == null ) throw new ArgumentNullException( "standardBindingObject" ); // NativeBindingObject nativeBindingObject = standardBindingObject.NativeBindingObject; if (nativeBindingObject == null ) throw new ArgumentNullException( "nativeBindingObject" ); } private StandardBindingObject<T> GetStandardBindingObject( object component) { #region Require if (component == null ) throw new ArgumentNullException( "component" ); #endregion // GetBindingObject StandardBindingObject<T> standardBindingObject = null ; T nativeBindingObject = null ; this .GetBindingObject(component, out standardBindingObject, out nativeBindingObject); // Return return standardBindingObject; } private T GetNativeBindingObject( object component) { #region Require if (component == null ) throw new ArgumentNullException( "component" ); #endregion // GetBindingObject StandardBindingObject<T> standardBindingObject = null ; T nativeBindingObject = null ; this .GetBindingObject(component, out standardBindingObject, out nativeBindingObject); // Return return nativeBindingObject; } public override void SetValue( object component, object value) { // GetBindingObject StandardBindingObject<T> standardBindingObject = null ; T nativeBindingObject = null ; this .GetBindingObject(component, out standardBindingObject, out nativeBindingObject); // RaiseStandardBindingObjectSetDirty if (_raiseStandardBindingObjectSetDirty == false ) { // SetValue _nativeBindingPropertyDescriptor.SetValue(nativeBindingObject, value); } else { // SetDirty EventHandler setDirtyDelegate = delegate ( object sender, EventArgs e) { standardBindingObject.IsDirty = true ; }; // SetValue _nativeBindingPropertyDescriptor.AddValueChanged(nativeBindingObject, setDirtyDelegate); _nativeBindingPropertyDescriptor.SetValue(nativeBindingObject, value); _nativeBindingPropertyDescriptor.RemoveValueChanged(nativeBindingObject, setDirtyDelegate); } } public override object GetValue( object component) { return _nativeBindingPropertyDescriptor.GetValue( this .GetNativeBindingObject(component)); } public override void ResetValue( object component) { _nativeBindingPropertyDescriptor.ResetValue( this .GetNativeBindingObject(component)); } public override bool CanResetValue( object component) { return _nativeBindingPropertyDescriptor.CanResetValue( this .GetNativeBindingObject(component)); } public override bool ShouldSerializeValue( object component) { return _nativeBindingPropertyDescriptor.ShouldSerializeValue( this .GetNativeBindingObject(component)); } public override object GetEditor(Type editorBaseType) { return _nativeBindingPropertyDescriptor.GetEditor(editorBaseType); } public override PropertyDescriptorCollection GetChildProperties( object instance, Attribute[] filter) { return _nativeBindingPropertyDescriptor.GetChildProperties( this .GetNativeBindingObject(instance), filter); } public override void AddValueChanged( object component, EventHandler handler) { _nativeBindingPropertyDescriptor.AddValueChanged( this .GetNativeBindingObject(component), handler); } public override void RemoveValueChanged( object component, EventHandler handler) { _nativeBindingPropertyDescriptor.RemoveValueChanged( this .GetNativeBindingObject(component), handler); } } |
再来定义 IStandardBindingListStrategy<T>界面。
-IStandardBindingListStrategy<T>定义,要做 Data Binding的数据对象 T,进出系统边界应该要实作的功能。
1 2 3 4 5 6 7 8 9 10 11 | public interface IStandardBindingListStrategy<T> where T : class , new () { void Add(T item); void Modify(T item); void Remove(T item); IEnumerable<T> GetList(); } |
最后是StandardBindingList<T>类别。
-StandardBindingList<T>将Data Binding的运作流程封装在内,用来取代 .NET内建提供的 System.ComponentModel.BindingList<T>。
-StandardBindingList<T>透过继承 Override的方式来聆听发生过的 Data Binding流程,使用 StandardBindingObject<T>来记录变化。
-StandardBindingList<T>实作了ITypedList接口,取代原本 Data Binding流程里取得PropertyDescriptor的流程。将原本应该取得数据对象T的属性对象,改为取得StandardBindingPropertyDescriptor<T>。
-StandardBindingList<T>开放了Refresh()函式,执行这个函式StandardBindingList<T>就会透过IStandardBindingListStrategy<T>取得数据对象 T的数据做 Data Binding的动作。
-StandardBindingList<T>会在每个 Data Binding流程里,检查StandardBindingObject<T>发生过的纪录。当记录满足条件,就会呼叫IStandardBindingListStrategy<T>的函式处理数据对象 T。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | public class StandardBindingList<T> : BindingList<StandardBindingObject<T>>, ITypedList where T : class , new () { // Properties private readonly IStandardBindingListStrategy<T> _strategy = null ; private readonly PropertyDescriptorCollection _propertyDescriptorCollection = null ; private bool _isRefreshing = false ; // Constructor public StandardBindingList(IStandardBindingListStrategy<T> strategy) : this (strategy, true ) { } public StandardBindingList(IStandardBindingListStrategy<T> strategy, bool runRefresh) { #region Require if (strategy == null ) throw new ArgumentNullException(); #endregion // Properties _strategy = strategy; _propertyDescriptorCollection = this .CreateStandardBindingPropertyDescriptorCollection(); // Refresh if (runRefresh == true ) { this .Refresh(); } } // Methods private PropertyDescriptorCollection CreateStandardBindingPropertyDescriptorCollection() { // Result List<PropertyDescriptor> standardBindingPropertyDescriptorCollection = new List<PropertyDescriptor>(); // Create foreach (PropertyDescriptor nativePropertyDescriptor in TypeDescriptor.GetProperties( typeof (T))) { standardBindingPropertyDescriptorCollection.Add( new StandardBindingPropertyDescriptor<T>(nativePropertyDescriptor)); } // Return return new PropertyDescriptorCollection(standardBindingPropertyDescriptorCollection.ToArray()); } private void CommitTrack(StandardBindingObject<T> standardBindingObject) { #region Require if (standardBindingObject == null ) throw new ArgumentNullException( "standardBindingObject" ); #endregion if (_isRefreshing == false ) { if (standardBindingObject.IsEmptyTrack == false ) { if ( this .CommitTrack(standardBindingObject, _strategy) == true ) { standardBindingObject.ResetTrack(); } } } } protected virtual bool CommitTrack(StandardBindingObject<T> standardBindingObject, IStandardBindingListStrategy<T> strategy) { #region Require if (standardBindingObject == null ) throw new ArgumentNullException( "standardBindingObject" ); if (strategy == null ) throw new ArgumentNullException( "strategy" ); #endregion // Add if (standardBindingObject.IsInsertItem == true ) { if (standardBindingObject.IsRemoveItem == false ) { if (standardBindingObject.IsCancelNew == false ) { if (standardBindingObject.IsEndNew == true ) { strategy.Add(standardBindingObject.NativeBindingObject); return true ; } } } } // Remove if (standardBindingObject.IsInsertItem == false ) { if (standardBindingObject.IsCancelNew == false ) { if (standardBindingObject.IsRemoveItem == true ) { strategy.Remove(standardBindingObject.NativeBindingObject); return true ; } } } // Modify if (standardBindingObject.IsInsertItem == false ) { if (standardBindingObject.IsRemoveItem == false ) { if (standardBindingObject.IsCancelNew == false ) { if (standardBindingObject.IsEndNew == true ) { if (standardBindingObject.IsDirty == true ) { strategy.Modify(standardBindingObject.NativeBindingObject); return true ; } } } } } // Return return false ; } public void Refresh() { try { // BeginRefresh _isRefreshing = true ; // Clear this .Clear(); // Add foreach (T item in _strategy.GetList()) { StandardBindingObject<T> standardBindingObject = new StandardBindingObject<T>(item); this .Add(standardBindingObject); standardBindingObject.ResetTrack(); } } finally { // EndRefresh _isRefreshing = false ; } // ResetBindings this .ResetBindings(); } #region BindingList<T> protected override void OnListChanged(ListChangedEventArgs e) { #region Require if (e == null ) throw new ArgumentNullException( "e" ); #endregion if (_isRefreshing == false ) { base .OnListChanged(e); } } #endregion #region Collection<T> protected override void InsertItem( int index, StandardBindingObject<T> item) { #region Require if (item == null ) throw new ArgumentNullException( "item" ); #endregion // Base base .InsertItem(index, item); // NewItem item.HookPropertyChanged(); item.IsInsertItem = true ; this .CommitTrack(item); } protected override void SetItem( int index, StandardBindingObject<T> item) { #region Require if (item == null ) throw new ArgumentNullException( "item" ); #endregion // OldItem StandardBindingObject<T> oldItem = this [index]; oldItem.UnhookPropertyChanged(); // Base base .SetItem(index, item); // NewItem item.HookPropertyChanged(); item.IsSetItem = true ; this .CommitTrack(item); } protected override void RemoveItem( int index) { // OldItem StandardBindingObject<T> oldItem = this [index]; oldItem.UnhookPropertyChanged(); oldItem.IsRemoveItem = true ; this .CommitTrack(oldItem); // Base base .RemoveItem(index); } protected override void ClearItems() { // OldItem foreach (StandardBindingObject<T> oldItem in this .Items.ToArray()) { oldItem.UnhookPropertyChanged(); oldItem.IsClearItems = true ; this .CommitTrack(oldItem); } // Base base .ClearItems(); } #endregion #region ICancelAddNew public override void CancelNew( int itemIndex) { // StandardBindingObject if (0 <= itemIndex && itemIndex < this .Count) { StandardBindingObject<T> standardBindingObject = this [itemIndex]; standardBindingObject.IsCancelNew = true ; this .CommitTrack(standardBindingObject); } // Base base .CancelNew(itemIndex); } public override void EndNew( int itemIndex) { // StandardBindingObject if (0 <= itemIndex && itemIndex < this .Count) { StandardBindingObject<T> standardBindingObject = this [itemIndex]; standardBindingObject.IsEndNew = true ; this .CommitTrack(standardBindingObject); } // Base base .EndNew(itemIndex); } #endregion #region ITypedList public string GetListName(PropertyDescriptor[] listAccessors) { return typeof (StandardBindingObject<T>).Name; } public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) { if (listAccessors != null && listAccessors.Length > 0) { throw new InvalidOperationException(); // return this.CreateStandardBindingPropertyDescriptorCollection(ListBindingHelper.GetListItemProperties(listAccessors[0].PropertyType)); } else { return _propertyDescriptorCollection; } } #endregion } |
后记 :
StandardBindingList还有很多地方需要加工,例如 : 加入数据验证、或是将 CommitTrack扩充更完整。
这些功能将会在后续的文章内一一实作,不过都还是以本章节的思路来做扩充。
期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律