dusm
dusm

Reputation: 1257

appendtext on text box only shown in the end all together in wpf

I have a simple textbox in my program. Other features : another input from the user textbox1, and a button. Once the user enters a value in textbox1, and presses the button, I start to check and print messages to the user. My problem is that I don't see those messages on real time, one at a time. The messages appear at once, in the end. I didn't define data binding, because I thought that since it's a simple thing, I wouldn't need it, or am i wrong ? This is a very small portion of my program, it's in the button click event handler.

MainText.AppendText("Starting Refiling...\u2028");
foreach (DocumentData doc in Docs)
{
    try
    {
        wsProxy.RefileDocument(doc);
        MainText.AppendText(String.Format("Refilling doc # {0}.{1}\u2028", doc.DocNum, doc.DocVer));
    }
    catch (Exception exc)
    {
        if (exc.Message.Contains("Document is in use") == true)
            MainText.AppendText(String.Format("There was a problem refilling doc # {0}, it is in use.\u2028",doc.DocNum));
        else
            MainText.AppendText(String.Format("There was a problem refilling doc # {0} : {1}.\u2028", doc.DocNum, exc.Message));
    }
}

Upvotes: 0

Views: 2101

Answers (1)

steveg89
steveg89

Reputation: 1827

You're doing all your looping/printing in the GUI thread. Basically you're giving it new items to show and not giving it time to show them. Create a background worker and let him do the work in the foreach loop that you posted. This should allow the UI thread to update the view as the text changes, instead of getting the one update at the end with all your changes. The link I posted includes examples on how to use the backgroundworker class, but here's what I'd do.

Create a background worker:

private readonly BackgroundWorker worker = new BackgroundWorker();

Initialize him:

public MainWindow()
  {
     InitializeComponent();

     worker.DoWork += worker_DoWork;
  }

Create a task for him:

void worker_DoWork( object sender, DoWorkEventArgs e)
{
   // Set up a string to hold our data so we only need to use the dispatcher in one place
   string toAppend = "";
   foreach (DocumentData doc in Docs)
   {
      toAppend = "";
      try
      {
         wsProxy.RefileDocument(doc);
         toAppend = String.Format("Refilling doc # {0}.{1}\u2028", doc.DocNum, doc.DocVer);  
      }
      catch (Exception exc)
      {
         if (exc.Message.Contains("Document is in use"))
            toAppend = String.Format("There was a problem refilling doc # {0}, it is in use.\u2028",doc.DocNum);
         else
            toAppend = String.Format("There was a problem refilling doc # {0} : {1}.\u2028", doc.DocNum, exc.Message);
      }

      // Update the text from the main thread to avoid exceptions
      Dispatcher.Invoke((Action)delegate
      {
         MainText.AppendText(toAppend);
      });
   }
}

Start him when you get the button press event:

private void Button_Click(object sender, RoutedEventArgs e)
  {
     worker.RunWorkerAsync();
  }

Upvotes: 1

Related Questions