Reputation: 3030
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
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
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
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