WPF - Updating Label Content During Processing

Well, I tried several ways to get this to work, the background worker, Dispatcher.Invoke, the threads in the called class, and nothing works. To date, the best solution is an extension method that calls the control. In addition, I tried to avoid passing data for the label through the event classes and simply invoke processing in my code, however this did not matter.

Regarding the background component, I continued to get exceptions, saying that the desktop was busy, so I created the class several times, but the shortcut only changed noticeably after the completion of the whole operation.

I deleted my previous code, here is all that matters, since the problem seems difficult to solve.

Call method

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

Yahoo class

 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)); } 

State classes

 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); } } } 

A Method That Changes Shortcuts Content

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

Updated static method:

  public static class ExtensionMethods { private static Action EmptyDelegate = delegate() { }; public static void Refresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.Render , EmptyDelegate); } 

Another EDITOR: I looked at my code a little longer, I realized that the foreach loop would execute very quickly, an operation that takes time,

 yahooResult = yahoo.ReturnLinkCount(modUri); 

Therefore, I declared a status class (which processes the event and calls the label, etc.) and is undersecret to it. I got the best results, although it still feels random, sometimes I see a couple of shortcut updates, and sometimes one, even if the same URI is passed, so weird.

+6
user-interface c # wpf
source share
5 answers

SOLVING THIS YES WOOHOOOOOOOO 3 days of testing, testing, testing.

I decided to start a new project only using the extension method above and just for the loop to test the functionality of updating the user interface. I started testing various DispatchPrioraties (tested them all).

Oddly enough, I believe that the highest priorities were worse, for example, when using "Send" did not update the label at all, Render updated it twice on average. It was a strange behavior that I experienced when I was looking for different priorities. I opened the help information:

The enumeration value is 4. Operations are processed after completion of all other non-idle operations.

Now it sounded exactly what I did not want, since it is obvious that the label should be updated during processing, so I never tried. I assume that as soon as one of my methods is completed, before it is called, the user interface will be updated. I find some guesses, but it 100% sequentially correctly updates two separate operations.

Thanks to everyone.

+3
source share

I hope there will be. useful ...

  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); } }); } 
+5
source share

Well, that will sound silly, but you can just reference the form namespace, and then you can do it

  using System.Windows.Forms; mylabel = "Start"; Application.doEvents(); myLabel = "update" Application.doEvents(); 

now the problem with this will be to use wpf, but you can still reference the forms and use this namespace. Another problem is that what ever was in que will be executed directly with ui. However, this is the easiest way to do tag updates that I could think of. I am not sure about other reasons why this would be bad to use, but this is a solution for the OP. If you have a good reason, as itโ€™s bad, donโ€™t miss a voice, just let me know and others by posting a comment. Thanks.

+3
source share

would it be simpler / better to add status information as a property on this object and would it only have fire notification of property changes?

so label text (or whatever) can be bound to a property instead of async trying to update the label?

or add this update method if you need to update it?

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

Otherwise, I donโ€™t think we have enough details to help ...

0
source share

Hope this helps:

 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); } 

Using:

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

All Articles