2010-08-02 20 views
6

嗯,我已經嘗試了幾種方法來使其工作,後臺工作者,Dispatcher.Invoke,被調用類中的線程以及任何東西似乎都不起作用。到目前爲止,最好的解決方案是調用控件調用的擴展方法。此外,我已經嘗試避免通過我的事件類傳遞標籤的數據,並簡單地在我的處理代碼中調用,但這沒有什麼區別。WPF - 處理過程中更新標籤內容

關於後臺組件,我不斷收到異常說明後臺工作人員很忙,所以我實例化了這個類幾次,但是標籤只有在整個操作完成後才明顯改變。

我已經刪除了我以前的代碼,這裏是所有相關的,因爲它看起來問題很難解決。

方法被稱爲

private void TestUris() 
     { 
      string text = new TextRange(rtxturis.Document.ContentStart, rtxturis.Document.ContentEnd).Text; 
      string[] lines = Regex.Split(text.Remove(text.Length - 2), "\r\n"); 

      foreach (string uri in lines) 
      { 
       SafeUpdateStatusText(uri); 
       bool result; 
       string modUri; 

       if (!uri.Contains("http://")) 
       { 
        modUri = uri; 
        result = StoreData.LinkUriExists(new Uri("http://" + modUri)); 
       } 
       else 
       { 

        modUri = uri.Substring(7); 
        result = StoreData.LinkUriExists(new Uri(uri)); 
       } 

       if (!result) 
       { 
        Yahoo yahoo = new Yahoo(); 
        yahoo.Status.Sending += (StatusChange); 
        uint yahooResult = 0; 

        yahooResult = yahoo.ReturnLinkCount(modUri); 

        if (yahooResult > 1000) 
        { results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 1000, "Will be processed", true)); } 
        else 
        { results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, (int)yahooResult, "Insufficient backlinks", false)); } 

       } 
       else 
       { 
        results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 0, "Previously been processed", false)); 
       } 
      } 


      foreach (var record in results) 
      { 
       dgvresults.Items.Add(record); 

      } 

      EnableStartButton(); 

     } 

雅虎類

