1

我正在尝试从另一个表单调用一个主表单中的函数......已经通过在主表单中声明它为公共静态来调用一个简单的函数,但我无法调用所需的函数。要调用的函数:

    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# 的理论,但正如它经常发生的那样,我只需要为我的工作做它,所以如果我自己没有找到解决方案,我希望能得到帮助。谢谢 :)

4

7 回答 7

9

您不能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();
}
于 2013-05-29T16:21:51.357 回答
2

您不能在静态上下文中访问非静态成员,这意味着您必须将 txtSendKeys 设为静态,或将您的函数设为非静态。

于 2013-05-29T16:20:54.727 回答
2

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

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

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

    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,以便下次单击按钮时会打开一个新表单,因为旧表单在关闭时已被释放。

最好的问候汉斯·米林...

于 2015-01-27T10:28:06.030 回答
1

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

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

额外的:

您在上一行中通过变量 dial 获得了 txtSendKeys.Text 的值。我想您根本不需要引用 txtSendKeys.Text ,而是可以简单地使用变量 dial 来完成该功能并将该功能保持为静态(无论如何您都可以在最后清除它)。

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);
        }

    }
于 2013-05-29T16:16:23.280 回答
0

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

public class static HelperFunctions
{

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

然后更换

MainForm.spotcall()

HelperFunctions.spotcall()
于 2013-05-29T16:14:31.913 回答
0

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

但是instance当你这样做时,会出现该类的一个:MainForm MyFormInstance = new MainForm();

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

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

  • 使spotcall不是静态的。
  • 将一个变量放入子窗体中MainForm MyParentMainForm;
  • 当您调用孩子时,将 MyParentMainForm 设置为 mainform 的实例。如果它是从主窗体调用的,您可以使用this关键字获取实例。
  • 在子窗体内,调用MyParentMainForm.spotcall

PS:我不确定是否有像真正的子表格一样的东西,或者您是否只是从另一个表格中调用新表格。如果真的有一个child表单,您可以获取Parent访问主表单实例的属性。

于 2013-05-29T16:21:23.010 回答
0

这是一个“设计模式”问题,我将详细说明,但如果您不希望该程序发生很大变化,我可以尝试解释解决此问题的最直接方法。“静态”的东西只存在一次——在整个应用程序中一次。当变量或函数是静态的时,从程序中的任何地方访问都容易得多;但是您不能访问对象的关联数据,因为您没有指向该对象的特定实例(即,您有七个 MainForms。您在哪一个上调用此函数?)由于标准 WinForm 设计期望您可以拥有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 个控制类。随着代码变得越来越复杂,您开始发现将某些事情移到不与用户交互的类的“子级别”会更有意义(因此,有一天,如果将其重新编码为服务器程序,您可以丢弃表单类,而只使用逻辑类 - 从理论上讲)。许多程序员还需要一些时间来理解对象“实例”的整个概念,以及调用函数的“上下文”。

于 2013-05-29T16:22:40.640 回答