2010-08-02 44 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