2012-04-04 56 views
1

我想了解如何定期更新我的GUI與一個簡單的文本字符串。從本質上講,我正在寫一個twitter應用程序,它定期輪詢twitter的更新。我希望更新的內容以文本塊的形式顯示在一個常量循環中。從後臺工作人員或事件更新GUI

爲了保持GUI響應,我需要在後臺工作線程中執行查詢,但是無法從此線程更新GUI。作爲一名學習者,我正在努力實現一種通過使用事件來更新GUI的方式。

在我下面的代碼中,我讚賞'MainWindowGoUpdate'將會出現在'錯誤的線程'上,但我怎樣才能獲得GUI線程來監聽事件呢?

一個指針讚賞。

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
    public static event UpdateTimeLineEvent _goUpdate; 

    public static string TheTimeLine; 
    UpdateTimeLine(); 
    } 

    private void UpdateTimeLine() 
    {   
    txtb_timeline.Text = "Updating..."; 

    BackgroundWorker startTimelineUpdater = new BackgroundWorker(); 
    startTimelineUpdater.DoWork += new DoWorkEventHandler(startTimelineUpdater_DoWork); 
    startTimelineUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(startTimelineUpdater_RunWorkerCompleted); 
    startTimelineUpdater.RunWorkerAsync();   
    } 

    void startTimelineUpdater_DoWork(object sender, DoWorkEventArgs e) 
    { 
    while (true) 
    { 
     Xtweet getSQL = new Xtweet(); 
     var sqlset = getSQL.CollectLocalTimelineSql(); 

     int i = 0; 
     while (i < 10) 
     { 
     foreach (var stringse in sqlset) 
     { 
      StringBuilder sb = new StringBuilder(); 

      sb.Append(stringse[0] + ": "); 
      sb.Append(stringse[1] + " @ "); 
      sb.Append(stringse[2]); 

      sb.Append("\n"); 

      TheTimeLine = sb.ToString(); 

      _goUpdate += new UpdateTimeLineEvent(MainWindowGoUpdate); 
      _goUpdate.Invoke(); 

      Thread.Sleep(10000); 
      i++; 
     } 
     } 
    }   
    } 
    void MainWindowGoUpdate() 
    { 
    txtb_timeline.Text = TheTimeLine; 
    } 
    void startTimelineUpdater_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
    txtb_timeline.Text = "should not see this"; 
    } 
} 
+1

SO已經充滿了數以萬計的這方面的問題。我想你的獨特之處在於你在工作線程中訂閱事件處理程序,而不是在啓動它之前訂閱它。 – 2012-04-04 22:36:40

回答

0

我會嘗試這些變化:
在你UpdateTimeLine添加

startTimelineUpdater.WorkerReportsProgress = true; 
startTimelineUpdater.ProgressChanged += new ProgressChangedEventHandler 
             (startTimelineUpdater_ProgressChanged); 

在startTimelineUpdater_DoWork刪除這些行

TheTimeLine = sb.ToString(); 
_goUpdate += new UpdateTimeLineEvent(MainWindowGoUpdate); 
_goUpdate.Invoke(); 

和插入這些:

BackgroundWorker bkgwk = sender as BackgroundWorker; 
bkgwk.ReportProgress(0, sb.ToString()); 

最後加進展事件

private void startTimelineUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    txtb_timeline.Text = e.ObjectState.ToString(); 
} 

現在你可以只留下調用UpdateTimeLine並刪除MainWindowGoUpdate方法

+0

嗨史蒂夫,感謝您的輸入。當我嘗試你的建議時,我遇到「此BackgroundWorker指出它不報告進度。修改WorkerReportsProgress以表明它報告進度。」 – Damo 2012-04-06 10:28:03

+0

對,我忘了添加該行。對我來說,MS爲什麼要求這條線,這是一種莫名的態度。添加ProgressChanged的事件處理程序時應該很明顯。現在看看我更新的答案。 – Steve 2012-04-06 10:43:05

+0

非常感謝。 startTimelineUpdater_ProgressChanged使用e.UserState.ToString();但效果很好。 :) – Damo 2012-04-06 10:54:50

1

您可以使用Dispatcher更新您的GUI。檢查this blog post是一個很好的例子,說明如何做到這一點。

0

在那裏你

txtb_timeline.Text = "should not see this"; 

就是你得到的結果。結果將在e.Result 您可以打包e.Result與多個屬性。

如果你想獲得中間結果,你可以使用進度。

+0

startTimelineUpdater_DoWork應該永遠不會調用已完成的方法 – Damo 2012-04-04 22:41:00

+0

好了解,那麼會不會進度做你所需要的? http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspx – Paparazzi 2012-04-04 22:59:13

1

可以使用Dispatcher類:

Dispatcher.BeginInvoke(
    DispatcherPriority.Input, new Action(() => 
    { 
     //update UI 
    })); 

不過你的情況我會收集從結果將BackgroundWorker放入局部變量中,然後更改標籤以循環訪問基於WPF Timer對象的結果。