从另一个类和线程的接口回调更新winform

时间:2015-03-19 13:02:29

标签: c# multithreading winforms

我有一个winform和一个不断发送更新的接口回调。我希望能够从回调接口更新label1.Text。然而,因为inface在一个单独的线程上运行,我不认为我可以直接执行它所以我试图使用委托并调用。

但是我遇到了错误:

在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke - 位于

 form1.Invoke(form1.myDelegate, new Object[] { so.getString() });

这是完整的代码。

     public partial class Form1 : Form
     {

         MyCallBack callback;
         public delegate void UpdateDelegate(string myString);
         public UpdateDelegate myDelegate;

         public Form1()
         {
             InitializeComponent();

             myDelegate = new UpdateDelegate(UpdateDelegateMethod);
             callback = new MyCallBack(this);
             CallBackInterfaceClass.SetCallBack(callback);

            callback.OnUpdate();
        }

         public void UpdateDelegateMethod (String str)
         {
             label1.Text = str;
         }
     }

     class MyTestCallBack : Callback
     {
         public Form1 form1;
         public SomeObject so;

         public MyTestCallBack(Form1 form)
         {
             this.form1 = form;
         }

         public void OnUpdate(SomeObject someobj)
         {
             so = someobj;
             OnUpdate();
         }

         public void OnUpdate()
         {
             form1.Invoke(form1.myDelegate, new Object[] { so.getString() });
         }

     }

两个问题。

  1. 有谁能解释我做错了什么?

  2. 这实际上是最好的方法吗?

  3. 以下是基于bokibeg的回复(见下文)的答案,并进行了一些修改以使其有效:

    public partial class Form1 : Form {
    MyTestCallBack _callback;
    
    public Form1()
    {
        InitializeComponent();
    
        _callback = new MyTestCallBack();
        _callback.MyTestCallBackEvent += callback_MyTestCallBackEvent;
        _callback.OnUpdate();
    }
    
    private callback_MyTestCallBackEvent(MyTestCallBackEventArgs e)
    {
         if (InvokeRequired)
         {
            Invoke(new Action(() =>
            {
                callback_MyTestCallBackEvent(sender, e);
            }));
            return;
         }
         label1.Text = e.SomeObject.GetDisplayString();
    }
    
    class MyTestCallBackEventArgs : EventArgs 
    {
         public SomeObject SomeObj { get; set; } 
    }
    
    class MyTestCallBack : Callback 
    {
        public event EventHandler<MyTestCallBackEventArgs> MyTestCallBackEvent;
        private SomeObject _so;
    
    protected virtual void OnMyTestCallBackEvent(MyTestCallBackEventArgs e)
    {
        if (MyTestCallBackEvent != null)
            MyTestCallBackEvent(this, e);
    }
    
    public void OnUpdate(SomeObject someobj)
    {
        _so = someobj;
        OnMyTestCallBackEvent(new MyTestCallBackEventArgs { SomeObject = _so });
    } }
    

1 个答案:

答案 0 :(得分:1)

这就是我要做的事情:

public partial class Form1 : Form
{
    MyTestCallBack _callback;

    public Form1()
    {
        InitializeComponent();

        _callback = new MyTestCallBack();
        _callback.MyTestCallBackEvent += callback_MyTestCallBackEvent;
        _callback.OnUpdate();
    }

    private callback_MyTestCallBackEvent(MyTestCallBackEventArgs e)
    {
        // TODO: Invoke code here with e.g. label1.Text = e.SomeObj.ToString()...
    }
}

class MyTestCallBackEventArgs : EventArgs
{
    public SomeObject SomeObj { get; set; }
}

class MyTestCallBack : Callback
{
    public event EventHandler<MyTestCallBackEventArgs> MyTestCallBackEvent;
    private SomeObject _so;

    public MyTestCallBack()
    {
        //
    }

    protected virtual void OnMyTestCallBackEvent(MyTestCallBackEventArgs e)
    {
        if (MyTestCallBackEvent != null)
            MyTestCallBackEvent(e);
    }

    public void OnUpdate(SomeObject someobj)
    {
        _so = someobj;
        OnMyTestCallBackEvent(new MyTestCallBackEventArgs { SomeObject = _so });
    }
}

它将GUI逻辑与线程正在执行的操作分开。它会引发一场事件,而且它有责任随心所欲地做任何事情。

我不确定这是否编译,我是用文本垫写的。如果您有任何疑问,请告诉我。

你可能刚刚了解了代表并​​被其带走了,这与使用事件类似,但事件是正确放置在&#34;后端&#34;逻辑形式可能会也可能不会使用它。还要注意form的代码是如何更好的,它没有那么多的样板代码只是为了实现一些后台服务类。

但请注意,MyTestCallBackEvent事件可能会在您关闭表单后继续触发,因此请确保在表单关闭或处理时取消订阅(或者当您觉得表单不再需要时)

哦,我差点忘了:你得到的原始错误是因为你在没有要求的情况下打电话给Invoke而且Form肯定还没准备好。阅读此问题以查看how to safely invoke controls