Passing a Form as an argument

I'm trying to duplicate an MsAccess app in C#.  In the Access App I have dozens of forms which have some contols which are common to them all. For Instance, they all have a NewRecordButton.  I want to call a global InsertNewRecord() function when the NewRecordButton is clicked. In MsAccess I pass the name of the form as an argument, but in C# I think I can pass a reference to the form. So in the form I have the code:

 private void NewRecordButtonClick(object sender, EventArgs e)
{
    MyFormClass.InsertNewRecord(this);
}

And in my class which houses my global routines I have this:

public class MyFormClass
{
    Public void InsertRecord(Form TheForm)
    {
        TheForm.NewRecordButton.Enabled=False;
    }
}

This doesn't work. So what am I doing wrong?
TownTalkAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
It doesn't work because the Form object does not contain a definition for NewRecordButton.  So how could you fix this.  Well the ideal solution would be to create a base form and have your forms inherit from this base form.  The base form would contain the definition for the NewRecordButton and could even handle the initial click of this button, you could then have additional functionality expressed within the child form.

Using this as the first example, let's see how this could be accomplished:

BaseForm.cs -
using System;
using System.Windows.Forms;

namespace EE_Q28691014
{
	public partial class BaseForm : Form
	{
		public BaseForm()
		{
			InitializeComponent();
		}

		public virtual void OnNewRecordClick(object sender, EventArgs e)
		{
			btnNewRecord.Enabled = false;
		}
	}
}

Open in new window

BaseForm.Designer.cs -
namespace EE_Q28691014
{
	partial class BaseForm
	{
		/// <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.btnNewRecord = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// btnNewRecord
			// 
			this.btnNewRecord.Location = new System.Drawing.Point(197, 227);
			this.btnNewRecord.Name = "btnNewRecord";
			this.btnNewRecord.Size = new System.Drawing.Size(75, 23);
			this.btnNewRecord.TabIndex = 0;
			this.btnNewRecord.Text = "New Record";
			this.btnNewRecord.UseVisualStyleBackColor = true;
			this.btnNewRecord.Click += new System.EventHandler(this.OnNewRecordClick);
			// 
			// BaseForm
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(284, 262);
			this.Controls.Add(this.btnNewRecord);
			this.Name = "BaseForm";
			this.Text = "BaseForm";
			this.ResumeLayout(false);

		}

		#endregion

		private System.Windows.Forms.Button btnNewRecord;
	}
}

Open in new window

Form1.cs -
using System;
using System.Windows.Forms;

namespace EE_Q28691014
{
	public partial class Form1 : BaseForm
	{
		public Form1()
		{
			InitializeComponent();
		}

		public override void OnNewRecordClick(object sender, EventArgs e)
		{
			base.OnNewRecordClick(sender, e);
			MessageBox.Show("We have disabled the new record button by using the click event in the parent (base).");
		}
	}
}

Open in new window

Form1.Designer.cs -
namespace EE_Q28691014
{
	partial class Form1
	{
		/// <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 = "Form1";
		}

		#endregion
	}
}

Open in new window

Program.cs -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

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

Open in new window

Which then produces the following output -Initial load.  We see the New Record button on Form1 even thought we didn't place it there.Pressing the New Record button disables it and shows the message box.  The message box was called from Form1 and the button was disabled in the base form.I have attached a zip of the project.  Because I had to clean the project in order to upload it, you will need to build it once before you try to look at Form1 in the design view.

-saige-
EE-Q28691014.zip

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
it_saigeDeveloperCommented:
Now I had stated ideally.  Another way you could accomplish this with what you are doing is by searching through the controls on the form in your method and finding the button that matches the criteria (in this case Name).  However, be warned that this method is prone to be easily broken (e.g. - set the wrong name).  This also introduces the concept of extension methods.

Form1.cs -
using System;
using System.Windows.Forms;

namespace EE_Q28691014
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void OnClick(object sender, EventArgs e)
		{
			this.InsertRecord();
			MessageBox.Show("We have disabled the new record button by using an extension method.");
		}
	}
}

