0

I'm trying to change Forms using threads. Initially I used Hide() and Show() to hide the previous Form from the next one, the problem is that when I close the application there is always something running in the backgorund. My idea is this: From Form1 clicking a button goes to Form2 which in turn can choose whether to return to Form1 or go to Form3 which in turn can choose whether to return to Form2 or Form1

enter image description here

This is a piece of code from the Form1 button that if clicked must take me to Form2. The point is that it does not close Form1 and in fact it always remains in the background and when I click the button to close Form2 (using Close ()) the program does not close and remains at Form1 and if I close that then the program closes definitively

The second form is called OptionGeneral

Thread StartThread = null;
    public void btnOptions_Click(object sender, EventArgs e)
    {
        StartThread = new Thread(SwitchForm);
        StartThread.Start();
        //Hide();
        OptionGeneral option = new OptionGeneral();
        option.Show();
    }

    public void SwitchForm()
    {
        StartThread.Abort();
    }
Tμrf
  • 404
  • 1
  • 3
  • 14
  • 4
    Why? All GUI things run on the main thread. Try doing this without the thread complications. – LarsTech Feb 11 '21 at 17:09
  • `when I close the application there is always something running in the background` When you had this version, what was running in the background? – LarsTech Feb 11 '21 at 17:12
  • `I'm trying to change Forms using threads`...why? What problem are you trying to solve by doing that? Just show and hide forms the normal way, don't overcomplicate it - unless you have a specific issue that you haven't told us about. But that would be a pretty unusual use case, I think. – ADyson Feb 11 '21 at 17:12
  • 2
    Really feels like you're headed for a problem here. Either these forms are created by one thread, and then you're starting another to handle what they do (which will likely end up needing a lot of invoking to avoid illegal cross thread ops/no point having the second thread if all it's gonna do is tell the first thread to do the work) or you're creating threads that create forms and ending up with a different thread responsible for windowing in each, which could still see illegal cross threading problems. Given that only one form is visible at any one time (seemingly), just use one thread – Caius Jard Feb 11 '21 at 17:22
  • 1
    *when I close the application there is always something running in the backgorund* - I suspect you mean you close Form2 when Form1 is hidden, which isn't actually closing the app at all - it's just closing a visible form, leaving the app running with a hidden form. Either close (not hide) all the forms when the user closes the last visible form, or show the startup form when another form closes, or consider doing an Environment.Exit if a hard quit suits you/you don't have anything you really want to clean up, settings to save etc – Caius Jard Feb 11 '21 at 17:24
  • @CaiusJard I tried to close the Form1 and not hide it, but if I close Form1 the application ends. Is it somehow possible to do this for the Form 2 too? – Tμrf Feb 11 '21 at 17:39
  • 1
    @Tμrf Sure, just [create your own application context](https://stackoverflow.com/questions/15300887/run-two-winform-windows-simultaneously/15301089#15301089) that defines when the application ends. – Servy Feb 11 '21 at 17:43
  • 1
    *I tried to close the Form1 and not hide it* - hide form 1 when you go to form 2. Form2 must have knowledge of form1, so it can show form1 when it hides itself (if the user commands "go to form1"). If form2 closes itself, it can close close form1 also, and the app quits. Same for form3, as it also knows about form1 per your diagram. All in: One thread, hide and show forms, not open and close them, unless you want to quit the app in which case close form1 – Caius Jard Feb 11 '21 at 17:49

4 Answers4

5

Is this a new application or one you are trying to redesign that already runs forms in separate threads...

In general programming in Windows either C++, WinForms or WPF you do the following. Make the interactions you do in the GUI event based. All forms dialogs and GUI elements live in the main thread so data passing is extremely simple and fast.

When real work needs to be done cast the work into a threadpool or task library and when the work is complete marshal the data back to the main ui thred to execute display logic.

In WPF the Dispatcher is your key to pushing data back to the UI. It has been a LONG while since I did webforms.

If your application does not obey these rules you will suffer complicated penatlies. If it is brand new then reboot your development with the strategies I had in mind.

If your application was designed against these rules and you are maintaining it then analyze what kind of work effort it would take to port all the features to a stable architecture and discuss with the people in charge.

Dharman
  • 30,962
  • 25
  • 85
  • 135
cbuteau
  • 736
  • 1
  • 7
  • 15
3

When you are in the form1() form1 is the main window of the system, which is the boot window, you cannot close it and go to form2(), but you can make the main window form2() and you call form1() before the Initialize Component form2()

in Program.cs

  static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form2());
    }

in form2()

public Form2()
        {
            new Form1().ShowDialog();

            InitializeComponent();
        }

now in form1() you can close window

  public Form1()
            {
               
    
                InitializeComponent();
            }



 private void btn_Close_Click(object sender, EventArgs e)
        {
        this.Close();
        }
CodeView
  • 498
  • 3
  • 14
2

Do not work with UI elements directly from other thread otherwise you'll get application freeze. Use some dispatching to do it like discussed in this topic How do I update the GUI from another thread?

Another bad thing - don't use thread.Abort() call otherwise your application will be unpredictable and buggy see https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.abort?view=netframework-4.8

The Thread.Abort method should be used with caution. Particularly when you call it to abort a thread other than the current thread, you do not know what code has executed or failed to execute when the ThreadAbortException is thrown. You also cannot be certain of the state of your application or any application and user state that it's responsible for preserving. For example, calling Thread.Abort may prevent the execution of static constructors or the release of unmanaged resources.

Alexander Egorov
  • 593
  • 10
  • 14
1

To me it seems a case of just hiding and showing the forms as per the comments, and closing Form1 if the other forms close.. Forget the showing/hiding via threading bit; there lies a world of pain (use TPL for long running operations/stay away from multithreading if you can):

class Form1{

  public Form2 Form2 { get; set; }

  Form1(){
    //wire forms up to each other
    var form3 = new Form3() { Form1 = this };
    Form2 = new Form2() { Form1 = this, Form3 = form3 };
    form3.Form2 = Form2;
  }

  void GoToForm2ButtonClick(...){
    this.Hide();
    Form2.Show();
  }
}



class Form2{
  public Form1 Form1 { get; set; }
  public Form3 Form3 { get; set; }

  //event handlers
  void GoToForm1ButtonClick(...){
    this.Hide();
    Form1.Show();
  }
  void GoToForm3ButtonClick(...){
    this.Hide();
    Form3.Show();
  }
  void FormClosing(...){ 
    Form1.Close();
  }
}

//event handlers
class Form3{
  public Form1 Form1 { get; set; }
  public Form2 Form2 { get; set; }

  void GoToForm1ButtonClick(...){
    this.Hide();
    Form1.Show();
  }
  void GoToForm2ButtonClick(...){
    this.Hide();
    Form2.Show();
  }
  void FormClosing(...){
    Form1.Close();
  }
}

And cue usual commentary about making class names meaningful, rather than just a type name followed by a number

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • I tried to use your code, but when I close the Form3, it gives me an error. `System.NullReferenceException: Reference to an object not set to an object instance` `Form1.get returned null.` Maybe because to access Form3 I go to Form2 and lose something of Form1? However, it does not happen in Form2, if I close it, the entire application ends and it works correctly. – Tμrf Feb 11 '21 at 19:20
  • Are you sure you wrote a code like mine, first line of Form1 constructor: `var form3 = new Form3() { Form1 = this };` - it is how Form3 knows about Form1. And also, you should not set Form1 property of form3 instance to null anywhere else, nor should you write `new Form3();` anywhere else .. – Caius Jard Feb 11 '21 at 19:31
  • My mistake, I forgot to fix `void GoToForm3ButtonClick()` using `Form3.Show()` now everything works fine – Tμrf Feb 11 '21 at 20:00