1. 程式人生 > >Winform 多個窗口編輯同一條數據同步的實現

Winform 多個窗口編輯同一條數據同步的實現

load message mes save http 有一個 9.png 實例 使用

場景: 一個主窗口中,可以在列表(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 多個窗口編輯同一條數據同步的實現