Winforms:从另一个类更新Form上的标签

时间:2012-03-21 12:20:56

标签: c# winforms multithreading label progress

我有一个项目,我需要从另一个类方法中更新标签文本。值得注意的是,此方法是从后台工作线程调用的。

我已尝试将文本传递给Workers ReportProgress()中的UserState Obj更新;方法,然后在主窗体上触发工作器进度更改事件时更新标签。这有效,但显然只会在引发进度更改事件时更新标签文本。

我的代码是不断加载/删除代理,我需要一个标签来显示它(因为只有当bg worker进展时才更新事件触发)。希望有人可以提供帮助。

由于

编辑*这里有一些代码可以让问题更容易理解: -

  public string Request(string action)
    {

        if (string.IsNullOrWhiteSpace(action))
        {
            return "";
        }

        HttpWebRequest req;

        string response = string.Empty;
        while (response.Equals(string.Empty) && proxy != null)
        {
            try
            {
                req = (HttpWebRequest)WebRequest.Create(action);
                req.Proxy = proxy;
                response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
            }
            catch (Exception ex)
            {
                RemoveProxy(proxy);
                MessageBox.Show("Proxy Removed: " + proxy.Address.ToString());

                proxy = GenNewProx();
                MessageBox.Show("New proxy" + proxy.Address.ToString());
            }
        }

        return response;
    }

^^^ - 我需要设置标签文本,目前使用Msgboxs,但更新主表单上的标签显然更可取

   foreach (string url in URLs)
        {
            result.URL = url;
            result.Shares = grabber.GetFacebookShares(url);
            result.Tweets = grabber.GetTweetCount(url);
            result.PlusOnes = grabber.GetPlusOnes(url);

            bgWorker.ReportProgress((outputGridView.Rows.Count * 100) / importGridView.Rows.Count, result);
        }

^^^ - 在主窗体上的bg worker do_work方法内。

第二次编辑*

我对事件有点新意,但是每次我切换代理并用新的代理/ msg传入一个字符串参数然后在主窗体中订阅此事件时,我就不会触发自定义事件,例如Proxy_Changed,然后在此事件触发时在主窗体上设置标签text =字符串args?我可能会说乱七八糟但是:/

3 个答案:

答案 0 :(得分:3)

以下是我认为课程中需要完成背景工作的重要部分:

public class Grabber
{
    public event EventHandler<MyArgs> NotifyParentUI;

    // other code.....

    public string Request(string action)
    {
        if (string.IsNullOrWhiteSpace(action))
        {
            return "";
        }

        HttpWebRequest req;

        string response = string.Empty;
        while (response.Equals(string.Empty) && proxy != null)
        {
            try
            {
                req = (HttpWebRequest)WebRequest.Create(action);
                req.Proxy = proxy;
                response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
            }
            catch (Exception ex)
            {
                RemoveProxy(proxy);
                NotifyParentUI(this, new MyArgs() 
                   { Message = string.Format("Proxy Removed: {0}", proxy.Address.ToString()) });

                proxy = GenNewProx();
                NotifyParentUI(this, new MyArgs() 
                   { Message = string.Format("New Proxy: {0}", proxy.Address.ToString()) });
            }
        }

        return response;
    } 
}

在您的主表单中,您有一种更新标签的方法,该方法是线程安全的:

public void UpdateMyLabel(object sender, MyArgs ea)
{
    this.Invoke(new MethodInvoker(
        delegate()
        {
            labelControl1.Text = ea.Message;
        }
        ));
}

同样在主窗体中,您必须创建“抓取器”的实例:

Grabber grabber = new Grabber();
grabber.NotifyParentUI += UpdateMyLabel;

你应该有一个在自己的线程上运行的方法:

public void ThreadProc()
{

    // other code before this....

    foreach (string url in URLs)
    {
       result.URL = url;
       result.Shares = grabber.GetFacebookShares(url);
       Thread.Sleep(0); // may want to take the Sleeps out
       result.Tweets = grabber.GetTweetCount(url);
       Thread.Sleep(0);
       result.PlusOnes = grabber.GetPlusOnes(url);
       Thread.Sleep(0);
    }
}

以下是您在主表单部分中启动主题的方法:

Thread t = new Thread(new ThreadStart(ThreadProc));
t.Start();

作为旁注,如果您需要将数据传递给您的线程,请查看此处: Passing Data to Threads and Retrieving Data from Threads

答案 1 :(得分:2)

使用Invoke方法在UI线程上运行匿名函数以更新标签。例如:

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += (sender, args) =>
                        {
                            for (int i = 0; i < 10000; ++i)
                            {
                                DoSomeWorkInBackground();

                                // Update the label in UI thread
                                MyOtherFormInstance.Invoke((MethodInvoker)delegate()
                                                                            {
                                                                                MyOtherFormInstance.SetLabelText(i);
                                                                            });
                                DoSomOtherWorkInBackground();
                            }
                        };

在您的表格中:

    public void SetLabelText(int i)
    {
        myLabel.Text = i.ToString();
        // not sure that this needed, but try:
        myLabel.Invalidate();
    }

答案 2 :(得分:1)

从您的问题和随后的评论中听到您在WinForms项目中运行代码的其他答案,如果我错了,请纠正我?在winform中,主程序线程通常总是静态的(static void Main())因此你必须使你的EventHandler 静态也避免空异常。我相信这会解决您的问题,因为它听起来像您的其他代码是正确的吗?