【问题标题】:call a main class function from another class using delegates使用委托从另一个类调用主类函数
【发布时间】:2014-01-07 08:10:56
【问题描述】:

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

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

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

主要形式

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

【问题讨论】:

  • 如果我直接从另一个类调用主函数的函数并更新文本框,当类函数的函数控件移回主窗体时,文本框将丢失数据。
  • 如果你指出你得到错误的地方会很好......
  • 错误出现在以下行:theMDIform.Invoke(new Form1.WriteToListBoxDelegate(theMDIform.SetListBox), '1');
  • 这看起来很危险的递归。
  • 您还试图在一个尚不存在的窗口上执行一个函数。你知道,就像你的错误所说的那样?你也有一个循环依赖。我建议你重新审视你是如何组织你的代码的。即使现在为您解决了这个错误,但在以后的道路上,您将遇到更多、更大的问题。

标签: c# delegates


【解决方案1】:

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

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

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

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

加法
当您从其他形式调用 nnn() 时,您还需要传递对 Form1 的引用。因此,您需要另一种形式来以某种方式获得该参考。一种可能的解决方案是将Form1 的引用存储在静态变量中。这将是单例模式的实现。我个人不喜欢这里的这种方法,因为您将来可能会决定拥有多个 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){ ...}
}

【讨论】:

  • 如果这个 nnn 是从另一个表单调用的,比如 Form2。然后它看起来像这样: Form2->nnn->Form1 然后 nnn 的签名会改变。不是吗?
  • @johnsonpinto 我将该问题的解决方案添加到我的答案中。
【解决方案2】:

为了避免紧coupling,我建议不要使用诸如传递表单作为参数的方式(如果必须,请使用遵循DIP原则的接口),或者使Class1"请求”表单中的操作。

我的建议是以主从方式设计你的程序。你的class1(冒充奴隶)应该做它所做的,并使用事件通知任何想知道它的行为的人。你的奴隶阶级不应该知道你的更高级别的大师班的存在(也就是你的形式)

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

归根结底,这与您目前所拥有的相比并没有太大变化。主要区别在于应该删除事件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;
}

【讨论】:

  • this.onNnn(this, theMDIform.SetListBox);说'Delegate'System.EventHandler'有一些无效的参数'和class1Instance.onNnnn += this.HandleClass1Nnn;说“Class1 不包含 onNnn 的定义”
  • StringArgs arg = new StringArgs(theMDIform.SetListBox);说“
  • 参数 '1':对于函数 'nnn' 中 Class1 中的上述错误行,无法从 'method group' 转换为 'string'
  • @johnsonpinto 再试一次。
  • 没有错误,但是 Class1 中的 'this.onNnn' 始终为空,因此不会更新 Form1 中的文本框。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 2016-09-28
  • 1970-01-01
相关资源
最近更新 更多