public class Yahoo 
    {   

     /// <summary> 
     /// Returns the amount of links each Uri has. 
     /// </summary> 
     public uint ReturnLinkCount(string uri) 
     { 
      string html; 
      Status.Update(uri, false); //this is where the status is called 
      try 
      { 

       html = client.DownloadString(string.Format("http://siteexplorer.search.yahoo.com/search?p=http%3A%2F%2F{0}&fr=sfp&bwm=i", uri)); 

      } 
      catch (WebException ex) 
      { 
       ProcessError(ex.ToString()); 
       return 0; 
      } 

      return (LinkNumber(html)); 

     } 

狀態類

public class StatusEventArgs : EventArgs 
    { 
     private string _message; 
     private bool _isidle; 

     public StatusEventArgs(string message, bool isidle) 
     { 
      this._message = message; 
      this._isidle = isidle; 
     } 

     public bool IsIdle 
     { 
      get { return _isidle; } 
     } 

     public string Message 
     { 
      get { return _message; } 
     } 
    } 

    public class Status 
    { 
     public Status() 
     { 
     } 

     // Declaring an event, with a custom event arguments class 
     public event EventHandler<StatusEventArgs> Sending; 

     // Some method to fire the event. 
     public void Update(string message, bool isIdle) 
     { 
      StatusEventArgs msg = new StatusEventArgs(message, isIdle); 
      OnUpdate(msg); 
     } 

     // The method that invokes the event. 
     protected virtual void OnUpdate(StatusEventArgs e) 
     { 
      EventHandler<StatusEventArgs> handler = Sending; 

      if (handler != null) 
      { 
       handler(this, e); 
      } 
     } 
    } 

方法的內容改變

private void StatusChange(object sender, StatusEventArgs e) 
     { 

      if(!e.IsIdle) 
      { 
       lblstatus.Content = e.Message; 
       lblstatus.Foreground = StatusColors.Green; 
       lblstatus.Refresh(); 
      } 
      else 
      { 
       lblstatus.Content = e.Message; 
       lblstatus.Foreground = StatusColors.Grey; 
       lblstatus.Refresh(); 
      } 

     } 
標籤

稱爲刷新靜態方法:

public static class ExtensionMethods 
    { 
     private static Action EmptyDelegate = delegate() { }; 

     public static void Refresh(this UIElement uiElement) 
     { 
      uiElement.Dispatcher.Invoke(DispatcherPriority.Render , EmptyDelegate); 
     } 

另一個編輯:在我的多一點的時間碼凝望,我已經意識到,在foreach循環會執行得非常快,需要花費時間的操作是

yahooResult = yahoo.ReturnLinkCount(modUri); 

因此我聲明編輯狀態類(處理事件並調用標籤等)並將其引發。我已經得到了更好的結果,雖然它仍然是隨機的,有時我會看到一些標籤更新,有時候,即使通過了完全相同的URI,也很奇怪。

+0

此代碼不同的線程內部執行? – decyclone 2010-08-02 14:52:10

+0

不幸的是,我仍然沒有設法修復它:(。 – Ash 2010-08-02 16:38:35

回答

3

解決它是WOOHOOOOOOOO測試,測試,測試的3天。

我決定用上面的擴展方法啓動一個新項目,並簡單地通過for循環來測試UI更新功能。我開始測試不同的DispatchPrioraties(測試它們全部)。

奇怪的是,我發現最高優先級更糟糕,例如使用Send並沒有更新標籤,Render平均更新了兩次。這是我嘗試不同優先事項時遇到的奇怪行爲。我發現背景:

枚舉值爲4.在所有其他非空閒操作完成後處理操作。

現在,這聽起來正是我不想要的,顯然標籤應該在處理過程中更新,因此我從來沒有嘗試過。我猜測,一旦我的方法之一完成,在下一次調用之前,UI將被更新。我發現猜測,但它100%持續更新兩個單獨的操作正確。

謝謝大家。

+0

即時通訊如此困惑....我似乎遇到同樣的問題,並不能弄清楚......只是在方法結束時更新......當調試器中有線被擊中......請協助。 – Seabizkit 2017-07-05 09:01:36

0

將狀態信息作爲屬性添加到此對象上會更簡單/更好嗎?它只是觸發屬性更改通知?

那樣標籤文本(或其他)可以綁定到屬性,而不是讓異步工作嘗試更新標籤?

或者添加一個這樣的方法來更新狀態,如果你必須更新它?

void SafeUpdateStatusText(string text) 
    { 
     // update status text on event thread if necessary 
     Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate 
     { 
      lblstatus.Content = text; 
     }, null); 
    } 

否則,我不認爲我們有足夠的細節,以幫助尚未....

+0

感謝您的方法和建議約翰。我已經測試了該方法五次與不同的調度優先級和標籤不會改變,直到我發佈的方法 – Ash 2010-08-02 18:52:33

+0

感覺非常隨意,有時它會顯示一個更新,有時候會更多,所以很奇怪,因爲我傳遞的是相同的數據,條件也是相同的。 – Ash 2010-08-02 19:26:11

+0

您是否正在做另一個如果你不是在另一個線程中使用它,你可能永遠不會給UI改變時間嗎? – 2010-08-02 20:25:05

5

我希望有某事。樂於助人......

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    ThreadPool.QueueUserWorkItem(o => 
    { 
     int result = 0; 
     for (int i = 0; i < 9999999; i++) 
     { 
      result++; 
      Dispatcher.BeginInvoke(new Action(() => 
      { 
       this.label1.Content = result; 
      })); 
      Thread.Sleep(1); 
     } 
    }); 
} 
+0

我試圖把它放到一個方法中,並在我的WPF應用程序中調用它,但標籤仍然不會更新。所以我訴諸使用Forms.Application.DoEvents()方法。誰能告訴我爲什麼我的方法失敗的:private void SetStatus(字符串狀態) { ThreadPool.QueueUserWorkItem(O => { Dispatcher.BeginInvoke(新的行動(()=> { lblStatus。內容=狀態; })); }); } – 2017-12-13 16:36:00

3

嗯,這是要健全愚蠢,但你可能只是引用的形式命名空間,然後你可以用這將是你做這個

 using System.Windows.Forms; 

    mylabel = "Start"; 
    Application.doEvents(); 

    myLabel = "update" 
    Application.doEvents(); 

現在的問題是使用WPF,但你仍然可以參考表單並使用這個命名空間。另一個問題是什麼都會直接執行到UI。然而,這是做我可以想到的標籤更新最簡單的方式。我不確定其他原因,爲什麼這將是不好的使用,但它是OP的解決方案。如果你有任何好的理由,那麼不要投票只是通過發表評論告訴我自己和其他人。謝謝。

+0

只有當我這樣做,什麼是正確的方法來做到這一點? – Seabizkit 2017-07-05 11:55:36

0

我希望這有助於:

private delegate void UpdateLabelDelegate(DependencyProperty dp, object value); 

public void UpdateLabelContent(Label label, string newContent) 
{ 
    Dispatcher.Invoke(new UpdateLabelDelegate(label.SetValue), DispatcherPriority.Background, ContentProperty, newContent); 
} 

用法:

while (true) 
{ 
    UpdateLabelContent(this.lblStatus, "Next random number: " + new Random().Next()); 
    Thread.Sleep(1000); 
} 
+0

如果從MainWindow:Window調用,爲什麼不能這樣工作:任何想法,只有在完整方法完成後纔會更新,而不是在執行該行之後更新。 – Seabizkit 2017-07-05 09:08:11