在WinForm項目開發中習慣於對於集合數據的批量修改,再一次性提交更新同步到數據庫。這里我們就必須實現對對象的改變的跟蹤記錄,我們實現對象的改變跟蹤有許多方式,大致我嘗試了兩種方式:1:對象強制實現接口,State守信和MakeMark行為。2:利用字典序繼續改變。雖然1的方式是否更加合理,但是在winform中與BindingSource集合使用簡化修增修改的書寫,配合的不是很好,供給開發人員使用不是很爽。於是我修改成為第二種方式集合記錄更改,在繼續在原集合真實修改,觸發BindingSource事件和與BindingSource很好的結合。
我們所要做的是對集合實體的變化做記錄,這個在微軟類庫中的System.Data.DataTable一樣,利用一套變化記錄機制,我們可以抽象出我們接口:
{
bool IsCanReject
{
get;
}
void AcceptChanged();
void RejectChanged();
event ObjectCollectionChanged objectCollectionChanged;
IEnumerable<KeyValuePair< object, ObjectObserveChangeState>> GetChangeds();
IEnumerable< object> GetChangeds(ObjectObserveChangeState changedState);
}
public enum ObjectObserveChangeState
{
None, Add, Modify, Delete
}
1:包含守信IsCanReject表示是否可以回滾(必須是可序列化的集合者可以回滾,內部利用序列化實現單級撤銷)。
2:AcceptChanged表示接受更改。
3:RejectChanged拒絕更改回滾。
4:GetChangeds獲取數據集合的更改或者某類型更改的集合。
數據更改通知事件:

{
public ObjectObserveChangeState ChangeState
{
get;
private set;
}
public object ItemValue
{
get;
private set;
}
public ObjectCollectionChangedEventArgs(ObjectObserveChangeState changeState, object itemValue)
{
this.ChangeState = changeState;
this.ItemValue = itemValue;
}
}
public delegate void ObjectCollectionChanged( object sender, ObjectCollectionChangedEventArgs e);
最后對於List集合的實現如下:

