如何从加载在面板中的子用户控件中访问父类函数/控件

5
我有一个主表单,其中包含一个面板,该面板将不同的用户控件加载到面板中。 现在我需要从用户控件中访问主表单中的函数。 以下是我的代码:
这是我的主窗体类:
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        loadlogin();
    }

    private void loadlogin()
    {
        login log = new login();
        mainPannel.Controls.Clear();
        mainPannel.Controls.Add(log);
    }

    public void mytest()
    {

    }
}

正文翻译:正如您所看到的,我正在将一个用户控件加载到主面板中。现在让我们来看看这个用户控件:
public partial class login : UserControl
{
    string MyConString = "";

    public login()
    {
        InitializeComponent();
    }


    public void button1_Click_1(object sender, EventArgs e)
    {

     //I want to call the parent function mytest(); HOW????

    }

}

当按钮1被点击时,我想要访问mytest()函数。我已经尝试了很多其他的解决方案,但仍然感到困惑。我已经使用了:
 Form my = this.FindForm();
 my.Text = "asdasfasf";

这让我可以引用父级并更改表单文本,但是如何访问它的函数呢?

你是否将 my.Text 的修饰符属性设置为 public? - string.Empty
3个回答

15

好的,上面的答案虽然可以工作,但将“父表单”传递给用户控件不是良好的编码实践。用户控件应该位于与您的表单项目不同的项目中,您的表单项目应引用控件项目以获得对它们的可见性。例如,假设您希望此UserControl在某个时刻嵌套在另一个UserControl中。如果您的代码没有重载构造函数,则不再起作用。更好的解决方案是使用事件。我提供了使用CustomEventArg的实现。通过这样做,您的登录UserControl可以放置在任何东西上并仍然有效。如果不需要更改父级文本的功能,请不要注册事件。下面是代码,希望能帮助到某些人。

这里是表单代码:

public Form1()
{
    InitializeComponent();

    loadlogin();
}

private void loadlogin()
{
    login log = new login();

    //Registers the UserControl event
    log.changeParentTextWithCustomEvent += new EventHandler<TextChangedEventArgs>(log_changeParentTextWithCustomEvent);

    mainPannel.Controls.Clear();
    mainPannel.Controls.Add(log);
}

private void log_changeParentTextWithCustomEvent(object sender, TextChangedEventArgs e)
{
    this.Text = e.Text;
}

这里是“登录”用户控件的代码(在我的测试解决方案中,只是一个带有按钮的用户控件)

public partial class login : UserControl
{
    //Declare Event with CustomArgs
    public event EventHandler<TextChangedEventArgs> changeParentTextWithCustomEvent;
    private String customEventText = "Custom Events FTW!!!";

    public login()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //Check to see if the event is registered...
        //If not then do not fire event
        if (changeParentTextWithCustomEvent != null)
        {
            changeParentTextWithCustomEvent(sender, new TextChangedEventArgs(customEventText));
        }
    }
}

最后是 CustomEventArgs 类:

public class TextChangedEventArgs : EventArgs
{
    private String text;

    //Did not implement a "Set" so that the only way to give it the Text value is in the constructor
    public String Text
    {
        get { return text; }
    }

    public TextChangedEventArgs(String theText)
        : base()
    {
        text = theText;
    }
}

用这种方式编写控件,对表单没有可见性将允许您的用户控件完全可重用,不会绑定到任何类型或种类的父级。只需定义一个用户控件可以触发的行为,并在必要时注册它们。我知道这是一篇旧文章,但希望这能帮助有人编写更好的用户控件。


1
快到2016年了,WinForms仍然非常强大!感谢您的答案,帮了我很多!点个赞! - Westerlund.io

7
这可能会有所帮助:
public partial class Form1 : Form
{
    //Other codes

    private void loadlogin()
    {
        login log = new login(this);    //CHANGE HERE
        mainPannel.Controls.Clear();
        mainPannel.Controls.Add(log);
    }

    //Other codes
}

而且

public partial class login : UserControl
{
    Form1 _parent;                       //ADD THIS

    public login(Form1 parent)
    {
        InitializeComponent();
        this._parent = parent;          //ADD THIS
    }

    public void button1_Click_1(object sender, EventArgs e)
    {
         this._parent.mytest();         //CALL WHAT YOU WANT
    }
}

将UserControl与其父级紧密耦合,通过声明对父类型的引用,这种编码方式实在是糟糕透顶。这完全消除了使用UserControl的任何优势,因为它永远不能独立于其父级存在。即使您创建了重载构造函数以允许传递不同类型的“父窗体”,每次想要将控件放置在不同的父类型上时,仍然必须修改代码。做自己一个忙...忽略这个答案并学习事件。 - Scope Creep
同意上面的评论,但这对于一次性场景是有用的。 - Ananda Prasad Bandaru

0

从您的用户控件:

((Form1)Parent).mytest();

这种方式有哪些缺点? - kk_Chiron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接