none
How to handle names of multiple instances of forms? RRS feed

  • Question

  • Suppose you have a form with a toolbar, and one of the toolbar buttons creates and displays a second form, like this:

    private void toolView_Click(object sender, EventArgs e)
    {
        var form = new RequestsForm();
        form.Show();
    }
    

    The second form is not shown modal on purpose, so that you can open two or more instances of this second form to compare the records side by side. However, every time the user clicks the View button, it creates an instance with the same name.

    Will this create a problem? Is it poor practice? What's a better alternative? I've tested it and it seems to work ok, but I haven't banged on it for hours like actually using it would.

    Tuesday, December 24, 2019 4:51 PM

Answers

  • You're confusing, rightfully so, variables with instances. They are not the same thing. Let's think of it this way. Every time you call `new` on a class (reference type technically) you are getting a new instance (object) in memory. You can do this any # of times during the lifetime of your code and hence can have any # of instances.

    //Create 5 instances
    for (var x = 0; x < 5; ++x)
       new RequestsForm();

    Variables are a compile time feature. They allow you to associate a memory address (determined at runtime) with an identifier you can use to find an instance. That is where the assignment comes in. The variables of your code are fixed at compile time but local variables are stored on the stack so they appear and disappear as your code runs. A variable may or may not be referencing an instance in memory.

    //3 variables, fixed at compilation time
    
    //Not pointing to anything
    RequestsForm form1 = null;
    
    //Pointing to an instance that has just been created
    RequestsForm form2 = new RequestsForm();
    
    //Pointing to the same instance as form2
    RequestsForm form3 = form2;

    Variables are used in your code to work with the instances you've created.

    Back to your original question. Yes, each time you call your method you are getting a local variable on the stack `form`. When the function returns the variable is gone. However each time it is called you are creating an instance of `RequestsForm` in memory and that instance will persist until it is no longer needed.

    The issue is that, since your variable goes out of scope at the end of the function, you won't have access to it anymore. Hence most people promote the variable to a field so it survives the function call. But now you need a separate variable (known at compile time) to store each form instance you create. This is where you'd normally use a List created as a field in the parent form to track the created child forms. You can then store the instances into the list and access them later. 

    In Winforms this is already being done for you so you don't technically need to do it yourself but it might be easier. In Winforms every open form is available via Application.OpenForms. So, in theory, you can access your form(s) later using this property without tracking it in a variable. However you get all the open forms so you'd then need to filter out those that aren't `RequestsForm` which you can do with LINQ. But if you have a lot of forms this is inefficient. Hence you may want to track the open requests form in a list anyway. But you need to make sure that when the form is closed you remove it from your list as well.

    So, the simplest solution.

    //Helper method in your main form
    private IEnumerable<RequestsForm> GetRequestsForms ()
    {
       return Application.OpenForms.OfType<RequestsForm>();
    }
    Note that for MDI forms there are properties on the parent form that has the list of child MDI forms if you are going that route as well.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Robert in SF Tuesday, December 24, 2019 7:22 PM
    Tuesday, December 24, 2019 5:12 PM
    Moderator

All replies

  • Hello,

    If each instance is standalone, meaning you don't need to reference a instance by name (as they will not have a name passed the first instance) then there is no issue under normal circumstances (how much time is the app open with multiple child forms along with resources available on the machine) as when the main form closes those child forms will be disposed. 

    Add var information = Application.OpenForms; and examine the instances in the local window after opening several of the child form and note there is no form name. 


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Tuesday, December 24, 2019 5:10 PM
    Moderator
  • You're confusing, rightfully so, variables with instances. They are not the same thing. Let's think of it this way. Every time you call `new` on a class (reference type technically) you are getting a new instance (object) in memory. You can do this any # of times during the lifetime of your code and hence can have any # of instances.

    //Create 5 instances
    for (var x = 0; x < 5; ++x)
       new RequestsForm();

    Variables are a compile time feature. They allow you to associate a memory address (determined at runtime) with an identifier you can use to find an instance. That is where the assignment comes in. The variables of your code are fixed at compile time but local variables are stored on the stack so they appear and disappear as your code runs. A variable may or may not be referencing an instance in memory.

    //3 variables, fixed at compilation time
    
    //Not pointing to anything
    RequestsForm form1 = null;
    
    //Pointing to an instance that has just been created
    RequestsForm form2 = new RequestsForm();
    
    //Pointing to the same instance as form2
    RequestsForm form3 = form2;

    Variables are used in your code to work with the instances you've created.

    Back to your original question. Yes, each time you call your method you are getting a local variable on the stack `form`. When the function returns the variable is gone. However each time it is called you are creating an instance of `RequestsForm` in memory and that instance will persist until it is no longer needed.

    The issue is that, since your variable goes out of scope at the end of the function, you won't have access to it anymore. Hence most people promote the variable to a field so it survives the function call. But now you need a separate variable (known at compile time) to store each form instance you create. This is where you'd normally use a List created as a field in the parent form to track the created child forms. You can then store the instances into the list and access them later. 

    In Winforms this is already being done for you so you don't technically need to do it yourself but it might be easier. In Winforms every open form is available via Application.OpenForms. So, in theory, you can access your form(s) later using this property without tracking it in a variable. However you get all the open forms so you'd then need to filter out those that aren't `RequestsForm` which you can do with LINQ. But if you have a lot of forms this is inefficient. Hence you may want to track the open requests form in a list anyway. But you need to make sure that when the form is closed you remove it from your list as well.

    So, the simplest solution.

    //Helper method in your main form
    private IEnumerable<RequestsForm> GetRequestsForms ()
    {
       return Application.OpenForms.OfType<RequestsForm>();
    }
    Note that for MDI forms there are properties on the parent form that has the list of child MDI forms if you are going that route as well.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Robert in SF Tuesday, December 24, 2019 7:22 PM
    Tuesday, December 24, 2019 5:12 PM
    Moderator
  • Do you understand scope? In the example you provide the variable form goes out of scope at the end of the method. So although the form exists, the variable with the name form does not. Outside of the method you cannot refer to (use) that variable.


    Sam Hobbs
    SimpleSamples.Info

    Tuesday, December 24, 2019 5:38 PM
  • You're confusing, rightfully so, variables with instances.

    Guilty as charged! :) Thanks for the clear explanation.

    Tuesday, December 24, 2019 7:23 PM