主表單有一DataGridView顯示會員資料列表,使用者點選某筆會員資料,系統會跳出一個子表單提供修改會員資料功能。更新會員資料後,主表單DataGridView裡的會員資料也隨之更新,以反應最新會員資料。
依上所述,可能的實作方式可以在主表單加入一個取得最新會員資料的方法,如LoadLatestUsers。在子表單中更新會員資料後,呼叫主表單的LoadLatestUsers以更新主表單的顯示資料。
主表單
private void DataGridView_Users_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { if (e.RowIndex == -1) { return; } DataGridViewRow currentRow = this.DataGridView_Users.CurrentRow; User user = currentRow.DataBoundItem as User; if (user == null) { return; } ChildForm form = new ChildForm(user); form.Owner = this; form.ShowDialog(); } public void LoadLatestUsers() { this.DataGridView_Users.DataSource = Repository.GetUsers(); }子表單
public ChildForm(User user) : this() { this._user = user; } private void ChildForm_Load(object sender, EventArgs e) { this.TextBox_FirstName.Text = this._user.FirstName; this.TextBox_LastName.Text = this._user.LastName; this.TextBox_PhoneNumber.Text = this._user.PhoneNumber; } private void Button_Update_Click(object sender, EventArgs e) { this._user.FirstName = this.TextBox_FirstName.Text; this._user.LastName = this.TextBox_LastName.Text; this._user.PhoneNumber = this.TextBox_PhoneNumber.Text; Repository.Update(this._user); MainForm mainForm = this.Owner as MainForm; mainForm.LoadLatestUsers(); this.Close(); }此一方法主要是在主表單建立一個公開方法LoadLatestUsers,在開啟子表單時,將子表單的Owner設為主表單。如此在子表單更新完資料後,取得Owner轉為主表單型別並呼叫LoadLatestUsers。以此方式實作,主要的缺點就是子表單與主表單耦合度太高,子表單需要明確知道它的Owner是誰。如果它的Owner需要有兩個表單以上該如何處理?
各位也可以發現,上述的需求就如同一般所說的Publisher-Subscriber或Observer Pattern。在.NET Framework 4.0開始,內建了兩個介面IObserver<T>及IObservable<T>可供開發人員實作Observer Pattern以達到前述的需求。
子表單
public partial class ChildForm : Form, IObservable<User> { private User _user; IObserver<User> _observer; // 省略 private void Button_Update_Click(object sender, EventArgs e) { this._user.FirstName = this.TextBox_FirstName.Text; this._user.LastName = this.TextBox_LastName.Text; this._user.PhoneNumber = this.TextBox_PhoneNumber.Text; Repository.Update(this._user); if (this._observer != null) { this._observer.OnNext(this._user); } this.Close(); } #region IObservable<User> Members public IDisposable Subscribe(IObserver<User> observer) { this._observer = observer; return null; } #endregion }子表單實作了IObservable<User>介面,上面的範例是假設Subscriber只有一個,如果有多個Subscriber可以自行修改,例如將_observer變數改為Dictionary或List型別。在會員資料更新後,呼叫IObserver<T>介面的OnNext方法以通知Subscriber(s)有更新。
主表單
public partial class MainForm : Form, IObserver<User> { // 省略 private void DataGridView_Users_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { // 省略 ChildForm form = new ChildForm(user); form.Subscribe(this); form.ShowDialog(); } private void LoadLatestUsers() { this.DataGridView_Users.DataSource = Repository.GetUsers(); } #region IObserver<User> Members public void OnCompleted() { throw new NotImplementedException(); } public void OnError(Exception error) { throw new NotImplementedException(); } public void OnNext(User value) { this.LoadLatestUsers(); } #endregion }主表單實作了IObserver<User>介面,並在開啟子表單時,呼叫其Subscribe方法訂閱更新。當子表單更新資料後便會呼叫OnNext方法重新載入最新的會員資料。各位可以看到原本的LoadLatestUser方法已變更為私有方法。OnNext方法傳入的是單一會員資料,如果不想重新載入所有的會員資料,也可以直接更新DataGridView上該筆會員資料以免載入不必要的資料。
以.NET Framework提供的內建介面來實作Observer Pattern,不僅讓子表單與主表單的耦合度降低,若有多個Subscriber,以此方式實作也相當簡單,而子表單也不需要知道它的Subscriber有誰,只管發送更新通知即可,Subscriber自然會作相對應的處理,只要它們都有實作IObserver<User>介面。
完整範例程式碼可至https://github.com/petekcchen/blog/tree/master/DataGridViewObserver下載。
No comments:
Post a Comment