2012-03-21 99 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

相關問題