I’m working on a C#/.NET 3.5/Windows Forms program. I would like to create a Modeless Dialog box and then update it with information generated from the main form. I’ve found several examples of the other direction – info from a dialog box updates the main window, but I’m having trouble going in the reverse direction. The GUI in the dialog box just doesn’t function properly. The mouse cursor is an hourglass. I sometimes see updates, but I often see a solid white box, remnants of other windows that were once on top of the dialog box, or it freezes.
Eventually the Dialog box will display more complicated information, but for now I’m just trying to duplicate a counter that appears as a label on the Main Window. To launch the dialog, I do the following:
bool secondWindowOpen = false;
Thread secondWindowThread;
MyPopupWindow secondWindow;
delegate void TextBoxDelegate(string message);
private void buttonPop_Click(object sender, EventArgs e)
{
// If the second window is not open, then open it
if (!secondWindowOpen)
{
secondWindowOpen = true;
secondWindow = new MyPopupWindow();
secondWindowThread = new Thread(secondWindow.MyMethod);
secondWindowThread.Start();
}
else // Close the second window
{
secondWindowOpen = false;
secondWindow.ShouldStop = true;
secondWindowThread.Join();
}
}
I update the counter with the following code:
if (secondWindow != null)
{
secondWindow.CounterText = args.FrameNumber.ToString();
}
The code for controlling the Modeless Dialog box looks like the following. I’ll admit the code for setting the text field is probably wrong, but it’s the best thing I have working at the moment (Invoke calls were giving me trouble).
public partial class MyPopupWindow : Form
{
public MyPopupWindow()
{
InitializeComponent();
}
public bool ShouldStop
{
get { return shouldStop; }
set { shouldStop = value; }
}
private bool shouldStop = false;
public void MyMethod()
{
this.Show();
this.Refresh();
while (!shouldStop)
{
Thread.Sleep(100);
labelCounter.Text = CounterText;
Refresh();
}
this.Close();
}
public string CounterText;
}
My big questions are the following: What is the best way to put a Modeless Dialog Box into a second thread when it just needs to update its own GUI elements? What is the best way to update those GUI elements from the Main Window/Thread? Thanks!
The way forms work is that at the core if the program is a loop that processes messages and passes them out to the forms to be processed. If your form never returns control to your message loop, your program stops working properly. You’ve tried to solve this by adding more threads, but that way leads to pain of its own.
You can’t do this in a thread as all operations applied to your form MUST be done on the UI thread.
You could pass back calls like Invalidate to the UI thread using BeginInvoke, but that gets really messy – it’s much better to write cooperative windows that run on the one UI thread than to fire off lots of threads that then try to prod the UI thread into doing things for them.
To do this you would create the form and then return control to your message handling loop. At a future time you would close the window from an event like a button click. If you need to update the window as result of any events, you would call invalidate in your event handler and then return.