简体   繁体   English

从子窗体访问主窗体中的控件

[英]Accessing a control in a main form from a child form

I have a main form with 3 main panels:我有一个带有 3 个主面板的主窗体:

  • Left one is the menu左边是菜单
  • Top one is a simple media player最上面的是一个简单的媒体播放器
  • Main one is the host for child panels主要是子面板的主机

The song selection is done in the child panel (through a datagrid ) and I would like to send the song name to the top panel, in a label song_played to begin with (which is in the main form).歌曲选择在子面板中完成(通过datagrid ),我想将歌曲名称发送到顶部面板,以标签song_played开头(在主窗体中)。

This is how I'm opening the child form (click on the menu):这是我打开子表单的方式(单击菜单):

private void openChildFormInPanel(Form childForm)
    {
        if (activeForm != null)
            activeForm.Close();
        activeForm = childForm;
        childForm.TopLevel = false;
        childForm.FormBorderStyle = FormBorderStyle.None;
        childForm.Dock = DockStyle.Fill;
        panelChildForm.Controls.Add(childForm);
        panelChildForm.Tag = childForm;
        panelChildForm.Parent = this;           
        childForm.BringToFront();
        childForm.Show();
    }

panelChildForm is the child panel located in the main form. panelChildForm是位于主窗体中的子面板。

On the click event I fire:在我触发的点击事件中:

openChildFormInPanel(new Stats_form());

In my child form, i tried several solutions but i have an exception System.NullReferenceException because the parent form is always null :在我的子表单中,我尝试了几种解决方案,但我有一个异常System.NullReferenceException因为父表单始终为null

this.Owner.Controls["song_played"].Text = (string)dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[2].Value;

I also tried :我也试过:

((Form1)this.Owner).lablSetText((string)dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[2].Value);

Form1 being the name of my main form and labSetText being a function to set the text of the label on the main form. Form1是我的主表单的名称, labSetText是一个用于设置主表单上标签文本的函数。

Last,最后的,

this.Parent.Controls["song_played"].Text = " dfgdfggdf";

fires the same exception触发相同的异常

Any help is appreciated :)任何帮助表示赞赏:)

You could keep looking around in the debugger - Quick Watch will help - and eventually you will find the properties of this on the childForm instance that allow you to go back "up" to the main for and back "down" to the top panel.您可以继续在调试器中环顾四周 - Quick Watch 会有所帮助 - 最终您会在childForm实例上找到它的属性, this属性允许您“向上”返回主 for 并“向下”返回到顶部面板。

I'd like to suggest another approach, that is less fragile though.我想建议另一种方法,虽然它不那么脆弱。

Instead of just having a Form for the Child form with the data grid view, derive your own form and add an event:与其只为带有数据网格视图的子表单创建一个Form ,不如派生出您自己的表单并添加一个事件:

public SongSelectorForm : Form
{
    public event EventHandler<String> SongChanged;

    private void OnDataGridViewClick(object sender, EventArgs e)
    {
        SongChanged?.Invoke(this, "New Song Name"); //Taken from the data grid view.
        //N.B. ?.Invoke is a safe way of calling the event handler in case no one is listened.
    }
}

Now in the MainForm when you add the ChildForm you can subscribe to the event:现在在 MainForm 中,当您添加 ChildForm 时,您可以订阅该事件:

private void openChildFormInPanel(SongSelectorForm childForm)
{
    //snip the above
    childForm.SongChanged += HandleSongChange;
}

//We are adding a new method to the main form now to specifically handle a song change event from somewhere.
private void HandleSongChange(object sender, String songName)
{
    this.TopForm.SongName = songName; //or whatever you use to update the songname in the top form.
}

As the Main Form is the "parent" it makes sense that it knows about its children.由于主窗体是“父窗体”,因此它知道它的子窗体是有道理的。 Using events is a way for the "parent" to orchestrate the behavior of the children without the children knowing about each other.使用事件是“父母”在孩子们不了解彼此的情况下编排孩子们的行为的一种方式。

I added a TopForm.SongName , so that the "parent" had an easier way of talking to the TopForm without knowing what the underlying controls are:我添加了一个TopForm.SongName ,以便“父级”可以更轻松地与 TopForm 对话,而无需知道底层控件是什么:

eg例如

//in topform
public String SongName
{
    get { return someControl.Text; }
    set { someControl.Text = value; }
}

This allows you to change things in TopForm but still maintains a simple way for Mainform to change the SongName without having to change that too.这允许您在 TopForm 中更改内容,但仍然保持 Mainform 更改 SongName 的简单方法,而无需更改它。

The more you learn about C# you will see that you could use Interfaces to define "contracts" between these components so they know less about each other, making it easier to change one part without worrying about breaking anything else.您对 C# 了解得越多,您就会发现可以使用接口来定义这些组件之间的“契约”,这样它们之间的相互了解就会减少,从而可以更轻松地更改某一部分,而不必担心会破坏其他任何部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM