2

Because this is turning out to be quite a large project and I often need to access objects in other forms from a class I firstly create a static variable in my program.cs class of type 'MainForm'which is a Windows Form.

From my DataManger.cs Class, I instantiate the object 'Program.MainFormObj = new MainForm()' and then call the Show method in order to display my Form. It looked like the the Paint event for the form doesn't get to finish but it does kick off as some controls are drawn. Presumably because the main thread (this is all running on one the main thread) is 'occupied' by the next statement. I figured, regardless of known problems I'd use Application.DoEvents() to temporarily counter this issue. As I imagined, it worked, but only to a certain extent. If I put a blocking method like MessageBox.Show(), I can view my completely flawless form in the background but as soon as I press 'OK' and the code proceeds the entire application exits.

I'm really stuck. Despite some extensive searching both here and using Google I can't find an apporpiate answer. I did this this thread: Form.Show() is not showing it's child controls but the given solution isn't appropriate for my solution. Any help is appreciated very much, thanks.

Community
  • 1
  • 1
Caster Troy
  • 2,758
  • 2
  • 20
  • 44
  • 1
    You are violating at least two "never do this!" rules of Winforms programming. What else you might be doing can only be guessed at. This is not an answerable question in its present form, visit your local bookstore or library to find decent books on proper Winforms programming techniques. – Hans Passant Jul 04 '12 at 00:14

1 Answers1

2

If this is a large project, invest time now to refactor it.

  • Consider an MVC pattern. You can do what with WinForms, not just newer UI technologies.
  • If you do not opt for WinForms, at least separate UI and data (Data Binding is your friend).
  • Build reusable components when different forms share common functionality.

Fighting the way WinForms works will be much more expensive in the mid-term than investing time now to do things right.

If you have any choice about the technology, consider WPF instead. There is a learning curve with WPF, but it may well be worth investing in that learning now.

UPDATE

Based on your code sample, I see that you are probably creating some of your forms on a thread other than the main UI thread. While that is allowed, it creates for very confusing code because forms can only be updated from the thread they were created on.

The simplest hack to get this working is probably to update HandleIncomingData to also invoke the Show() calls on the main UI thread.

There is supposed to be a way to cleanly do that from a static method, outlined here:

https://stackoverflow.com/a/505361/141172

However, when I tried that, I found that SynchronizationContext was always null. I'm sure I'm just missing a step.

I was able to get things working by misusing the LoginForm (assuming, perhaps incorrectly, that the form is always available. If not, perhaps create a special form just for thread marshaling).

The hack looks like this:

Program.MainForm = new MainForm();
try
{

    MessageBox.Show("Login Success.", "Login", MessageBoxButtons.OK, MessageBoxIcon.Information);

            // Abusing LoginForm's Invoke method.  Code assumes LoginForm is always available.
    Program.LoginForm.Invoke((MethodInvoker)delegate
    {
        Program.MainForm.Show();
    });


}
catch (Exception Ex)
{
    MessageBox.Show(Ex.ToString()); //Debuging purposes
}

By the way, there's an excellent extension method that makes it a breeze to invoke UI code from a non-UI thread:

https://stackoverflow.com/a/3588137/141172

Community
  • 1
  • 1
Eric J.
  • 139,555
  • 58
  • 313
  • 529
  • Thanks for the reply. Unfortunately for this project, I don't have any other choice but to use WinForms due to time constraints. I'm definable going to research MVC pattern's and WPF this Summer, I agree it's far more beneficial in the long term. Do you know any methods to resolve this issue that I can implement in to the current structure of the solution? – Caster Troy Jul 04 '12 at 00:24
  • There's not enough information to be sure what the problem is. Can you create a small test case that demonstrates the issue and post that code, or at least the relevant parts? – Eric J. Jul 04 '12 at 00:25
  • Thx a bunch, worked great. I actually tried such a solution but rather than calling the Invoke method on LoginForm I called it on MainForm which threw an exception because it hadn't been created yet. It's my understanding that when you call the Invoke method it performs the operations in the lambda expressions block on that thread so there are no illegal cross thread operations. I suppose that's wrong if it's possible to call that Invoke method from the LoginForm. If you can help me understand anymore I'd appreciate that. Is there any way I can give you some form of reputation here on SO? – Caster Troy Jul 04 '12 at 02:37
  • You must fully create and show the form before you can call Invoke on it, correct. Calling Invoke (or BeginInvoke) marshals the call onto the UI thread. If you want to give some reputation, the appropriate way to do that is to accept this answer :-) (hit the checkmark so that it turns green) – Eric J. Jul 04 '12 at 04:43