none
C#中,如何在一个子窗体里面修改主窗体中的控件? RRS feed

  • 问题

  • 假如Form1是主窗体,程序运行之后创建一个自窗体ChildForm,我需要在ChildForm里面去修改Form1中的ListView控件的内容,应该如何做?

    如果是在Form1里面修改ChildForm里面的控件,我就知道,只需要把ChildForm里面的控件设置修改权限为“Public”,然后就可以直接用ChildForm.listView1来修改了。

    但是反过来却遇到了问题,因为我不知道Form1的实体对象在哪里?


    da jia hao!
    2010年3月18日 16:34

答案

  • 你好!
    在窗体间传递数据的方法比较多:
    1,在子窗体中自定义一个构造函数,参数类型是主窗体,当要显示子窗体的时候,就用这个构造函数来实例化子窗体,然后把this指针传进去,说起来太抽象了,我大概一写大家应该就明白了:
       public class frmMain:Form
       {
            ...
            frmControl controlForm=new frmControl(this);
            controlForm.Show();
        }

        public class frmControl:Form  //子窗体,用来控制主窗体的某些显示!
        {
             private frmMain mainForm;
             public frmControl(frmMain mainForm)
             {
                  this.mainForm=mainForm;
              }
              private void button1_Click(object sender,EventArgs e)

                   {

                               frmMain.textBox1.Text=this.textBox1.Text;  //把子窗体的文本框值传递给主窗体的文本框!

                   }

         }
    2,我个人感觉上面的方法不是很好,虽然实现起来很简单,只是想改变窗体的标题文本,就把整个主窗体的引用都传递给子窗体,这样的方式不是很幽雅,我们用接口来改进上面的方法,这样可以限制暴露给子窗体的功能,降低窗体之间的耦合度:
       public interface IChangeTitle:
       {
            void ChangeTitle(string title);
        }
       public class frmMain:Form,IChangeTitle
       {
            ...
            frmControl controlForm=new frmControl(this);
            controlForm.Show();
            public void ChangeTitle(string title)
            {
                 this.Text=title;
             }       
        }

        public class frmControl:Form  //子窗体,用来控制主窗体的某些显示!
        {
             private IChangeTitle ichangeTitle;
             public frmControl(IChangeTitle ichangeTitle)
             {
                  this.ichangeTitle=ichangeTitle;
              }
              private void button1_Click(object sender,EventArgs e)

                   {

                               ichangeTitle.ChangeTitle(this.textBox1.Text);  //通过接口来调用方法

                   }

         }
    3,为了进一步降低窗体之间的耦合度,我们可以用委托来实现这个需求:
        public partial class ChildForm : Form
        {
            public delegate void TitleChangedHandler(string title);
            public TitleChangedEventHandler TitleChanged;
            public ChildForm()
            {
                InitializeComponent();
            }

           
            private void btn_Ok_Click(object sender, EventArgs e)
            {           
                if (TitleChanged != null)
                    TitleChanged("Test Title"); //委托调用
               
            }
        }
    主窗体给委托变量赋值就可以了:
        public partial class MainForm : Form
        {
            private ChildForm loginForm = new ChildForm();
            public MainForm()
            {
                InitializeComponent();
                loginForm.TitleChanged = new ChildForm.TitleChangedEventHandler(FormTitleChanged);
            }

            protected void FormTitleChanged(string title)
            {
                this.Text = title;
            }

            private void button1_Click(object sender, EventArgs e)
            {
                loginForm.Show();
            }
        }

    4,也可以在子窗体中定义一个自定义的事件,然后自定义一个事件参数,用来传递你想传递的一些信息:
        public partial class ChildForm : Form
        {
            public class TitleChangedEventArgs : EventArgs //事件参数类
            {
                private string title = "";
                public string Title
                {
                    get
                    {
                        return title;
                    }
                    set
                    {
                        title = value;
                    }
                }
            }
            public delegate void TitleChangedEventHandler(object sender, TitleChangedEventArgs e);
            public event TitleChangedEventHandler TitleChanged;
            public ChildForm()
            {
                InitializeComponent();
            }

           
            private void btn_Ok_Click(object sender, EventArgs e)
            {
                TitleChangedEventArgs e1=new TitleChangedEventArgs();
                e1.Title="Login sucessed";
                OnTitleChanged(e1);//触发事件
               
            }

            protected virtual void OnTitleChanged(TitleChangedEventArgs e)   //触发事件的方法
            {
                if (TitleChanged != null)
                    TitleChanged(this, e);
            }
        }

    主窗体订阅这个事件就可以了:
        public partial class MainForm : Form
        {
            private ChildForm loginForm = new ChildForm();
            public MainForm()
            {
                InitializeComponent();
                loginForm.TitleChanged += new ChildForm.TitleChangedEventHandler(FormTitleChanged);
            }

            protected void FormTitleChanged(object sender, ChildForm.TitleChangedEventArgs e)
            {
                this.Text = e.Title;
            }

            private void button1_Click(object sender, EventArgs e)
            {
                loginForm.Show();
            }
        }


    周雪峰
    • 已标记为答案 liubin 2010年3月20日 3:53
    2010年3月19日 6:47
    版主