Open in new window

Form1.Designer.cs -
namespace EE_Q28691014
{
	partial class Form1
	{
		/// <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.NewRecordButton = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// NewRecordButton
			// 
			this.NewRecordButton.Location = new System.Drawing.Point(197, 227);
			this.NewRecordButton.Name = "NewRecordButton";
			this.NewRecordButton.Size = new System.Drawing.Size(75, 23);
			this.NewRecordButton.TabIndex = 0;
			this.NewRecordButton.Text = "New Record";
			this.NewRecordButton.UseVisualStyleBackColor = true;
			this.NewRecordButton.Click += new System.EventHandler(this.OnClick);
			// 
			// Form1
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(284, 262);
			this.Controls.Add(this.NewRecordButton);
			this.Name = "Form1";
			this.Text = "Form1";
			this.ResumeLayout(false);

		}

		#endregion

		private System.Windows.Forms.Button NewRecordButton;
	}
}

Open in new window

Extensions.cs -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace EE_Q28691014
{
	static class Extensions
	{
		public static void InsertRecord(this Form form)
		{
			foreach (Control control in form.Controls)
			{
				if (control is Button)
				{
					Button btn = control as Button;
					if (btn.Name.Equals("NewRecordButton"))
						btn.Enabled = false;
				}
			}
		}
	}
}

Open in new window

Program.cs -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

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

Open in new window

Produces the following output -Again we have form 1 with a new record button on it.This time however, pressing the button calls an extension method that disables the button before the button click event displays a message.-saige-
TownTalkAuthor Commented:
Thank you so much for the comprehensive replies!

I like the idea of using the base form. But nothing like this exists in vb, so I have to learn some new concepts here....

The first thing I found is that on Form1, the btnNewRecord is in a fixed location presumably because it is inherited from BaseForm. In my MsAccess app although I have dozens of forms each with 11 common buttons, the forms are different sizes/shapes according to the nature of the data in there. So I definitely need to move the buttons around and preferably resize them. Is there a workaround for this?

Edit: I found the answer to this. In the BaseForm I changed the Modifiers property to Protected.
Introduction to R

R is considered the predominant language for data scientist and statisticians. Learn how to use R for your own data science projects.

TownTalkAuthor Commented:
I've got your first example working now thank you.

I'm thinking a bit deeper into this now...... So yes the routines in BaseForm can reference all the common buttons, but what about the text boxes which are different on every form? In my MsAccess application the New Record Button creates a new record and places the Key Field value into a text box of the same name. For example, in the Customers screen the New Record Button causes a new record and customer code to be generated, then writes the new customer code into a text box called CustomerCode. I achieve this by supplying the tablename and keyfield name to the routine which inserts the new record.

I would like to write this code in the BaseForm.OnNewRecordClick and supply it with the relevent parameters. But if I am understanding this correctly, code executing within the BaseForm class will be unable to reference any entity on a form which is inheriting that class even if it knows the name of that entity.

In MS Access I can write: Forms![Form1]![CustomerCode]= "ABC123"

Is that not possible in C#?
TownTalkAuthor Commented:
I think I got it. I put this code in the BaseForm class......

Public Void WriteTextBox(String ControlName, String ControlValue)
{
    this.Controls[ControlName].Text = ControlValue;
}

It even works when called from the chld form.
it_saigeDeveloperCommented:
To provide some clarification to you.  When you instantiate the child class (in this case a form), all of the code in the base class (that the child has not overridden) *is* now a part of the child class.

Consider the following:

BaseForm.cs -
using System;
using System.Windows.Forms;

namespace EE_Q28691014
{
	public partial class BaseForm : Form
	{
		public BaseForm()
		{
			InitializeComponent();
		}

		protected virtual void OnNewRecordClick(object sender, EventArgs e)
		{
			btnNewRecord.Enabled = false;
		}

