Create element in background thread an then add to main-interface
i have a problem with threading in WPF. I want to have created a complex user interface and then i want to add it to my main-window. While this complex user interface is creating i want to show a progress bar in my main window. I think this only could be made with threads. But there is a problem. The created element can't be added to main window because it is created in a separate thread. Do anybody know if there is a possibility to transfer UIElements that are created in a background-thread to the main-thread. If i try in a simple way it says that the object can't be accessed because it is in a separate thread. I have already made my progress-bar thread safe.
I hope following example explain a bit better what i want to to.
StackPanel tcForm = new StackPanel();
Semaphore loadedSema = new Semaphore(0,1);
Thread thread = new Thread(new ThreadStart(delegate(){
//Formular should be created in background
tcForm.Children.Add(new Formular());
ProgressBar.AddProgr开发者_如何转开发ess();
//...other things
loadedSema.Release();
}));
thread.start();
loadedSema.WaitOne();
new Formular()
runs a very long time, so i thought about creating in background.
It is also impossible to add Formular
to a variable and then add it main thread.
//this is also impossible
//in background-thread
form = new Formular
//in main-thread
tcForm.Children.Add(form);
I hope that there is a way to this. Would be nice if there are some advices,
Thanks, Martin
You should use Dispatcher.Invoke method
...
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(new Formular());
ProgressBar.AddProgress();};)
....
EDIT
You can create Fromular() object before dispatching, if it is working long
var f = new Formular();
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f);
ProgressBar.AddProgress();};)
I don't know much about WPF, but I just learned about the BackGroundWorker which will propably do the work for you.
http://dotnetperls.com/backgroundworker
You just have to handle the WorkerCompleted event which is raised after the task and should run in the main thread. It can also report the progress to update your progress bar.
Example:
void worker_Start()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork +=
new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync("MyArg");
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = new Formular();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Controls.Add((Control)e.Result);
}
If all you want to do is update a progress bar (or similar) then you should create all the UI up front in the main thread and then send status updates from the background thread to the main thread using the form's Invoke method (e.g send an int
to say the progress between 0 and 100%)
I don't think there is a way to share windows forms controls between threads.
EDIT: Ok, I now see that this is tagged WPF. The answer remains the same, but instead of invoking on the control, you use the Dispatcher class (each graphical element holds a reference to the proper dispatcher). You can also use the BackgroundWorker class as suggested in another answer.
No - that is not possible. The WPF is mainly single-threaded.
However, you should wonder why the creation of the interface takes that much time. The WPF is quite fast. "Ordinary" control creation should not be a bottleneck.
Maybe you can optimze other object creations; try profiling your application.
And try building your UI from bottom to top: The last action should be adding your control to your form.
You could XAML serialize your ui-elements and then send them back to the main thread. Not sure if it is faster to unserialize in the main thread than creating them there in the first place though.
精彩评论