標籤:play ext opened 同步 sel 9.png alt 資料同步 his
情境: 一個主視窗中,可以在列表(DataGridView)裡選中一條記錄編輯,開啟一個編輯視窗(非模態視窗),編輯視窗儲存後需要重新整理父視窗,由於編輯視窗是非模態視窗,如果開啟了多個視窗,並且都是編輯同一條資料,那麼一個視窗儲存(並關閉)後,需要通知其它正在開啟的視窗“資料有更改,需要重新整理”
首先,重新整理父視窗,如果是開啟編輯視窗是模態視窗,那麼可以類似如下的實現(虛擬碼):
FormEdit frm = new FormEdit();frm.EditId = 選中資料行對應的id; if(frm.ShowDialog() == DialogResult.OK){ UpdateThisForm();}
非模態視窗是Form.Show(); 由於該方法是void修飾,因此不能像上面那樣去實現,此時可以在編輯視窗類別中公開一個事件,當父視窗new這個編輯視窗後,可以註冊這個事件,然後編輯視窗中如果儲存了可以調用該事件方法達到通知的效果。
下面是例子,主視窗有一個DataGridView控制項,資料繫結是Person的集合,Person實體類有Id,Name屬性,選中某一行並點擊編輯,可以開啟編輯介面; 編輯介面有一個文字框顯示編輯Person的Name,有一個儲存按鈕,點擊儲存之後將修改的Name更新到Person集合中(此處Person集合通過Xml序列化和還原序列化實現儲存於讀取)
主視窗核心代碼:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { if (dataGridView1.SelectedRows.Count == 1) { int personId = (int)dataGridView1.SelectedRows[0].Cells["Id"].Value; Form2 frm = new Form2(); frm.personId = personId; frm.UpdateParentEvent += Frm_UpdateParentEvent; frm.Show(); } } private void Frm_UpdateParentEvent() { LoadData(); } private void Form1_Load(object sender, EventArgs e) { LoadData(); } private void LoadData() { List<Person> personList = XmlSerializeHelper.DeserializeObject<List<Person>>("persons.xml"); dataGridView1.DataSource = personList; }
View Code
編輯視窗核心代碼:
public partial class Form2 : Form { public int personId; /// <summary> /// 重新整理父視窗的事件 /// </summary> public event Action UpdateParentEvent; private Person p = null; private List<Person> persons; public Form2() { InitializeComponent(); } private void Form2_Load(object sender, EventArgs e) { persons = XmlSerializeHelper.DeserializeObject<List<Person>>("persons.xml"); p = persons.Where(ps => ps.Id == personId).SingleOrDefault(); if (p != null) { txtName.Text = p.Name; } } private void btnSave_Click(object sender, EventArgs e) { if (p != null) { p.Name = txtName.Text; XmlSerializeHelper.SerializeObject(persons, "persons.xml"); UpdateParentEvent?.Invoke(); //擷取所有開啟的視窗 var openForms = Application.OpenForms; Type thisType = this.GetType(); this.Close(); foreach (var item in openForms) { Type itemType = item.GetType(); //如果都是當前視窗的類的執行個體,但不是當前執行個體(證明開啟了多個視窗) if (itemType == thisType && !object.ReferenceEquals(item,this)) { int itemPersonId = (int)itemType.GetField("personId").GetValue(item); //證明編輯的是同一條記錄,需要通知其它視窗重新整理頁面 if (itemPersonId == this.personId) { MethodInfo mInfo = itemType.GetMethod("ChangeHandle",BindingFlags.NonPublic | BindingFlags.Instance); mInfo?.Invoke(item,null); } } } } } private void ChangeHandle() { if (MessageBox.Show("其它視窗修改了本條資料,需要重新載入","提示",MessageBoxButtons.OK,MessageBoxIcon.Information) == DialogResult.OK) { //重新載入資料 Form2_Load(this, null); } } }
View Code
測試:
下面是開啟了兩個編輯視窗,並且都是編輯同一條資料,當編輯其中一個的Name,並儲存後,另一個提示需要重新整理
樣本中使用了Application.OpenForms;得到當前所有開啟的視窗,遍曆並通過反射擷取她們的“類型”(Type,下同),如果“類型”與當前視窗的“類型”相同,並且不是當前視窗,且又是編輯同一條資料時,反射擷取方法並調用,以達到通知的效果。
Winform 多個視窗編輯同一條資料同步的實現