Question

I've spend now over 2 hours trying to resolve this issue and it would be awesome if someone could help me .. :)

Basically, what I try to to is an application which queries a database with LINQ and webservices and retrieves informationen.

From the result I extract few informations and write them to a .CSV file.

Everything works perfectly, except the logging.

Since I dont want that my UI frezzes, I've implemented a background worker:

I hand my logger textbox over to the background worker, that I write the progress from my static webservice methods.

using TextBoxAsAlias = System.Windows.Controls.TextBox;

Here I write for the first time to the logger textbox, which works absolutely perfect.

private void btnExecute_Click_1(object sender, RoutedEventArgs e)
        {
            // Register background worker
            worker.DoWork += worker_DoWork;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;

            // Flush the content of the logger textbox
            txtboxLogger.Clear();
            txtboxLogger.AppendText("#########################" + Environment.NewLine);
            txtboxLogger.AppendText("# Logger - " + DateTime.Now.ToString("T") + "#" + 
        txtboxLogger.AppendText("#########################" + Environment.NewLine + Environment.NewLine);


        worker.RunWorkerAsync(new Object[] {txtboxLogger });

            }

Here is where I get the problem:

As you can see I try again to log some text in the DoWork method. The problem is, that the whole text will just be logged when the worker_DoWork has finished. So as result I wait for 5minutes and nothing happens in the logger textbox and as soon as it finished, everything gets written at once.

void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Object[] parameter = (Object[])e.Argument;
            TextBoxAsAlias textboxLogger = (TextBoxAsAlias)parameter[0];

            textboxLogger.Dispatcher.InvokeAsync((Action)(() =>
            {
                txtboxLogger.AppendText(DateTime.Now.ToString("T") + " - Start processing ... " + Environment.NewLine);

                if (isAutoSelection)
                {
                    // Execute Webservice with auto selection
                    RandomDoWorkMethod(null, context, credential, dateStart, textboxLogger);
                }

                else
                {
                    // Read în the Numbers + hand it over to the webservice for further computing
                    RandomDoWorkMethod(ReadInputFile(), context, credential, dateStart, textboxLogger);
                }

            }));
        }

Does anyone know how I can write immediately during the background Worker to the log file and not just at the end?

I make further use of the following code in my other methods, but the result is still the same, because all of them are in the worker_DoWork thread.

textboxLogger.Dispatcher.InvokeAsync((Action)(() =>
            {
))};

Thanks in advance for your help.

Regards

George

Was it helpful?

Solution

Use SynchronizationContext of your UI thread.

Global variable:

private System.Threading.SynchronizationContext _uiSyncContext;

In constructor:

this._uiSyncContext = System.Threading.SynchronizationContext.Current;

Working with UI elements in worker_DoWork method:

this._uiSyncContext.Post(
  delegate(object state)
  {
    txtboxLogger.AppendText(state as string);
  },
  "Your Text"
);

You can also use Send (Synchronous) method instead of Post (Asynchronous).

OTHER TIPS

Using the dispatcher like that pushes all the work back to the UI, you should only use the dispatcher to refresh the text every now and then, never push RandomDoWorkMethod using the dispatcher.

Also consider using binding (also see notes on BackgroundWorker and ProgressChanged).

This sounds like a standard scenario for using the ProgressChanged event.

A BackgroundWorker thread cannot directly communicate with the UI thread, but it does expose an event that can. Here is how you set this up:

In your "Register background worker" section, add the following lines:

worker.WorkerReportsProgress = true;
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

You need to define the handler somewhere inside your class to look something like this:

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage == 0)
    {
        string message = DateTime.Now.ToString("T") + " - Start processing ... ";
        txtboxLogger.AppendText(message + Environment.NewLine);                 
    }
}

Notice, we're assuming a progress of 0 means we've just started our process. This value needs to be sent inside the DoWork event handler. So your DoWork method will now look like this:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    worker.ReportProgress(0);

    if (isAutoSelection)
    {
        // Execute Webservice with auto selection
        RandomDoWorkMethod(null, context, credential, dateStart, textboxLogger);
    }
    else
    {
        // Read în the Numbers + hand it over to the webservice for further computing
        RandomDoWorkMethod(ReadInputFile(), context, credential, dateStart, textboxLogger);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top