使用委托从另一个类调用主类函数

时间:2014-01-07 08:10:57

标签: c# delegates

我有一个表单和另一个类文件,当我单击主窗体中的一个按钮时,它将一个值传递给另一个文件中另一个类中的函数(此函数是通用的,由所有文件调用),它再次调用主表单/类中的函数并更新文本框。

我编写了代码,但它抛出异常,说“在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke。”

代码在这里.. plz纠正错误的地方。 主窗体有按钮和文本框。

主要表格

namespace One
{
public partial class Form1 : Form
{
    public delegate void WriteToListBoxDelegate(string StringForText);

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Class1 c1 = new Class1();
        int a = 9;

        c1.nnn(a);            
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }
    public void SetListBox(string StringForText)
    {
        textBox1.Text += DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss") + ": " + StringForText + '\n' + textBox1.Text;
        MessageBox.Show(textBox1.Text);            
    }

}
}

另一个类文件

namespace One
{
public  class Class1
{   
    public One.Form1 theMDIform = new One.Form1();

    public int nnn(int a)
    {

        theMDIform.Invoke(new Form1.WriteToListBoxDelegate(theMDIform.SetListBox), '1');
    return 0;
    }
}
}

2 个答案:

答案 0 :(得分:1)

您需要将Form1的引用传递给nnn()

c1.nnn(this, a);
...
public int nnn(Form1 theMDIform, int a)
{
    ...
}

并从Form1 theMDIform类中删除Class1成员。

目前,您从nnn()对象调用Form1,但之后又回拨了另一个Form1对象,该对象不正确。您需要回调相同的Form1对象。

<强>加成
当您从其他表单调用nnn()时,您还需要传递对Form1的引用。所以你需要另一种形式来以某种方式获得该引用。一种可能的解决方案是将对Form1的引用存储在静态变量中。这将是Singleton模式的实现。我个人不喜欢这种方法,因为您可能决定将来有几个Form1个对象:

class Form1{
    private static Form1 oInstance;

    // Don't call it from the `Form1` constructor because that
    // will publish the not completely constructed object!
    private void InitInstance(){
        if (oInstance == null)
            oInstance = this;
        else
            throw new SomeException(...);
    }

    public Form1 Instance{
        get{ return oInstance;}
    }
    ...
};

然后其他表单可以获得Form1.Instance所需的引用并将其传递给nnn()

但我更愿意将Form1对象的引用传递给每个表单,例如作为构造函数参数:

class OtherForm{
    private Form1 MainForm;

    public OtherForm(Form1 MainForm){ ...}
}

答案 1 :(得分:0)

为了避免紧张coupling,我建议不要使用parctices,例如将表单作为参数传递(如果必须,请使用符合DIP原则的界面),或者制作Class1从您的表单中“请求”操作。

我的建议是以主从方式设计你的程序。你的class1(伪装成奴隶)应该做它做的事情,并告诉谁想知道它使用事件的动作。你的奴隶班不应该知道你的更高级别的大师班的存在(你的形式是AKA)

表单将监听事件,并采取您认为适合触发事件的操作。

在底线,这并不是你现在所做的大改变。主要区别在于应删除事件WriteToListBoxDelegate,而不是将onNnn事件添加到class1并让您的表单听取该事件。

事件的代码可能如下所示:

public event EventHandler<StringArgs> onNnn;
public int nnn(int a)
{

    if(this.onNnn != null)
    {
        string s = "any text you want to path";
        StringArgs arg = new StringArgs(s);
        this.onNnn(this,arg);
    }
    return 0;
}

宣言StringArgs

public class StringArgs : EventArgs
{
    private readonly string _txt;
    public string Txt
    {
        get { return this._txt; }
    }

    public StringArgs (string txt)
    {
        this._txt = txt;
    }   
}

在表单中添加绑定到事件:

public Form1()
{
    InitializeComponent();
    class1Instance.onNnnn += this.HandleClass1Nnn;

}

private voit HandleClass1Nnn(object sender, StringArgs args)
{
     textBox1.Text += args.Txt;
}