0

When I create a new Windows Form, Visual Studio automatically provides me with two files:

MyForm.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Hardest_Game
{
    public partial class MyForm : Form
    {
        public MyForm()
        {
            InitializeComponent();
        }
    }
}

MyForm.Designer.cs

namespace Hardest_Game
{
    partial class MyForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "MyForm";
        }

        #endregion
    }
}

My first question is, why are we creating two files? Why not just define the methods in one file?

Second question, and the more important one, why are we using System.ComponentModel.Icontainer here, with all the Dispose() methods and such? What do they actually do, msdn.microsoft.com doesn't provide too much information, it simply explains that they're used to contain stuff.

This code seems to work just fine:

using System.Windows.Forms;
using System.Drawing;

namespace Hardest_Game
{
    class MainWindow : Form
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }

        // Controls
        Button myButton { set; get; }

        void InitializeComponent()
        {
            myButton = new Button();
            myButton.Text = "My Button";
            this.Controls.Add(myButton);
        }
    }
}

It looks cleaner, it uses less stuff, etc. Why would I use the method Microsoft wants me to use?

EDIT: Okay sorry guys, my second question might not have been the best one, let me try again: If I were to programmatically create a program (as I do in the third piece of code), including all of its UI etc, would I benefit from using IContainer and Dispose()? That's why I asked what's the purpose of them, to know if I should use them myself, or if they're only for the autogenerated code.

Skamah One
  • 2,456
  • 6
  • 21
  • 31
  • The Designer class is autogenerated. You don't have to touch that file. There's also comments everywhere in that file, like `do not modify the contents of this method with the code editor.`. And I don't think you'd appreciate your unique file to get wiped out each time you make a change to the form. – Pierre-Luc Pineault Apr 28 '15 at 00:08

4 Answers4

3

The class is split into two files (partial classes) so that you can keep auto-generated designer code separate from your own logic. The WinForms designer in Visual Studio will autogenerate code in the designer file, which actually adds and positions all of your controls. (And should not be manually modified because of this)

The container object is used for holding non UI components, such as timers. The dispose method is automatically implemented to clean these resources up when your application/window closes. See What's the purpose of the components IContainer generated by the Winforms designer?

Community
  • 1
  • 1
Cyral
  • 13,999
  • 6
  • 50
  • 90
  • So if I'm not using the designer, but am instead programmatically creating my UI, would my version work just fine? Should I still create a `container` for all my non-UI objects? I've edited my main question! :) – Skamah One Apr 28 '15 at 09:50
  • All these are objects which are automatically generated, and it is not adviseable to change anything created if you have done so with the visual designer. If you are creating the form *completely* programmatically then you don't need a everything. Just create your form, then create your objects (text boxes, buttons, etc) and add them to the form's Controls collection. – Francine DeGrood Taylor Apr 28 '15 at 17:56
  • It sounds like you are trying a third approach, which is to create the form as a separate file the same way the visual designer would have, but doing it yourself. I'm curious; is this what you are trying to do, and if so, why? As a learning exercise? Or is there a functional effect that you want? – Francine DeGrood Taylor Apr 28 '15 at 17:59
2

One of the classes contains code that you write yourself, the other is generated from the visual design of the form. When you are in the designer and you drag a control (say a text box) onto the form, Visual Studio automatically adds the control, as well as a default set of properties.

Separating the two allows you to treat the visual part of the form as separate from the code.

  • Well this only answers the first question, not the second, which was the more important one. I'm wondering if I need the `Dispose()` and `IContainer` for anything, read my edited new question :) – Skamah One Apr 28 '15 at 09:51
0

The two files are to separte automatically generated code from user-typed code, as already explained.

If you're not using the designer, you're not going to need the IContainer. If you were to just simply use a List<IDisposable> instead, and iterate over all the components to Dispose them when your control is being disposed, you are completely fine. Also note that the WinForms designer does not even initialize the container field, unless that is actually required.

The Container used in your designer.cs file is more or less a remarkably convoluted way for your Control to keep track of "components" that aren't controls.

The problem IContainer attempts to solve is that there might be "components" (whatever meaning you choose to assign to that word), which gain additional arbitrary properties that are specific to the surrounding system ("container") which the components are a part of.

For example, a System.Windows.Forms.Timer is a component. It does not have a Name property. However, the specific IContainer implementation called Container makes the arbitrary semantic definition that each component inside of it can have a name(1). So an instance of Container doesn't simply contain a list of IComponent. Instead, think of it as a list of Name_With_Corresponding_IComponent. The name Microsoft chose for that list's element type (as a general concept) is "Site" (ISite). Each IContainer implementation is free to define arbitrary ISite types and use those internally. The ISite type used by Container is called Site, so Container internally has a list of Site instances. Ultimately, this allows the Container to check that the names of its components are valid and unique. Additionally, all components in the container know the container, and can therefore access all other components in the container for whatever reason (this is the only reason why using a plain List<IDisposable> instead of a Container could potentially break something - if you are using a component which relies on its Site property being set so that it can access other components in its container).

If you believe that this Container thing and the functionality it provides to you is useful, you can use it.

Internally, the WinForms designer uses an IContainer implementation that is derived from Container (called DesignerHost). This thing exists during design time in Visual Studio for each UserControl or Form you're designing. Its Site implementation contains a lot more additional information than just the name of the component. Also, unlike the Container instance that is typically allocated in your .designer.cs file (which really only contains non-Control components), the DesignerHost actually contains all the things on the designed object (including Controls). It needs to, because otherwise checking for unique component names isn't very helpful.

So the bottom line is, the WinForms designer used in Visual Studio uses a beefed up implementation of IContainer internally to manage controls and components during design-time. The Container implementation that is used in your designer.cs is just a glorified List<IDisposable> where Dispose is called in a foreach loop.

(1): Funnily enough, the decision to include a Name property in a Site doesn't even come from Container's particular Site implementation. The ISite interface itself defines Name - so all sites have it. The problem here is, Microsoft themselves couldn't come up with any example of an interesting piece of Site information that would be relevant for Container, therefore I cannot give a better example either. Also note that in the designer.cs code, some components will not be added into the container, some will be added but without a name, and some will be added with a name. It is very inconsistent and depends on the implementor of the component to do everything correctly, including providing a suitable constructor.

dialer
  • 4,348
  • 6
  • 33
  • 56
-3

When you get a .Designer.cs file, that's a file that's automatically generated in some fashion. Modifying it (almost almost always) will result in your changes being overwritten when the file is regenerated from its source. In this case, the designer file is being generated and re-generated when you make changes to your UI using the drag and drop tools.

That's the reason there are two files: You have a partial class, giving you one section of the class that you can't and shouldn't modify hidden away in one file, and one that you can and should modify that won't get touched by the designer generators in a different file. When the code gets compiled, the class definitions in the two files are "merged" back together. Without the partial keyword, you wouldn't be able to do that -- classes can't jump across file boundaries.

And that basically answers the second question, as well: Don't worry about what's going on in the Designer.cs files.

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
  • 2
    "Don't worry about what's going on in the Designer.cs files." if that's how you expect people to do programming, not knowing what happens in their program's code... Well, yeah. – Skamah One Apr 28 '15 at 09:52