C# WinForms – Implications of Handles Between Forms

cobject-orientedwinforms

I was developing a WindowsForm application in C#, with 2 forms. Regardless of what they both did specifically I needed to access values in form2 and send them to form1 and vice versa. For this to happen I found someone talking about constructor overload and it worked for me as I explain in the code.

Form1:

namespace miniDldMngr
{
    public partial class Main : Form
    {
        miniDldMngr.SettingsForm settingsForm; //Instantiate settingsForm

        private void settingsToolStripButton_Click(object sender, EventArgs e)
        {
            settingsForm = new miniDldMngr.SettingsForm(this); //Create handle for Form1
            settingsForm.ShowDialog(); //Form properties were changed to act like a dialog
        }

Form2:

namespace miniDldMngr
{
    public partial class SettingsForm : Form
    {
        private Main HandleToForm1; //local variable to store handle to Form1

        public SettingsForm()
        {
            InitializeComponent();
        }

        public SettingsForm(Main frm1Handle) //overloaded constructor with handle to Form1
        {
            InitializeComponent();
            HandleToForm1 = frm1Handle;
            txtIni.Text = HandleToForm1.comboLoad.Text; //here's how i access controls on form1 for example, as long as modifiers are public
        }

I came across this answer on Stack Overflow and user codesparkle commented:

It's neither scalable nor OOP-like.

Which lead me to believe that it might not have been the best choice to solve my initial issue. (S)He further added:

One approach is to create an event in the class that knows the information which needs to be shown. The form can then register one of its methods as an event handler. Once the information becomes available, the class notifies the Form by calling that handler with an argument containing the displayable information. The beauty of this approach is that the class is decoupled (not dependent on) the implementation of Form. The MVC and MVVM design patterns are other robust ways of doing it.

Now I'm left with some questions:

  1. What are the implications of the procedure I used?
  2. Why isn't it an object-oriented approach?
  3. What would be the best practice to send information back and forth between classes/forms?
  4. How would you go about creating the event mentioned by codesparkle?
  5. I don't know anything about MVC or MVVM design patterns, so some links to a structured explanation would be appreciated.

Please consider that I'm very new to programming and I won't understand you if you talk like I know what I am doing. Code examples work wonders with me, since I can test them.

Best Answer

To answer each of your questions:

What are the implications of the procedure I used?

In this instance, you are passing a reference from a parent object (the Main form) to the child object (the Settings form). The result of this is that the Settings form must know a lot of things about the Main form in order to work properly. Some not-so-desirable implications:

  1. The Settings form must know the names of all the controls in the Main form in order to work properly.
  2. You have to make a lot of things in the Main form public. Making things public isn't a mortal sin by any stretch, however now your Main form is advertising a lot of functionality that it doesn't need to advertise to the outside world. This is more of an issue when your project grows, or if you work with more than one developer, who will be poking around the public members of your objects to figure out how to work with your code from the outside.
  3. Down the road, if for some reason the main form and the settings form were in two different assemblies (DLL files), you might run into trouble because you cannot create circular references.

Why isn't it an object-oriented approach?

Well, what you are doing is object-oriented, however because you have a child object depending on a parent object, you are going against the Dependency Inversion Principle and are thus causing tight coupling between objects.

When people on SO and other sites talk about how "object oriented" something is, they often are referring to S.O.L.I.D., which are five key principles of object oriented design.

What would be the best practice to send information back and forth between classes/forms?

I think in this instance the easiest way to accomplish this would be to create properties in your Settings form that represent the values that are modified within the settings window.

For example, this code would be in your Settings form:

public string UserName
{
   get { return txtUserName.Text; }
   set { txtuserName.Text = value; }
}

And this code would be in your Main Form:

private void settingsToolStripButton_Click(object sender, EventArgs e)
{
    settingsForm = new miniDldMngr.SettingsForm() { UserName = lblUserName.Text };
    settingsForm.ShowDialog(); 
    lblUserName.Text = settingsForm.UserName;
}

It is slightly more code, but now you are free to make as many changes as you want to the main form, and the settingsform won't need to be updated.

There are of course many other approaches you can take, which leads me to your last two questions:

How would you go about creating the event mentioned by codesparkle?

Creating and raising an event is another way to avoid tight coupling between two classes. Notice how the Windows Forms objects, such as ToolStrip are able to call methods in your code (settingsToolStripButton_Click), even though the Windows Forms code is not linked to your code. That is the beauty of events. My opinion is that it is overkill in this situation, since you are showing the form as a Dialog (where you can just read all of the values after the dialog closes), but nonetheless here is an example:

First, you would have code like this in your SettingsForm:

public string UserName
{
   get { return txtUserName.Text; }
   set { txtuserName.Text = value; }
}

public event EventHandler UserNameChanged;
protected void OnUserNameChanged(EventArgs e)
{
   if(UserNameChanged != null)
   {
       UserNameChanged(this, e);
   }
}

private void txtUserName_TextChanged(object sender, EventArgs e)
{
    OnUserNameChanged(EventArgs.Empty);
}

Then, you would have code similar to this in your MainForm:

private void settingsToolStripButton_Click(object sender, EventArgs e)
{
    settingsForm = new miniDldMngr.SettingsForm() { UserName = lblUserName.Text };
    settingsForm.ShowDialog(); 

    lblUserName.UserNameChanged += 
        (sender, args) => lblUserName.Text = settingsForm.UserName;
}

I don't know anything about MVC or MVVM design patterns, so some links to a structured explanation would be appreciated.

The MVVM pattern is a pattern championed by Microsoft, primarily for use in WPF. You can read a nice description here:

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

You can use this pattern in Windows Forms, however I wouldn't recommend it, as WPF has more of the basic plumbing complete in order to actually make it work.

Happy coding!

Related Topic