全部回复

  • 你好!

    你可以使用相同的方式,但这里需要将 form1 传递给 childform。如

     

    public partial class Form1 : Form
    {
        private void Show()
        {
            // 将 from1 通过构造函数传递给 childform
            using (ChildForm cf = new ChildForm(this))
            {
                cf.ShowDialog();
            }
        }
    }
    
    public partial class ChildForm : Form
    {
        private Form1 from1;
        // 增加一个带参的构造函数,用于接收 from1.
        public ChildForm(Form1 from1)
        {
            InitializeComponent();
            this.from1 = from1;
        }
    }

     


    知识改变命运,奋斗成就人生!
    2010年3月19日 1:52
    版主
  • 这样也行啊。请问这是标准做法吗?
    da jia hao!
    2010年3月19日 2:48
  • 没有标准做法,只有是否合适.......

     

    也可以在 ChildForm 上面添加事件,然后主窗体响应它的事件。

     

    不过主界面可是单线程的,嘿嘿

    2010年3月19日 2:53
  • 不管你使用什么方式来修改,建议在 from1 中暴露一个方法或事件来修改你的控件,而不是直接操作,避免以后产生混乱。
    知识改变命运,奋斗成就人生!
    2010年3月19日 2:56
    版主
  • 事实上,如果我不把Form1的实体传给ChildForm,那么我就必须用静态函数,而静态函数里面根本就无法对ListView控件操作。。。。因为ListView是在designer.cs里面自动生成的,我应该不能修改它的属性。


    da jia hao!
    2010年3月19日 3:06
  • 你好!
    在窗体间传递数据的方法比较多:
    1,在子窗体中自定义一个构造函数,参数类型是主窗体,当要显示子窗体的时候,就用这个构造函数来实例化子窗体,然后把this指针传进去,说起来太抽象了,我大概一写大家应该就明白了:
       public class frmMain:Form
       {
            ...
            frmControl controlForm=new frmControl(this);
            controlForm.Show();
        }

        public class frmControl:Form  //子窗体,用来控制主窗体的某些显示!
        {
             private frmMain mainForm;
             public frmControl(frmMain mainForm)
             {
                  this.mainForm=mainForm;
              }
              private void button1_Click(object sender,EventArgs e)

                   {

                               frmMain.textBox1.Text=this.textBox1.Text;  //把子窗体的文本框值传递给主窗体的文本框!

                   }

         }
    2,我个人感觉上面的方法不是很好,虽然实现起来很简单,只是想改变窗体的标题文本,就把整个主窗体的引用都传递给子窗体,这样的方式不是很幽雅,我们用接口来改进上面的方法,这样可以限制暴露给子窗体的功能,降低窗体之间的耦合度:
       public interface IChangeTitle:
       {
            void ChangeTitle(string title);
        }
       public class frmMain:Form,IChangeTitle
       {
            ...
            frmControl controlForm=new frmControl(this);
            controlForm.Show();
            public void ChangeTitle(string title)
            {
                 this.Text=title;
             }       
        }

        public class frmControl:Form  //子窗体,用来控制主窗体的某些显示!
        {
             private IChangeTitle ichangeTitle;
             public frmControl(IChangeTitle ichangeTitle)
             {
                  this.ichangeTitle=ichangeTitle;
              }
              private void button1_Click(object sender,EventArgs e)

                   {

                               ichangeTitle.ChangeTitle(this.textBox1.Text);  //通过接口来调用方法

                   }

         }
    3,为了进一步降低窗体之间的耦合度,我们可以用委托来实现这个需求:
        public partial class ChildForm : Form
        {
            public delegate void TitleChangedHandler(string title);
            public TitleChangedEventHandler TitleChanged;
            public ChildForm()
            {
                InitializeComponent();
            }

           
            private void btn_Ok_Click(object sender, EventArgs e)
            {           
                if (TitleChanged != null)
                    TitleChanged("Test Title"); //委托调用
               
            }
        }
    主窗体给委托变量赋值就可以了:
        public partial class MainForm : Form
        {
            private ChildForm loginForm = new ChildForm();
            public MainForm()
            {
                InitializeComponent();
                loginForm.TitleChanged = new ChildForm.TitleChangedEventHandler(FormTitleChanged);
            }

            protected void FormTitleChanged(string title)
            {
                this.Text = title;
            }

            private void button1_Click(object sender, EventArgs e)
            {
                loginForm.Show();
            }
        }

    4,也可以在子窗体中定义一个自定义的事件,然后自定义一个事件参数,用来传递你想传递的一些信息:
        public partial class ChildForm : Form
        {
            public class TitleChangedEventArgs : EventArgs //事件参数类
            {
                private string title = "";
                public string Title
                {
                    get
                    {
                        return title;
                    }
                    set
                    {
                        title = value;
                    }
                }
            }
            public delegate void TitleChangedEventHandler(object sender, TitleChangedEventArgs e);
            public event TitleChangedEventHandler TitleChanged;
            public ChildForm()
            {
                InitializeComponent();
            }

           
            private void btn_Ok_Click(object sender, EventArgs e)
            {
                TitleChangedEventArgs e1=new TitleChangedEventArgs();
                e1.Title="Login sucessed";
                OnTitleChanged(e1);//触发事件
               
            }

            protected virtual void OnTitleChanged(TitleChangedEventArgs e)   //触发事件的方法
            {
                if (TitleChanged != null)
                    TitleChanged(this, e);
            }
        }

    主窗体订阅这个事件就可以了:
        public partial class MainForm : Form
        {
            private ChildForm loginForm = new ChildForm();
            public MainForm()
            {
                InitializeComponent();
                loginForm.TitleChanged += new ChildForm.TitleChangedEventHandler(FormTitleChanged);
            }

            protected void FormTitleChanged(object sender, ChildForm.TitleChangedEventArgs e)
            {
                this.Text = e.Title;
            }

            private void button1_Click(object sender, EventArgs e)
            {
                loginForm.Show();
            }
        }


    周雪峰
    • 已标记为答案 liubin 2010年3月20日 3:53
    2010年3月19日 6:47
    版主
  • 非常感谢版主的详细帮助。我已经用事件的方式实现了我的功能!


    da jia hao!
    2010年3月20日 3:53
  • 不客气啊!
    周雪峰
    2010年3月20日 5:56
    版主