1

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.

6
  • why would this q be here but not rather SO?
    – nawfal
    Dec 28, 2011 at 10:28
  • @nawfal I thought it could take a turn to an existential debate which wouldn't be apropriate for SO. And i want to discuss a few questions and SO is oriented for quick questions for quick answers. Thats how i chose to come here. Dec 28, 2011 at 11:06
  • I thought it could take a turn to an existential debate which wouldn't be apropriate for SO Also not appropriate for Programmers :) But the question looks fine to me, I really don't see it turning any kind of ugly.
    – yannis
    Dec 28, 2011 at 11:36
  • 1
    I removed the First of all I would like you all to know I am an absolute beginner so I might say some things that make no sense, but that's why I am asking, please bare with me. sentence from your question. You don't have to ask people to be nice, they have to be. If you get an non-constructive comment, flag it. We are all beginners in some way or another.
    – yannis
    Dec 28, 2011 at 11:44
  • Just for clarification, if it took a turn into a debate where would it be apropriate? The way i see it, if someone said this is the proper way and now someone says it isn't, it will become an opinion-based response and will turn into a debate. Unless who told me it was the right way was wrong. Either way I want to learn the reasons of each side to do one thing or the other. Please let me know what to do if this question is out of place. Dec 28, 2011 at 11:45

2 Answers 2

0

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!

2
  • Wow, I just got home and read through your answer. It's a great read and spelled out simple enough for me to understand it. I just need to wrap my head around some concepts (Dependency Inversion Principle), read through the posted links and test out the code to figure out if I really understood it. Thanks! Dec 29, 2011 at 2:31
  • First right answer in 2012, at least in Portugal time (GMT+1) ;D Jan 1, 2012 at 0:05
1

I think that others are concerned about tight coupling.

For instance, what will txtIni.Text display when Form2 has been instantiated with the default constructor?

In my opinion, you should resolve this value in its own property with a backing store, so that the alternate constructor, which Form1 would call, could set this property.

1
  • 1
    1- txtIni would display nothing if Form2 was instantiated with the default(clean) constructor, so i dont use that constructor, just the overloaded one. The intention is for txtIni to have the same value as comboLoad in Form1. Are you suggesting a property for this value that sets itself on form2? 2- So you're saying that my overloaded constructor should pass properties and not the form handle? How should I set the property for that to work across the forms classes? And how would I access the main form from form2, properties, controls and methods. Dec 28, 2011 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.