欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Winform笔记:窗体间相互访问的几种实现方法

程序员文章站 2022-05-06 08:05:06
...

窗体组合经常会使用到,但是要避免循环引用的问题。
窗体对象相互引用的可以使用单例模式,用窗体类静态方法获取实例对象再去调用具体内容。在窗体间相互引用时,使用单例可以解决循环引用问题。

窗体间的数据传递可以使用委托和事件

委托与事件的区别:个人乱扯
委托是类;事件是一种委托类型,提供发布和订阅机制。
委托由定义者注册和注销和执行;事件由定义者触发,提供调用者注册和注销
委托使用Func<> 和 Action<> 可以满足丰富的委托类型,注册委托的函数需要满足委托函数签名,可实现同步,异步且能带回调执行委托
事件直接用EventArgs,或EventArgs继承自定义事件类丰富事件属性;注册事件函数需要提过(object sender, MsgEventArgs e)参数

使用单例

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form2 : Form
    {
        //窗体组合经常会使用到,但是要避免循环引用的问题。
        //窗体对象相互引用的可以使用单例模式,用窗体类静态方法获取实例对象再去调用具体内容。在窗体间相互引用时,使用单例可以解决循环引用问题。

        public TextBox TextBox1
        {
            get
            {
                return this.textBox1;
            }
            set
            {
                this.textBox1 = value;
            }

        }
        //在Form2中添加Form3实例引用,组合
        private static readonly Form3 form3 = Form3.GetForm3();


        //Form2实例单例
        private static readonly Form2 form2 = new Form2();

        private Form2()
        {
            InitializeComponent();
        }

        //获取Form2单例实例
        public static Form2 GetForm2()
        {
            return form2;
        }


        private void Form2_Load(object sender, EventArgs e)
        {
            banding(form3, panel1);
        }

        private void banding(Form form, Panel panel)
        {
            panel.Controls.Clear();
            form.FormBorderStyle = FormBorderStyle.None;
            form.StartPosition = FormStartPosition.Manual;
            //form.Size = page.Size;
            form.Dock = DockStyle.Fill;
            form.TopLevel = false;
            panel.Controls.Add(form);
            form.Show();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //在Form2中通过form3引用修改Form3内容
            form3.TextBox1.Text = "123";
        }
        private void button2_Click(object sender, EventArgs e)
        {
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Form4 form4 = new Form4();
            form4.Show();
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form3 : Form
    {
        public TextBox TextBox1
        {
            get
            {
                return this.textBox1;
            }
            set
            {
                this.textBox1 = value;
            }

        }

        //Form3实例单例
        private static readonly Form3 form3 = new Form3();
        private Form3()
        {
            InitializeComponent();
        }

        public static Form3 GetForm3()
        {
            return form3;
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //因为Form2已经组合了Form3,想要通过Form3中修改Form2内容,不应该在Form3中组合Form2,会导致循环引用
            //应该在Form3中直接调用Form2获取对象引用的静态方法去调用具体内容
            //在窗体间相互引用时,使用单例可以解决循环引用问题
            Form2.GetForm2().TextBox1.Text = "456";
        }

        private void button2_Click(object sender, EventArgs e)
        {

        }

        private void Form3_Load(object sender, EventArgs e)
        {

        }
    }
}

使用委托和事件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp2
{
    public class MsgEventArgs : EventArgs//自定义事件类;无参数时可以直接用EventArgs
    {
        public string Msg { get; private set; }
        public MsgEventArgs(string msg)
        {
            this.Msg = msg;
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    //窗体间的数据传递可以使用委托和事件

    public partial class Form4 : Form
    {
        //定义委托
        public Action<string> SendMsg { get; set; }

        public Form4()
        {
            InitializeComponent();
        }

        private void Form4_Load(object sender, EventArgs e)
        {
            Form5 form5 = new Form5();         
            SendMsg += form5.SetText;//绑定委托;但委托被执行时,绑定委托的函数将被执行;可同步,异步且能带回调执行委托

            form5.MsgInfoEvent += BingEvent;//订阅事件;但事件被触发时,订阅事件的函数将被调用

            //委托与事件的区别:个人乱扯
            //委托由定义者注册和注销和执行;事件由定义者触发,提供调用者注册和注销
            //委托使用Func<> 和 Action<> 可以满足丰富的委托类型,注册委托的函数需要满足委托函数签名,可实现同步,异步且能带回调执行委托
            //事件直接用EventArgs,或EventArgs继承自定义事件类丰富事件属性;注册事件函数需要提过(object sender, MsgEventArgs e)参数


            banding(form5, panel1);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //执行委托
            //if (SendMsg != null)
            //{
            //    //执行委托,向form5传值
            //    SendMsg(this.textBox1.Text);
            //}  

            //同步执行委托;阻塞
            Debug.WriteLine("button1_Click begin");
            //SendMsg.Invoke(this.textBox1.Text);

            //异步执行委托;非阻塞
            //需要在程序入口添加 Control.CheckForIllegalCrossThreadCalls = false; //设置不捕获线程异常 
            //解决“线程间操作无效: 从不是创建控件“xxxx”的线程访问它。”
            //SendMsg.BeginInvoke(this.textBox1.Text,null,null);
            SendMsg.BeginInvoke(this.textBox1.Text, Callback, null);//异步执行委托,委托函数执行完成后再执行回调函数Callback

            Debug.WriteLine("button1_Click end");
        }

        //SendMsg回调函数
        public void Callback(IAsyncResult iar)
        {
            //获取绑定委托函数的引用
            AsyncResult ar = (AsyncResult)iar;
            Action<string> del = (Action<string>)ar.AsyncDelegate;
            del.EndInvoke(iar);//等待委托函数执行完成
            Debug.WriteLine("Callback end");
        }

        //订阅事件函数
        private void BingEvent(object sender, MsgEventArgs e)
        {
            this.textBox1.Text = e.Msg;
        }

        private void banding(Form form, Panel panel)
        {
            panel.Controls.Clear();
            form.FormBorderStyle = FormBorderStyle.None;
            form.StartPosition = FormStartPosition.Manual;
            //form.Size = page.Size;
            form.Dock = DockStyle.Fill;
            form.TopLevel = false;
            panel.Controls.Add(form);
            form.Show();
        }


    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form5 : Form
    {

        public event EventHandler<MsgEventArgs> MsgInfoEvent;//类中声明事件;发布事件;提供外部订阅+=和注销-=
        public Form5()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //触发事件,外部订阅事件的函数将被执行
            EventHandler<MsgEventArgs> msgInfo = MsgInfoEvent;
            if (msgInfo != null)
            {
                msgInfo(this, new MsgEventArgs(this.textBox1.Text));
            }
        }
        public void SetText(string msg)
        {
            System.Threading.Thread.Sleep(3000);
            this.textBox1.Text = msg;
        }
    }

}

测试代码链接