2012-03-21 94 views
2

我有一个项目,我需要从另一个类的方法内更新标签文本。值得注意的是这个方法是从后台工作线程调用的。Winforms:从另一个类更新窗体上的标签

我试过在文本中传递更新为User ReportProgress()中的UserState Obj;方法,然后在主窗体上触发工人进度更改事件时更新标签。这可以起作用,但显然只有在引发进度更改事件时才会更新标签文本。

我有加载/删除代理不断的代码,我需要一个标签来显示它,因为它发生(而不是只有当bg工人进展改变事件触发时更新)。希望有人能帮助。

感谢

编辑*下面是一些代码,以使问题变得更容易理解: -

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工人在主窗体中执行do_work方法。

第二编辑*

我是一个有点新的事件,但是我能不火过一个自定义事件说Proxy_Changed每次我切换proxys而在字符串参数传递与新的代理/味精,我们再订阅在主窗体中将此事件添加到此事件中,然后在主窗体上设置标签text =当此事件触发时的字符串参数?虽然我可能说的是乱码tbh:/

回答

1

它从你的问题和后续的评论其他的答案,你是一个WinForms项目中运行代码的声音,纠正我,如果我错了吗?在一个WinForm程序主线程通常总是静态的(静态无效的主要()),因此,你必须使你的事件处理程序静态也避免了空例外。我相信这会解决你的问题,因为听起来你的其他代码是正确的?

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(); 
    } 
+0

这工作,但该标签只更新当工人报告了一些进展,除非我误解你的实现?我使用的是财产的其他类并将其设置为我想要显示的标签上的表格上的字符串,然后通过这个在例如为: myLabel.Text = gp.Status; – dtsg 2012-03-21 13:18:07

+0

我更新了示例,请尝试 – asktomsk 2012-03-21 13:57:11

+0

这看起来像调用ProgressChanged的更复杂的方式。为什么这种方式会更好? – 2012-03-21 14:10:02

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

+0

林不知道这将工作。标签文本只会在工作人员进行报告时才会更新,就像我之前提到的那样。 的BG工人里面做工作的方法,我有一些代码熄灭并检索一些值,然后将它们存储在结果列表中,然后传递给ReportProgress方法,这提高了ProgressChanged事件。 这意味着只有当我们完成检索某些值并将它们传递给ReportProgress时,标签文本才会更新,这不是我所需要的。 – dtsg 2012-03-21 15:29:18

+0

每次选择/删除新代理(发生在外部课程中)时,标签文本需要更新,但是,这不会导致工作进程更改事件触发。希望我已经解释清楚问题 – dtsg 2012-03-21 15:38:57

+0

@OldRed更新了事件处理程序 – 2012-03-21 16:51:50

相关问题