NomenNescio
NomenNescio

Reputation: 3030

Update controls created in another thread?

I have two threads.

Thread 1: WPF thread. Shows a Window with all the information.
Thread 2: Loops constantly, receiving information & updates the Window in thread 1.

I have the following interfaces.

IModuleWindow
{
    void AddModule(IModule module);
    void RemoveModule(IModule module);
}

IModule
{
    UserControl GetSmallScreen();
    UserControl GetBigScreen();
}

IModuleWindow is implemented by the WPF window in Thread 1
IModule is implemented by an object, is instantiated in Thread 2, and then sent to thread 1.

I want to Add the UserControls in IModule to the Window object in thread 1, and show them. IModule objects get updated constantly in thread 2 and they have to change their text.

Basically the idea is that this program is supposed to show the state of objects in thread 2 , which gets updated constantly.

What is the best way to accomplish this in WPF?

Upvotes: 2

Views: 516

Answers (3)

Dennis
Dennis

Reputation: 37760

It would be nice to be able to use controls created at another thread, thats what I want ideally

The short answer: forget it.

A UI control belongs to a single UI thread only. The best you can do here, is to create controls in main thread, prepare data in background thread, and update controls' properties in main (UI) thread again.

For data preparation I recommend use TPL.

Upvotes: 1

Farhad Jabiyev
Farhad Jabiyev

Reputation: 26635

It helped me lot to understand what i must do.

The scenario must be like that:

ObservableCollection images = new ObservableCollection();
TaskFactory tFactory = new TaskFactory();

tFactory.StartNew(() =>
{
  for (int i = 0; i < 50; i++)
  {
    //GET IMAGE Path FROM SERVER
    System.Windows.Application.Current.Dispatcher
          .BeginInvoke((Action)delegate()
          {
            // UPDATE PROGRESS BAR IN UI
          });

     images.Add(("");
   }    
  }).ContinueWith(t =>
     {
       if (t.IsFaulted)
       {
          // EXCEPTION IF THREAD IS FAULT
          throw t.Exception;
        }
      System.Windows.Application.Current.Dispatcher
       .BeginInvoke((Action)delegate()
       {
          //PROCESS IMAGES AND DISPLAY
       });
    });

You must use System.Windows.Application.Current.Dispatcher.BeginInvoke() for updating UI in WPF.

Upvotes: 1

Tudor
Tudor

Reputation: 62439

IMO the best idea is to use BackgroundWorker, with the very handy ReportProgress method and ProgressChanged event.

The ProgressChanged event is raised on the GUI thread, so you can perform your updates to the GUI directly. Here's how you code should look like:

// initialize the worker
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();


// thread 2 (BackgroundWorker) 
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // main loop
    while(true) 
    {
        // time-consuming work
        // raise the event; use the state object to pass any information you need
        ReportProgress(0, state);
    }
}

// this code will run on the GUI thread
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // get your state back
    object state = e.UserState;
    // update GUI with state
}

Upvotes: 2

Related Questions