{
private IList collection;
private Dictionary< object, ObjectObserveChangeState> itemChangedCollection = new Dictionary< object, ObjectObserveChangeState>();
public event ObjectCollectionChanged objectCollectionChanged = null;
private byte[] _seriable;
public ObjectObserveCollection(IList list)
{
collection = list;
IsCanReject = list.GetType().IsSerializable;
if (IsCanReject)
{
try
{
_seriable = UtilsSerializer.BinarySerializer(list);
}
catch (Exception ex)
{
IsCanReject = false;
}
}
try
{
RegisterNotifyPropertyChanged(list.OfType<INotifyPropertyChanged>());
}
catch (Exception ex)
{
throw new Exception( " The collection model must implement the interface of INotifyPropertyChanged; ");
}
}
protected void RegisterNotifyPropertyChanged(IEnumerable<INotifyPropertyChanged> notifyCollection)
{
notifyCollection.ToList().ForEach(t =>
{
t.PropertyChanged += t_PropertyChanged;
});
}
protected void t_PropertyChanged( object sender, PropertyChangedEventArgs e)
{
if (!itemChangedCollection.ContainsKey(sender))
{
itemChangedCollection.Add(sender, ObjectObserveChangeState.Modify);
}
}
#region IList 成員
public int Add( object value)
{
var index = this.collection.Add(value);
this.OnObjectCollectionChanged( new ObjectCollectionChangedEventArgs(ObjectObserveChangeState.Add, value));
return index;
}
protected void OnObjectCollectionChanged(ObjectCollectionChangedEventArgs e)
{
RecoredChanged(e);
if ( this.objectCollectionChanged != null)
{
this.objectCollectionChanged( this, e);
}
}
protected void RecoredChanged(ObjectCollectionChangedEventArgs e)
{
switch (e.ChangeState)
{
case ObjectObserveChangeState.Add:
this.itemChangedCollection.Add(e.ItemValue, e.ChangeState);
RegisterNotifyPropertyChanged( new List<INotifyPropertyChanged>() { e.ItemValue as INotifyPropertyChanged });
break;
case ObjectObserveChangeState.Delete:
if (itemChangedCollection.ContainsKey(e.ItemValue))
{
switch (itemChangedCollection[e.ItemValue])
{
case ObjectObserveChangeState.Add:
itemChangedCollection.Remove(e.ItemValue);
break;
default:
itemChangedCollection[e.ItemValue] = ObjectObserveChangeState.Delete;
break;
}
}
else
{
itemChangedCollection.Add(e.ItemValue, ObjectObserveChangeState.Delete);
}
(e.ItemValue as INotifyPropertyChanged).PropertyChanged -= t_PropertyChanged;
break;
default:
if (itemChangedCollection.ContainsKey(e.ItemValue))
{
itemChangedCollection[e.ItemValue] = ObjectObserveChangeState.Modify;
}
else
{
itemChangedCollection.Add(e.ItemValue, ObjectObserveChangeState.Modify);
}
break;
}
}
public void Clear()
{
foreach ( var item in this.collection)
{
OnObjectCollectionChanged( new ObjectCollectionChangedEventArgs(ObjectObserveChangeState.Delete, item));
}
this.collection.Clear();
}
public bool Contains( object value)
{
return this.collection.Contains(value);
}
public int IndexOf( object value)
{
return this.collection.IndexOf(value);
}
public void Insert( int index, object value)
{
this.collection.Insert(index, value);
this.OnObjectCollectionChanged( new ObjectCollectionChangedEventArgs(ObjectObserveChangeState.Add, value));
}
public bool IsFixedSize
{
get { return this.collection.IsFixedSize; }
}
public bool IsReadOnly
{
get { return this.collection.IsReadOnly; }
}
public void Remove( object value)
{
this.collection.Remove(value);
this.OnObjectCollectionChanged( new ObjectCollectionChangedEventArgs(ObjectObserveChangeState.Delete, value));
}
public void RemoveAt( int index)
{
var value = this.collection[index];
this.collection.RemoveAt(index);
this.OnObjectCollectionChanged( new ObjectCollectionChangedEventArgs(ObjectObserveChangeState.Delete, value));
}
public object this[ int index]
{
get
{
return this.collection[index];
}
set
{
this.collection[index] = value;
}
}
#endregion
#region ICollection 成員
public void CopyTo(Array array, int index)
{
this.collection.CopyTo(array, index);
}
public int Count
{
get { return this.collection.Count; }
}
public bool IsSynchronized
{
get { return this.collection.IsSynchronized; }
}
public object SyncRoot
{
get { return this.collection.SyncRoot; }
}
#endregion
#region IEnumerable 成員
public IEnumerator GetEnumerator()
{
return this.collection.GetEnumerator();
}
#endregion
#region IDisposable 成員
public void Dispose()
{
this.itemChangedCollection.Clear();
this.itemChangedCollection = null;
}
#endregion
#region IObjectObserveable 成員
public void AcceptChanged()
{
this.itemChangedCollection.Clear();
if (IsCanReject)
{
_seriable = UtilsSerializer.BinarySerializer( this.collection);
}
}
public IEnumerable<KeyValuePair< object,ObjectObserveChangeState>> GetChangeds()
{
return this.itemChangedCollection.ToDictionary(t => t.Key, t => t.Value);
}
public IEnumerable< object> GetChangeds(ObjectObserveChangeState changedState)
{
return this.itemChangedCollection.Where(t => t.Value == changedState).Select(t => t.Key);
}
public void RejectChanged()
{
if (!IsCanReject)
{
throw new Exception( " This method required the collection type must be Serializable; ");
}
this.collection =(IList) UtilsSerializer.BinaryDeserialize( this._seriable);
}
public bool IsCanReject
{
get;
private set;
}
#endregion
}
在最后WinForm中測試:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Green.Utility;
using Green.Config.FrameWork;
namespace WindowsFormsApplication1
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
ObjectObserveCollection stus;
int count = 0;
private void Form3_Load( object sender, EventArgs e)
{
var list = new List<Student>();
list.Add(GeneratorStu());
stus = new ObjectObserveCollection(list);
bs = new BindingSource() { DataSource = stus };
dataGridView1.DataSource = bs;
}
BindingSource bs = null;
public Student GeneratorStu()
{
return new Student() { ID = ++count, Name = count.ToString() };
}
private void button4_Click( object sender, EventArgs e)
{
stus.AcceptChanged();
}
private void button1_Click( object sender, EventArgs e)
{
var model=bs.AddNew() as Student;
model.ID = ++count;
model.Name = count.ToString();
}
private void button2_Click( object sender, EventArgs e)
{
if (bs.Position != - 1)
{
bs.RemoveCurrent();
}
}
private void button3_Click( object sender, EventArgs e)
{
var add = stus.GetChangeds(ObjectObserveChangeState.Add).ToList();
var delete = stus.GetChangeds(ObjectObserveChangeState.Delete).ToList();
var update = stus.GetChangeds(ObjectObserveChangeState.Modify).ToList();
}
}
[Serializable]
public class Student : INotifyPropertyChanged
{
private int _ID;
public int ID
{
get { return _ID; }
set
{
if (_ID != value)
{
_ID = value;
OnPropertyChanged( " ID ");
}
}
}
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
_Name = value;
OnPropertyChanged( " Name ");
}
}
}
private void OnPropertyChanged( string p)
{
if ( this.PropertyChanged != null)
{
this.PropertyChanged( this, new PropertyChangedEventArgs(p));
}
}
#region INotifyPropertyChanged 成員
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
對於新增和刪除我們只需利用BindingSource的,bs.AddNew() 和bs.RemoveCurrent();感覺使用起來方便了吧。最后獲取數據更改利用GetChangeds。對於保存后AcceptChanges。
效果圖:
歡迎大家指正和建議,希望能夠共同進步,謝謝。