I need to create window with loading gif when my main window is rendering. I have read some articles and make a decision that for this purposes i need to create new thread. I did it like in this article
As a result I have something like that:
LoadingDialog _loadingDlg;
Thread loadingThread;
public void ShowLoading()
{
loadingThread = new Thread(new ThreadStart(loadingThreadWork));
loadingThread.SetApartmentState(ApartmentState.STA);
loadingThread.Start();
}
private void loadingThreadWork()
{
_loadingDlg = new LoadingDialog();
_loadingDlg.Show();
System.Windows.Threading.Dispatcher.Run();
}
public void HideLoading()
{
_loadingDlg.Dispatcher.InvokeShutdown();
}
First time when I call ShowLoading() and then HideLoading() everything works like I want. But when I call ShowLoading() at the second time I get an exception at
_loadingDlg.Show();
with message The calling thread cannot access this object because a different thread owns it.
How can this be? _loadingDlg is created in the previous line, and in the same thread.
In the loadingThreadWork you're creating the control, before the first run it's a null, so in first time you succeed. However, you're creating the dialog in a different thread, which is marked as an owner for the control.
At the next time you're calling the loadingThreadWork, control isn't null, and ant change for it from a different thread (and it is a different thread, because you're creating it again) leads to the exception you've got.
As you're using WPF, you probably should switch from threads to async operations, which are much more readable, supportable and predictable than your current solution.
Related
UPDATE: Just to summarize what my question has boiled down to:
I was hoping that constructing .NET forms and controls did NOT create any window handles -- hoping that process was delayed until Form.Show/Form.ShowDialog
Can anyone confirm or deny whether that is true?
I've got a large WinForms form with tab control, many many controls on the form, that pauses while loading for a couple seconds. I've narrowed it down to the designer generated code in InitializeComponent, rather than any of my logic in the constructor or OnLoad.
I'm well aware that I can't be trying to interact with the UI on any thread other than the main UI thread, but what I'd like to do is to have the application pre-load this form (run the constructor) in the background, so it's ready for display on the UI thread instantly as soon as the user wants to open it. However, when constructing in a background thread, on this line in the designer:
this.cmbComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
I'm getting the error
Current thread must be set to single
thread apartment (STA) mode before OLE
calls can be made. Ensure that your
Main function has STAThreadAttribute
marked on it.
Now this is halfway down the designer file, which gives me hope that in general this strategy will work. But this particular line seems to be trying to instantly kick off some kind of OLE call.
Any ideas?
EDIT:
I think I'm not making myself clear here. The delay seems to take place during the construction of a bazillion controls during the designer-generated code.
My hope was that all this initialization code took place without actually trying to touch any real Win32 window objects since the form hasn't actually been shown yet.
The fact that I can set (for example) Label texts and positions from this background thread gave me hope that this was true. However it may not be true for all properties.
While it is not possible to create a form on one thread, and display it using another thread, it is certainly possible to create a form in a non main GUI thread. The current accepted answer seems to say this is not possible.
Windows Forms enforces the Single Threaded Apartment model. In summary this means that there can only be one Window message loop per thread and vice versa. Also, if for example threadA wants to interact with the message loop of threadB, it must marshal the call through mechanisms such as BeginInvoke.
However, if you create a new thread and provide it with it's own message loop, that thread will happily process events independently until it is told to end the message loop.
So to demonstrate, below is Windows Forms code for creating and displaying a form on a non GUI thread:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ManagedThreadId.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(OpenForm);
Thread t = new Thread(ts);
t.IsBackground=false;
t.Start();
}
private void OpenForm()
{
Form2 f2 = new Form2();
f2.ShowDialog();
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ManagedThreadId.ToString() ;
}
}
The OpenForm method runs in a new thread and creates an instance of Form2.
Form2 is actually given it's own separate message loop by calling ShowDialog(). If you were to call Show() instead, no message loop would be provided and Form2 would close immediately.
Also, if you try accessing Form1 within OpenForm() (such as using 'this') you will receive a runtime error as you are trying to do cross-thread UI access.
The t.IsBackground=false sets the thread as a foreground thread. We need a foreground thread because background threads are killed immediately when the main form is closed without first calling FormClosing or FormClosed events.
Apart from these points, Form2 can now be used just like any other form. You'll notice that Form1 is still happily running as usual with it's own message lopp. This means you can click on the button and create multiple instances of Form2, each with their own separate message loop and thread.
You do need to be careful about cross Form access which is now actually cross-thread. You also need to ensure that you handle closing of the main form to ensure any non main thread forms are closed correctly.
I think your understanding is a little off. Controls must be touched from the thread that created them, not the main UI thread. You could have numerous UI threads in a application, each with its own set of controls. Thus creating a control on a different thread will not allow you to work with it from the main thread without marshalling all of the calls over using Invoke or BeginInvoke.
EDIT
Some references for multiple UI threads:
MSDN on Message Loops
MSDN social discussion
Multiple threads in WPF
The answer is no.
If you create a window handle on any thread other than the GUI thread you can never show it.
Edit: It is completely possible to create Forms and controls and
display them in a thread other than the main GUI thread. Of course if
you do this you can only access the multi threaded GUI from the thread
that created it, but it is possible. – Ashley Henderson
You need to perform any heavy lifting on a bg thread and then load the data into you GUI widget
In general, properties of the form need to be accessed from the same thread running the message loop. That means, in order to construct the form on another thread, you would need to marshal any calls to actually set properties using BeginInvoke. This is true for property sets from the constructor, too, if they end up generating a message that needs to be processed (as is happening to you now).
Even if you get that to work, what does it buy you? It will be a bit slower, not faster, overall.
Perhaps just show a splash screen while this form is loading?
Alternatively, review why your form takes so long to construct in the first place. It's not common for this to take seconds.
I believe it is possible to add the components created on the non-UI thread to the main UI, I've done it.
So there are 2 threads, 'NewCompThread' and 'MainThread'.
You spin off NewCompThread and it creates components for you - all ready to be displayed on the MainUI (created on MainThread).
But ... you WILL get an exception if you try something like this on NewCompThread:
ComponentCreatedOnNewCompTHread.parent = ComponentCreatedOnMainThread;
But you can add this:
if (ComponentCreatedOnMainThread.InvokeRequired) {
ComponentCreatedOnMainThread.Invoke(appropriate delegate...);
} else {
ComponentCreatedOnNewCompTHread.parent = ComponentCreatedOnMainThread;
}
And it will work. I've done it.
The strange thing (to me) is that then the ComponentCreatedOnNewCompTHread 'thinks' it was created on the MainThread.
If you do the following from the NewCompThread:
ComponentCreatedOnNewCompTHread.InvokeRequired
it will return TRUE, and you'll need to create a delegate and use Invoke to get back to the MainThread.
Creating a control in a background thread is possible but only on an STA thread.
I created an extension method in order to use this with the async/await pattern
private async void treeview1_AfterSelect(object sender, TreeViewEventArgs e)
{
var control = await CreateControlAsync(e.Node);
if (e.Node.Equals(treeview1.SelectedNode)
{
panel1.Controls.Clear();
panel1.Controls.Add(control);
}
else
{
control.Dispose();
}
}
private async Control CreateControlAsync(TreeNode node)
{
return await Task.Factory.StartNew(() => CreateControl(node), ApartmentState.STA);
}
private Control CreateControl(TreeNode node)
{
// return some control which takes some time to create
}
This is the extension method. Task does not allow to set the apartment so I use a thread internally.
public static Task<T> StartNew<T>(this TaskFactory t, Func<T> func, ApartmentState state)
{
var tcs = new TaskCompletionSource<T>();
var thread = new Thread(() =>
{
try
{
tcs.SetResult(func());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.IsBackground = true;
thread.SetApartmentState(state);
thread.Start();
return tcs.Task;
}
We have a project that have a couple years development invested into and it now need a progress window because some process are very long. We deal with 3D CAD, advanced engineering, Simulations Third Party DLL, Web services, WCF services.
Now i am trying to add a generic process window you can start in 1 place and end anywhere else. that's not complicated per say. simple static class that open a window on MyClass.Open(string Message) and a MyClass.Close() to hide it once the heavy duty code completed. This works perfectly except the heavy code block the Thread.
The project is a mix of bunch of projects but this part is 99% WPF and i am fairly new to WPF threading as they don't behave like winforms. In winforms thread i create that open other forms are not block by main app heavy work. In WPF the copy pasted code the form is frozen.
I tried Thread and Background Worker without success. then to make sure it wasn't my window the issue or my static class i tried opening the window manually with a Form.Show(); and a Form.Close(); in one of the heavy work function an the form still showed and close properly but yet still frozen. then i removed the Form.Close(); and it started to move right after the work completed. Now i find very strange that the main thread when working at full capacity freeze other threads. I have an actual Exact copy in winform for that progress window except that instead being a Form with label i have a WPF window with a label in a grid.
I tried doing it the right way which is creating a thread for the heavy function but compiler now give me 2,404 errors. I would have at least a week of work just o try if something works and i'd rather not as changing the whole project like so would take at least a year and half and we mostly have 2-3 weeks to complete this so i am looking or any solution that might help finishing that. I can be very dirty. as long as it works.
thank you very much.
Edit :
#Baldrick requested more detail about thread.
I went very simple for thread.
public static class CWaitingMessage
{
private static frmWaiting window = new frmWaiting();
private static Thread t = null;
private static string Message = "";
public static void Open(string sMessage)
{
Message = sMessage;
t = new Thread(new ThreadStart(RunForm));
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
}
private static void RunForm()
{
try
{
window = new frmWaiting();
window.UpdateText(Message);
window.Show();
System.Windows.Threading.Dispatcher.Run();
}
catch
{
window.Close();
}
}
public static void Close()
{
if (t != null)
{
t.Abort("Completed");
}
}
}
If i use System.Windows.Threading.Dispatcher.Run(); instead while (ShowForm) { } the form isn't frozen but my thread disappear by that i mean it never reach f.Close();... ever.
Edit #2 :
Managed to make the abort of the thread using the dispatcher.Run but now i have a bigger issue. the program never stop. the thread start, then i call the abort with a special catch on thread exception and on abort i call a method in the window to save the amount of time it's been opened and close the form. I checked and the file is created so the abort does work but if Dispatche.Run is calle in a thread that is aboded it seems to live on his own. now i have created a monster that never stop running. i close my app completely an visual studio still see it as running.
I am very close to forget about a solution in WPF and go for a winform form to show that message as i know it works perfectly in winforms without that freeze up annoyance.
Edit #3 : Updated my current class i use. I have checked my old exampled and background worker i was only doing a normal form load then running a background worker to loop. the form was in a the same thread as the main code which is completely normal as Background worker are MTA and therefore block UI thread. for UI i need Threads which are STA.
I cannot call dispatcher.Invoke to test it. i couldn't find the assembly for it. my compiler and intellisense don't like it by default :)
The Thread class is not used so much these days as there are now much simpler ways of creating asynchronous methods. For example, please take a look at the Task Class page on MSDN for examples on how to easily create asynchronous methods in WPF.
If you are using .NET 4.5, you can also use the new async and await keywords for even easier asynchronous methods. Please see the await (C# Reference) page on MSDN for a detailed description of this new functionality with code examples.
Having said that, using a BackgroundWorker may actually be your best bet for implementing ProgressBar update functionality with its easy access to update the UI on the UI thread. Please take a look at the BackgroundWorker Class page on MSDN for a full example.
If you need specific help with something, please edit your question in order to add the relevant code.
Found it. after 3 days of work.
For people wondering how to open and close a thread in WPF without freezing he main thread when the new form have animation and no process work.
Code :
public static class CWaitingMessage
{
private static event Action CloseWindow = delegate { };
public static void Open(string sMessage)
{
Thread t = new Thread(delegate()
{
frmWaiting window = new frmWaiting(sMessage);
CloseWindow += () => window.Dispatcher.BeginInvoke(new ThreadStart(() => window.Close()));
window.Closed += (sender2, e2) => Window.Dispatcher.InvokeShutdown();
window.Show();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public static void Close()
{
CloseWindow();
}
}
Note that no error handling and multiple window opening is supported. this is simple the skeleton working and ready to use. I know at least 2 handful of people that will be very interested in this piece of code.
If you required process also on that window background worker works perfectly in the window. This is very useful for mouse over over a grid being filled asynchronously and while you mouse over you can still open secondary window with another DataGrid and heavy work without issue.
I've got my main form Form1 running the main bulk of my program.
I have a separate thread started to perform an algorithm.
When I run the method from the new thread, method MyAlgorithm() I get the error
InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
This is the method that I want to run contained in Form1, the main class in my application.
// Reset the results values
public void ShowResults()
{
while (true)
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
}
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
I'm invoking my thread like this...
// Set the algorithm method up in it's own thread
Thread thread = new Thread(new ThreadStart(MyAlgorithm));
// Run the algorithm
thread.Start();
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
In Windows Forms, you'd either use Control.Invoke/BeginInvoke or use a BackgroundWorker and perform the update in the progress event handler.
In WPF you'd use Dispatcher.Invoke/BeginInvoke.
In C# 5 and .NET 4.5 you'll be able to use async methods which should make a lot of this much simpler...
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
If the "threaded method" is just an instance method of the Form, then you've already got the this reference. If it's not, you'll need to provide that information - ideally as an ISynchronizeInvoke to avoid a direct dependency on Windows Forms if you can express the "update" part separately. (That interface is somewhat deprecated these days, in favour of synchronization contexts, but it still works perfectly well.)
Have a look at Control.Invoke():
public void ShowResults()
{
while (true)
{
Thread.Sleep(1000); // don't spam the UI thread
if (this.InvokeRequired)
{
this.Invoke((Action)UpdateGui);
}
else
{
UpdateGui();
}
}
}
private void UpdateGui()
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
You can use:
myform.Invoke(ShowResults);
There's other options here too:
Alternately use a System.Forms.Timer to call ShowResults periodically. Or another option would be not to use another thread to do the operation; do it in the GUI thread and call Application.DoEvents() from within the operation when you want to let the GUI update.
The first option is nice because it keeps you from accidentally flooding the GUI with Invoke requests, and the second option is nice because it's all on the GUI thread and allows you to have fine-grain control over when things get displayed on the GUI.
I'm writing a plug-in for another application through C#.NET. Some of the processes my plug-in must perform are rather time consuming so I want to take advantage of multiple threads so I can show the user a progress bar of how the current task if progressing rather then the whole thing just hanging.
Typically the UI for something like this would be created in the main thread, and a secondary thread would be created to do the work, such as through the BackGroundWorker class. However, in my case the work must be done in the main thread because the application I'm writing the plug-in for isn't to happy with threads other then the thread it created for the plug-in accessing it.
So instead I'm creating a second thread to create my UI in (a WinForms Form), which then communicates back to the main thread to do any real work.
I'm able to create my Form in the main thread just fine, yet when I try to instantiate my form in the second thread I get an InvalidOperationException. This occurs in the designer file for the form where the name property of a column in a list view is being set.
Here are the details of the exception.
System.InvalidOperationException was caught
Message=ColumnInfo cannot be set.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
at System.Windows.Forms.ColumnHeader.set_Text(String value)
at QA.Revit.RevitQAForm.InitializeComponent() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.Designer.cs:line 758
at QA.Revit.RevitQAForm..ctor() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.cs:line 34
at QA.Revit.RevitQAToolApp.FormMethod() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitModelCheckerCmd.cs:line 99
InnerException:
Update
I seemed to have gotten this working now by changing the ApartmentState of the secondary UI thread to STA. Although I'm totaly new to this multithreading stuff and have no idea what ApartmentState or STA means.
Here's my code.
//property used to store a reference to the form
internal RevitQAForm RevitQAForm { get; set; }
//monitor object that when pulsed shows the form
public static readonly Object showFormLock = new object();
//this method is called by the parent app when it starts
public Autodesk.Revit.UI.Result OnStartup(Autodesk.Revit.UI.UIControlledApplication application)
{
//this creates the form UI Thread
_formThread = new System.Threading.Thread(new System.Threading.ThreadStart(FormMethod));
_formThread.Name = "Form Thread";
_formThread.SetApartmentState(System.Threading.ApartmentState.STA);
_formThread.Start();
//returns that the plug-in startup succeeded
return Autodesk.Revit.UI.Result.Succeeded;
}
//the method is started on the second thread
private void FormMethod()
{
try
{
//creates the form
RevitQAForm = new RevitQAForm();
lock (showFormLock)
{
while (true)
{
//waits for a pulse
System.Threading.Monitor.Wait(showFormLock);
RevitQAForm.ShowDialog();
}
}
}
catch (System.Threading.ThreadAbortException)
{
//disposes the form if the thread is aborted
RevitQAForm.Dispose();
}
}
//this is called when the user request the form be shown
public void ShowForm()
{
lock (showFormLock)
{
System.Threading.Monitor.Pulse(showFormLock);
}
}
//this is called when the program closes
public Autodesk.Revit.UI.Result OnShutdown(Autodesk.Revit.UI.UIControlledApplication application)
{
//aborts the form thread
formThread.Abort();
return Autodesk.Revit.UI.Result.Succeeded;
}
Like I said this seems to work now. I'm able to start the app with my plug-in and show the form repeatedly. The form is also disposed when I close the program.
Yet now I'm trying to figure out how this form can communicate back to the main thread. The form will need to be able to trigger the main thread to start processing, the main thread will then need to be able to periodically report it's progress back to the form thread. At any point the form thread should be able to tell the main thread to cancel processing. Finally the main thread will need to notify the form when the processing is complete.
Any one have any tips on how I could do this?
This won't work. All forms need to use the underlying message pump in Windows, and to do that they need to be on the original thread.
To trigger the processing in main thread, you can use any WaitHandle derived class such as say ManualResetEvent/AutoResetEvent - essentially, Main thread will wait on to the wait handle and form thread can signal the event to start processing.
For communicating progress back from main thread to your UI/Form thread, you can use events or delegates. The simplest way would be to declare the process update delegate, instantiate it with some form's method. Then main thread can invoke it - which will essentially run the method within your form class (on main thread). Within this method, you must need to marshall call to your form's thread using Invoke method the form.
Try to call method, which uses
System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
by using method Invoke.
i am working with a winforms control that is both a GUI element and also does some internal processing that has not been exposed to the developer. When this component is instantiated it may take between 5 and 15 seconds to become ready so what i want to do is put it on another thread and when its done bring it back to the gui thread and place it on my form. The problem is that this will (and has) cause a cross thread exception.
Normally when i work with worker threads its just with simple data objects i can push back when processing is complete and then use with controls already on the main thread but ive never needed to move an entire control in this fashion.
Does anyone know if this is possible and if so how? If not how does one deal with a problem like this where there is the potential to lock the main gui?
You don't need to lock the GUI, you just need to call invoke:
Controls in Windows Forms are bound to
a specific thread and are not thread
safe. Therefore, if you are calling a
control's method from a different
thread, you must use one of the
control's invoke methods to marshal
the call to the proper thread. This
property can be used to determine if
you must call an invoke method, which
can be useful if you do not know what
thread owns a control. ref
Here is how it looks in code:
public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);
Normally calling the LoadComponent from another thread will cause a cross-thread exception, but with the above implementation the method will be invoked on the GUI thread.
InvokeRequired tells you if:
the caller must call an invoke method
when making method calls to the
control because the caller is on a
different thread than the one the
control was created on.
ref
Update:
So if I understand you correctly the control object is created on a thread other than the GUI thread, therefore even if you were able to pass it to the GUI thread you still won't be able to use it without causing a cross-thread exception. The solution would be to create the object on the GUI thread, but initialize it on a separate thread:
public partial class MyForm : Form
{
public delegate void ComponentReadyDelegate(YourComponent component);
private YourComponent _component;
public MyForm()
{
InitializeComponent();
// The componet is created on the same thread as the GUI
_component = new YourComponent();
ThreadPool.QueueUserWorkItem(o =>
{
// The initialization takes 5-10 seconds
// so just initialize the component in separate thread
_component.Initialize();
LoadComponent(_component);
});
}
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
}
Without knowing too much about the object. To avoid cross thread exceptions, you can make the initial thread invoke a call (Even if you are calling from a thread).
Copied and pasted from one of my own applications :
private delegate void UpdateStatusBoxDel(string status);
private void UpdateStatusBox(string status)
{
listBoxStats.Items.Add(status);
listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
labelSuccessful.Text = SuccessfulSubmits.ToString();
labelFailed.Text = FailedSubmits.ToString();
}
private void UpdateStatusBoxAsync(string status)
{
if(!areWeStopping)
this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
}
So essentially the threaded task will call the "Async" method. Which will then tell the main form to begininvoke (Actually async itself).
I believe there is probably a shorter way to do all of this, without the need for creating delegates and two different methods. But this way is just ingrained into me. And it's what the Microsoft books teach to you do :p
The BackgroundWorker class is designed for exactly this situation. It will manage the thread for you, and let you start the thread, as well as cancel the thread. The thread can send events back to the GUI thread for status updates, or completion. The event handlers for these status and completion events are in the main GUI thread, and can update your WinForm controls. And the WinForm doesn't get locked. It's everything you need. (And works equally well in WPF and Silverlight, too.)
The control must be created and modified from the UI thread, there's no way around that.
In order to keep the UI responsive while doing long-running initialization, keep the process on a background thread and invoke any control access. The UI should remain responsive, but if it doesn't, you can add some wait time to the background thread. This is an example, using .Net 4 parallel tools: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html
If interaction with the specific control being initialized can't be allowed until initialization finishes, then hide or disable it until complete.