		protected virtual void WriteTextBox(Control Control, String Value)
		{
			Control.Text = Value;
		}
	}
}

Open in new window

BaseForm.Designer.cs -
namespace EE_Q28691014
{
    partial class BaseForm
    {
        /// <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.btnNewRecord = new System.Windows.Forms.Button();
		   this.SuspendLayout();
		   // 
		   // btnNewRecord
		   // 
		   this.btnNewRecord.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
		   this.btnNewRecord.Location = new System.Drawing.Point(197, 227);
		   this.btnNewRecord.Name = "btnNewRecord";
		   this.btnNewRecord.Size = new System.Drawing.Size(75, 23);
		   this.btnNewRecord.TabIndex = 0;
		   this.btnNewRecord.Text = "New Record";
		   this.btnNewRecord.UseVisualStyleBackColor = true;
		   this.btnNewRecord.Click += new System.EventHandler(this.OnNewRecordClick);
		   // 
		   // BaseForm
		   // 
		   this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
		   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
		   this.ClientSize = new System.Drawing.Size(284, 262);
		   this.Controls.Add(this.btnNewRecord);
		   this.Name = "BaseForm";
		   this.Text = "BaseForm";
		   this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button btnNewRecord;
    }
}

Open in new window

Form1.cs -
using System;
using System.Windows.Forms;

namespace EE_Q28691014
{
	public partial class Form1 : BaseForm
	{
		public Form1()
		{
			InitializeComponent();
		}

		protected override void OnNewRecordClick(object sender, EventArgs e)
		{
			base.OnNewRecordClick(sender, e);
			WriteTextBox(textBox1, "Howdy TownTalk");
			MessageBox.Show("We have disabled the new record button by using the click event in the parent (base).");
		}
	}
}

Open in new window

Form1.Designer.cs -
namespace EE_Q28691014
{
    partial class Form1
    {
        /// <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.textBox1 = new System.Windows.Forms.TextBox();
		   this.SuspendLayout();
		   // 
		   // textBox1
		   // 
		   this.textBox1.Location = new System.Drawing.Point(13, 13);
		   this.textBox1.Name = "textBox1";
		   this.textBox1.Size = new System.Drawing.Size(178, 20);
		   this.textBox1.TabIndex = 1;
		   // 
		   // Form1
		   // 
		   this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
		   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
		   this.ClientSize = new System.Drawing.Size(284, 262);
		   this.Controls.Add(this.textBox1);
		   this.Name = "Form1";
		   this.Text = "Form1";
		   this.Controls.SetChildIndex(this.textBox1, 0);
		   this.ResumeLayout(false);
		   this.PerformLayout();

        }

        #endregion

	   private System.Windows.Forms.TextBox textBox1;
    }
}

Open in new window

Produces the following output -Initial load.After pressing the button, we see the text appear in the textbox and the button is disabled.This shows that the child form is actually calling the method.  Since the child form does know about the textbox control, the method can be used to modify the control.

However, we cannot access textBox1 from the BaseForm because BaseForm knows nothing about textBox1.

For example:
// Specify this in the BaseForm.cs.  Invalid, will produce compiler errors.
protected virtual void WriteTextBox(string Value)
{
	textBox1.Text = Value;
}

Open in new window


-saige-
TownTalkAuthor Commented:
Thanks again for taking the time to do the above. I agree with everything except your final statement.  The base form CAN write a value into a textbox on the child form. simplifying what I did just now.....

The Load event of Form1 has this line:

 private void FormLoad(object sender, EventArgs e)
  {
               //KeyFieldName is declared in BaseClass
               KeyFieldName = "DepartmentID";
  }

And then in the BaseForm....

Public partial class BaseClass : Form
{
     protected string KeyFieldname;

    Public Void InsertRecord()
    {
            this.Controls[KeyFieldName].Text = "Dept007"
    }
}

Form1 contains a field called DepartmentID and the above Base Class code  writes "Dept007" into it.

So i've got this doing everything I need. Thank you so much for your help.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.