• Winform 多个窗口编辑同一条数据同步的实现


    场景: 一个主窗口中,可以在列表(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,下同),如果“类型”与当前窗口的“类型”相同,并且不是当前窗口,且又是编辑同一条数据时,反射获取方法并调用,以达到通知的效果。

     

  • 相关阅读:
    街边的泥人张
    没事试试50mm1.4
    WWOOF介绍一下,但貌似我们利用不了
    护照和签证
    071205还是晴photo
    忘年旅行
    12月6日大雪
    12月5日
    周六
    071204 晴
  • 原文地址:https://www.cnblogs.com/godbell/p/7583116.html
Copyright © 2020-2023  润新知