C# - 以父表单调用函数

时间:2013-05-29 16:09:04

标签: c# forms

我正在尝试从另一种形式调用主窗体中的函数...已经调用了一个简单的函数,通过在主窗体中声明它是public static,但我无法调用所需的函数。 要调用的函数:

    public static void spotcall()
    {
        string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString();
        MainForm.txtSendKeys.Text = dial;// Here it asks me for a reference to an object.


        foreach (char c in txtSendKeys.Text)
        {
            sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked);
        }
        txtSendKeys.Clear();
    }

我用来从子表单调用它的过程:

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Text = "Hoho";
        MainForm.spotcall();
    }

我完全承认我缺乏一些关于C#的理论,但是因为它经常发生,我只需要为我的工作做,所以我希望得到帮助,如果我偶然得不到自己的解决方案。谢谢:))

7 个答案:

答案 0 :(得分:5)

您无法在静态方法中引用MainForm上的控件实例。就像编译器告诉你的那样,你需要一个表单实例来更新TextBoxes之类的东西。如果没有实例,您尝试更新的值会在哪里?

我不确定如何创建子表单,但是您可以在MainForm上调用方法的一种方法是直接向子表单提供MainForm实例的引用。这可能是通过构造函数或一些公共财产。

例如

public class ChildForm : Form {

    public MainForm MyParent { get; set; }

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Text = "Hoho";

        // Now your child can access the instance of MainForm directly
        this.MyParent.spotcall(); 
    }   

}

假设您在ChildForm内创建MainForm代码,为孩子提供参考非常简单:

var childForm = new ChildForm();
childForm.MyParent = this; // this is a `MainForm` in this case
childForm.Show();

您还需要使spotcall成为实例方法,而不是静态方法,并删除代码中MainForm的静态引用:

public void spotcall()
{
    string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString();
    // Now it no longer asks you for a reference, you have one!
    txtSendKeys.Text = dial;

    foreach (char c in txtSendKeys.Text)
    {
        sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked);
    }
    txtSendKeys.Clear();
}

答案 1 :(得分:2)

您无法在静态上下文中访问非静态成员,这意味着您必须使txtSendKeys保持静态,或使您的函数保持非静态。

答案 2 :(得分:1)

如果创建静态函数,则可能不会在函数内引用非静态函数的全局变量。

因此,为了使spotcall成为静态,你必须删除对txtSendKeys的引用(我假设这是你在表单中其他地方创建的文本框)或者必须在静态函数中声明txtSendKeys。

其他:

您通过变量拨号获取了上一行中txtSendKeys.Text的值。根本没有引用txtSendKeys.Text,我想你可以简单地使用变量拨号来完成这个功能并让函数保持静态(无论如何你都要清除它)。

public static void spotcall()
    {
        string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString();


        foreach (char c in dial)
        {
            sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked);
        }            
    }

虽然这不会克服同样的问题,但您可能会遇到checkBoxPrivate.Checked。

您可以将其更改为采用布尔参数。

public static void spotcall(Boolean PrivateChecked)
    {
        string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString();               

        foreach (char c in dial)
        {
            sideapp.Keyboard.SendKey(c.ToString(), PrivateChecked);
        }

    }

答案 3 :(得分:1)

我认为正确的方法是使用委托。这样,您的表单(窗口)不必知道任何有关父表单的信息(表单可以从不同的父表单打开)。

我们想要在子窗体关闭时调用父窗体中的函数(不要将窗体显示为模态)。

在您的子表单顶部创建一个委托:

    public delegate void CloseEvent();
    public CloseEvent WindowClosed;

创建表单结束事件并让它调用您的委托:

    private void child_FormClosing(object sender, FormClosingEventArgs e)
    {
      WindowClosed();
    }

父表单中的按钮可以显示子表单并设置回调:

    private ChildForm childform = null;

    private void buttonShowChildForm_Click(object sender, EventArgs e)
    {
      if (childform == null)
      {
        childform = new ChildForm();
        childform.WindowClosed += childClosed;
        childform.Show();
      } else
      {
        childform.BringToFront();
      }
    }

    private void childClosed()
    {
        childform = null;
    }

在此示例中,我们使用按钮打开不阻止父窗体的新窗体。如果用户第二次尝试打开表单,我们只需将现有表单放到前面即可向用户显示。当表单关闭时,我们将对象设置为null,以便下次单击按钮时打开一个新表单,因为旧表单在关闭时处理。

祝你好运   汉斯米林......

答案 4 :(得分:0)

您可以将共享代码放在两个表单都可见的第三个类中。所以,例如:

public class static HelperFunctions
{

    public static void spotcall()
    {
        . . . 
    }
}

然后替换

MainForm.spotcall()

HelperFunctions.spotcall()

答案 5 :(得分:0)

MainForm只是一个类。它具有类的结构。但是,您可以从中获得的唯一数据是static数据。

但是当您执行以下操作时,会显示该类的instanceMainForm MyFormInstance = new MainForm();

MainForm只能用于访问静态成员(方法,属性......)。 如果要获取txtSendKeys,则必须从实例(对象引用)获取它。那是因为文本框不是静态的,所以它只存在于表单的实例中。

因此,您应该执行以下操作:

  • spotcall不是静态的。
  • 将子格式变为MainForm MyParentMainForm;
  • 当您调用子项时,请将MyParentMainForm设置为mainform的实例。如果从主窗体调用它,则可以使用this关键字获取实例。
  • 在子表格中,请致电MyParentMainForm.spotcall

PS:我不确定是否有类似真正的儿童形式,或者你只是从另一个人那里打电话给新形式。如果确实有child表单,您可以获取Parent属性来访问主表单的实例。

答案 6 :(得分:0)

这是一种“设计模式”问题,我将详细说明,但如果您不希望此程序发生很大变化,我可以尝试解释解决此问题的最直接方法。 “静态”事物只存在一次 - 一次在整个应用程序中。当变量或函数是静态的时,从程序中的任何地方访问都会容易得多;但是你无法访问对象的相关数据,因为你没有指向该对象的特定实例(即,你有七个MainForms。你在调用这个函数是哪一个?)因为标准的WinForm设计需要你可以拥有显示7个MainForm副本,所有相关的变量将是实例变量或非静态变量。但是,如果您希望永远不会有第二个MainForm,那么您可以采用“单例”方法,并且可以轻松访问您的一个实例。

partial class MainForm {

    // only including the code that I'm adding; I'm sure there's a lot of stuff in your form.
    public static MainForm Instance { public get; private set; }

    protected void onInitialize() { // You need to hook this part up yourself.
        Instance = this;
    }
}

partial class SubForm {
    protected void onImportantButton() {
        MainForm.Instance.doImportantThing()
    }
}

在许多初学者的代码中,在表单类中放置过多的活动数据更改逻辑是一个非常常见的问题。这不是一个可怕的事情 - 你不想只是为了一个简单的事情而做5个控制课程。随着代码变得越来越复杂,你开始发现一些事情更有意义转移到不与用户交互的类的“子级”(所以,有一天,如果将其重新编码为服务器程序) ,你可以扔掉表单类,只使用逻辑类 - 理论上讲。许多程序员也需要一些时间来理解对象“实例”的整个概念,以及调用函数的“上下文”。