Reputation: 2063
if I call form.show()
on a WinForms object from another thread, the form will throw an exception. Is where any way I can add a new, visible form to the main app thread? Otherwise, how can I open the form without stopping my currently executing thread?
Here is my sample code. I am attempting to start a thread and then execute some work within that thread. As the work progresses, I will show the form.
public void Main()
{
new Thread(new ThreadStart(showForm)).Start();
// Rest of main thread goes here...
}
public void showForm()
{
// Do some work here.
myForm form = new myForm();
form.Text = "my text";
form.Show();
// Do some more work here
}
Upvotes: 26
Views: 68067
Reputation: 31
I was about to show message box from constructor. You can replace MessageBox with your windows form.
public Form1()
{
Thread thread = new Thread(new ThreadStart(() => {
MessageBox.Show("Server is connected");
}));
thread.Start();
}
Upvotes: 0
Reputation: 95
After searching the web and not finding a good solution, I came up with my own:
public async Task FunctionWhereIStartForm( Func<Delegate,object>invoke )
{
//this is on another thread
invoke( new MethodInvoker( ( ) =>
{
new formFoo().Show( );
} ) );
}
Then call like this:
await FunctionWhereIStartForm(Invoke);
Upvotes: -3
Reputation: 403
If your use case is to display a GUI while the Main GUI Thread is busy (like loading bar) you can do the following:
private void MethodWithLoadingBar()
{
Thread t1 = new Thread(ShowLoading);
t1.Start();
// Do the Main GUI Work Here
t1.Abort();
}
private void ShowLoading()
{
Thread.Sleep(1000); //Uncomment this if you want to delay the display
//(So Loading Bar only shows if the Method takes longer than 1 Second)
loadingGUI = new LoadingGUI();
loadingGUI.label1.Text = "Try to Connect...";
loadingGUI.ShowDialog();
}
My LoadingGUI is a simple Form with a public Label and a ProgressBar with Style set to Marquee
Upvotes: -1
Reputation: 11
The best way by my experience:
var ac = (ReportPre)Application.OpenForms["ReportPre"];
Thread shower = new Thread(new ThreadStart(() =>
{
if (ac == null)
{
this.Invoke((MethodInvoker)delegate () {
ac = new ReportPre();
ac.Show();
});
}
else
{
this.Invoke((MethodInvoker)delegate
{
pictureBox1.Visible = true;
});
if (ac.InvokeRequired)
{
ac.Invoke(new MethodInvoker(delegate {
ac.Hide();
ac.Show();
}));
}
}
}));
shower.Start();
Upvotes: 1
Reputation: 209
You should call Application.Run()
after you call form.Show()
. For example:
public void showForm()
{
// Do some work here.
myForm form = new myForm();
form.Text = "my text";
form.Show();
Application.Run();
// Do some more work here
}
As for the details behind why, this msdn post may help.
Upvotes: 13
Reputation: 2678
Try using an invoke call:
public static Form globalForm;
void Main()
{
globalForm = new Form();
globalForm.Show();
globalForm.Hide();
// Spawn threads here
}
void ThreadProc()
{
myForm form = new myForm();
globalForm.Invoke((MethodInvoker)delegate() {
form.Text = "my text";
form.Show();
});
}
The "invoke" call tells the form "Please execute this code in your thread rather than mine." You can then make changes to the WinForms UI from within the delegate.
More documentation about Invoke is here: http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
EDIT: You will need to use a WinForms object that already exists in order to call invoke. I've shown here how you can create a global object; otherwise, if you have any other windows objects, those will work as well.
Upvotes: 38