Yahya Hussein
Yahya Hussein

Reputation: 9121

updating wpf UI while running process

I have a custom WPF control that I want to show when a button is clicked and hide when processing is finished, I am trying this but the control is not visible until the processing is done.

public delegate void UpdateTextCallback(string message);

private void UpdateText(string message)
{
    if (message == "v")
        crclLoading.Visibility = Visibility.Visible;
    else
        crclLoading.Visibility = Visibility.Hidden;
}

private void TestThread()
{
    crclLoading.Dispatcher.Invoke(
        new UpdateTextCallback(this.UpdateText),
        new object[] {"v" }
    );
}

private void TestThread2()
{
    crclLoading.Dispatcher.Invoke(
        new UpdateTextCallback(this.UpdateText),
        new object[] { "s" }
    );
}

and in butoon_click:

Thread show= new Thread(new ThreadStart(TestThread));
show.Start();
//long time conusming processing
Thread hide= new Thread(new ThreadStart(TestThread2));
hide.Start();

Upvotes: 1

Views: 4104

Answers (2)

Bhushan Shimpi
Bhushan Shimpi

Reputation: 90

In WPF, only the thread that created a DispatcherObject may access that object. For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the event queue of the Dispatcher at the specified DispatcherPriority. Invoke is a synchronous operation; therefore, control will not return to the calling object until after the callback returns.

use Dispatcher.Invoke(new Action(() => MethodName));

Upvotes: 2

mm8
mm8

Reputation: 169390

All you do on your background threads is to call Dispatcher.Invoke and this executes the specified delegate synchronously on the UI thread.

Also, you start second thread right after you have started the first one and your code doesn't make much sense at all.

You need to actually perform some potentially long-running operation on the background thread.

By the way, the recommended way to execute something on a background thread is to start a new Task nowadays. Try this:

crclLoading.Visibility = Visibility.Visible;
Task.Factory.StartNew(()=> 
{
    //do something that might take a while here....
    System.Threading.Thread.Sleep(5000);
}).ContinueWith(task => 
{
//and then set the Visibility to Hidden once the task has finished
crclLoading.Visibility = Visibility.Hidden;
}, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

Upvotes: 2

Related Questions