Multiple exactly the same forms - c#

I have multiple forms who look exactly the same (invoice, priceoffer, order,...) Now I created the first form. But after thinking about this, all the other forms will look exactly the same.
Is there a technique, or some other way that prevents me of creating all the forms over and over again?

Just create a single form class that you'd call OrderForm or something like that
public class OrderForm : Form {
}
Then use this to create all your controls on it, and create an instance of this class every time you need to show it to a user. Best part of this is if one of your forms changes (let's say invoice) you could just inherit from your class and only change the part that is different:
public class InvoiceForm : OrderForm {
}
And then just create an instance of InvoiceForm when you need that.
EDIT answering OPs question in the comment.
Let's say you create a bunch of controls in the constructor of OrderForm :
public class OrderForm : Form {
public OrderForm {
var button = new Button() { ... };
var label = new Label () { ... };
this.Controls.Add(button);
this.Controls.Add(label);
}
}
Now if you'd create an instance of OrderForm, these controls would be added to the form, no matter how many instances you'd create of these:
//each of these instances have the same controls
var form1 = new OrderForm();
var form2 = new OrderForm();
var form3 = new OrderForm();
Now if you'd define a subclass of OrderForm namely InvoiceForm, you'd be able to use the same form controls as OrderForm, with some changes to it:
public class InvoiceForm : OrderForm {
public InvoiceForm() : base(){ // : base() executes the constructor of the superclass
//all controls in the `OrderForm` class are added because we called base().
var invoiceControl = new Label() { ... };
this.Controls.Add(invoiceControl);
//now in total your form will count 4 controls
}
}
Now you can just create an instance of InvoiceControl to get the changed form.
//first 2 forms have 3 controls, last 2 forms have 4 controls.
var form1 = new OrderForm();
var form2 = new OrderForm();
var form3 = new InvoiceForm();
var form4 = new InvoiceForm();

Create a UserControl, and use it in multiple forms.

A good place to start with Visual inheritance.
https://msdn.microsoft.com/en-us/library/bx1155fz(v=vs.110).aspx
But as GuidoG say above you could have some strange behavior in Visual Studio and in the designer.
You could handle the different save button behavior by making the click handler calling an other overridable Sub and then override this Sub in the inherited Form (instead of coding your saving process directly in the event handler as most people do:-)).
Exemple
public class BaseForm
{
private void SaveButton_Click(System.Object sender, System.EventArgs e)
{
OnSaveButtonClick();
}
protected virtual void OnSaveButtonClick()
{
//Saving process for base form
}
}
public class InheritedForm : BaseForm
{
protected override void OnSaveButtonClick()
{
//Saving process for inherited form
}
}
Keep in mind that further modification in the "base" form would also apply to the inherited one without a word. This could be an issue if you are not well organized. Sometimes it's better to do a good old copy/paste.

Related

Using other classes to modify panel within Windows Forms

The program i am trying to make involves one main form, which should be able to switch between 5 different menus. Programming all the functionality within the Form.cs file would make this an extremely long class, so what i want to do is call the Panel from another class to add control elements and load all the data from a MySQL database, depending on the menu chosen.
More specifically I have my ParentInterface.cs, where I want to show a ChoreUI within a dynamic Panel which will be modified in a new class called ChoreUI.cs.
I have tried making ChoreUI inherit from the ParentInterface, as well as making it the target. Though my lack of knowledge of Windows Forms is in the way.
ParentInterface.cs
namespace ChoreApplication.UI{
public partial class ParentInterface : Form
{
private ChoreUI ChoreUI;
private ParentInterface PUI;
public ParentInterface()
{
ChoreUI = new ChoreUI(PUI);
InitializeComponent();
}
private void ChoreNavButton_Click(object sender, EventArgs e)
{
var ChoreUI = new ChoreUI(PUI);
ChoreUI.DillerDaller();
}
}
ChoreUI.cs
namespace ChoreApplication.UI
{
class ChoreUI
{
public ParentInterface PUI;
public ChoreUI(ParentInterface PUI)
{
this.PUI = PUI;
}
public void DillerDaller()
{
PUI.dynamicPanel.Controls.Add(new Label { Location = new Point(10, 10), Name="textName", Text = "hello"});
}
}
I want to be able to add new control elements to the Panel, from the ChoreUI class instead of in the ParentInterface class. But as of now I am not succeeding in doing so.
What you have at the moment is not that bad, your child component has a reference to the parent and that's ok.
This, however, is the issue
public void DillerDaller()
{
PUI.dynamicPanel.Controls.Add(new Label { Location = new Point(10, 10), Name="textName", Text = "hello"});
}
At the basic level, you violate the encapsulation principle, where the dynamicPanel is protected inside the form so that it's not accessible from outside. Inheriting the child component from the main form is not the right solution.
At somewhat higher level, you violate here the so called Law of Demeter where the inner implementation details of a component should not be that misused. Changing the dynamicPanel visibility to public will not help. Rather, the rule says you should wrap such implementation details with a stable interface
public partial class ParentInterface : Form
{
...
public void AddDynamicPanelControl( Control control ) {
this.dynamicPanel.Controls.Add( control );
}
public void RemoveDynamicPanelControl( Control control ) {
this.dynamicPanel.Controls.Remove( control );
}
}
and use the newly introduced interface
public void DillerDaller()
{
var label = new Label { Location = new Point(10, 10), Name="textName", Text = "hello"};
this.PUI.AddDynamicPanelControl( label );
// if you store the reference to the label somewhere,
// you'll be able to call `Remove....` to remove this control from
// the form
}

Use information from objects in a child form from a main form in C#

I have a C# form called Form1.cs. By pressing a button, a new Form called Form2.cs comes up and I do something in form2. I have some variables in both forms.
I want to communicate between these two forms like this.
in form1:
string s=frm2.textbox1.text;`
form2:
if(frm1.checkbox1.checked==true)
or something like these codes.
I have tried the below code:
form1:
Form2 f=new Form2(this);
f.showDialog();`
form2:
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
`
and this works. But I don't want to use pointers like "this" and call this.mainform. Is there another way to communicate between forms like function calls?
Thank you.
Here are a couple of different approaches you can take that remove the need for Form 2 to know about Form 1 and that will make Form 2 reusable:
Delegates
You can declare a delegate function on the second form, and then pass a delegate method from the first form to the second one, so the second form can call back to the first one.
That approach means your second form no longer has any direct knowledge of your first form. It also means you can reuse the second form from any form and just pass in a delegate with the correct signature. Example below:
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f=new Form2(UpdateTextBox);
f.ShowDialog();
}
private void UpdateTextBox(string newText)
{
label1.Text = newText;
}
}
Form 2:
public partial class Form2 : Form
{
public delegate void ChoiceMadeOnForm2Delegate(string choice);
private ChoiceMadeOnForm2Delegate _choiceDelegate;
public Form2(ChoiceMadeOnForm2Delegate choiceDelegate)
{
InitializeComponent();
_choiceDelegate = choiceDelegate;
}
private void saveButton_Click(object sender, EventArgs e)
{
_choiceDelegate(textBox1.Text);
Close();
}
}
In this example the delegate method just has one parameter, but if you want to pass back a series of values to Form 1 your delegate method declaration could include more parameters, or the parameter could be a class instead.
If you also want to set initial values for Form2 from Form 1 you can of course add those as constructor parameters for Form 2 and pass them in when you new up Form 2.
In your example Form 2 is shown as a dialog, but if you ever want to not show Form 2 modally you could even have a delegate on Form 1 that you pass to Form 2, so the forms can then communicate in two directions.
Use data binding and a shared class
Another approach is to use databinding, whereby you bind both forms to the same object and pass that object from Form 1 to Form 2 in its constructor when you open Form 2. When either form then changes the object those changes will then be reflected on both forms simultaneously and instantly.
To do that you need to read up on a concept called databinding and implement the INotifyPropertyChanged interface on the data class. You then bind the relevant controls on both forms to that class. Documentation on INotifyPropertyChanged can be found here
You can pass only information that Form2 needs and expose only information that Form1 needs
Form1
string valueOfForm2 = null;
using Form2 f = new Form2(this.checkbox1.Checked)
{
f.ShowDialog();
valueOfForm2 = f.ReturnValue;
}
Then use valueOfForm2 for you needs in the Form1
Form2
bool _IsForm1ValueChecked;
//By this property text will be exposed to outside of Form
public string ReturnValue { get { return this.textbox1.Text;} }
public Form2(bool isForm1ValueChecked)
{
_IsForm1ValueChecked = isForm1ValueChecked;
}
_IsForm1ValueChecked will be set in the contructor - then use it for your purpose in the Form2
I think for such stuff, I was using properties.
I prefer not access from one form the controls of the other one.
If I need information from one form, I prefer giving the access to this other form through properties.
More than that, you can define an interface that will contain all the properties/methods that you need for the communication between the forms. It will be clearer to work with an interface, you will get the information you need and won't be overloaded with other irrelevant information.
For example:
Interface IForm2
{
// your properties
string PersonName {get;} // Just an example
// your methods
}
class Form1: Form
{
private IForm2 _form2;
void Foo()
{
var pname = _form2.PersonName; // Just an example
}
}
class Form2: Form, IForm2
{
string PersonName
{
get
{
return personNameTextBox.Text;
}
}
}

How can I make my Form Control variables acessible to classes other than my Form class?

For example after creating a new Windows Form project I have my class called Form1.cs and from that form I can simply start typing the name of a form control and it will auto populate the form control variable names and I am able to use them in the class. However I have other classes that need to be able to access these form control variables as well, but they are not accessible.
Make them public if they are going to be used in another assembly, or internal if they are going to be used in the same project. Making them static means you don't have to pass your Form1 into the other classes.
Example... Say your Form1 has a string that contains the text you display in the title bar. Making it internal static, like this:
internal static readonly string MsgBox_Title = " Best Application Evar!";
lets you access it from other classes like this:
Form1.MsgBox_Title
It doesn't have to be readonly; that's just an example I pulled from an old app...
If you don't want static variables, you'll have to pass in an instance of Form1.
public class SomeClass
{
private Form1 m_Form1;
public SomeClass(Form1 form1)
{
m_Form1 = form1;
}
private void someMethod()
{
string localValue = m_Form1.SomeMemberStringVariable;
}
}
It's a very contrived example, but hopefully you get the idea.
If you want to call the Refresh method from a class instantiated from Form1, you could use an event in the child class to notify Form1.
Example:
This Form1 has a button that I use to show a secondary form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnShowPopup_Click(object sender, EventArgs e)
{
PopupForm f = new PopupForm();
f.CallRefreshHandler += PopupForm_CallRefreshHandler;
f.ShowDialog();
}
private void PopupForm_CallRefreshHandler(object sender, EventArgs e)
{
Refresh();
}
}
The secondary form, "PopupForm", has a button that I use to raise an event that the Form1 is subscribed to, and lets Form1 know to call Refresh.
public partial class PopupForm : Form
{
public event EventHandler CallRefreshHandler;
public PopupForm()
{
InitializeComponent();
}
private void btnRaiseEvent_Click(object sender, EventArgs e)
{
EventHandler handler = CallRefreshHandler;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Hope this helps.
Create an object of that class & start using those variables like this
Form1 fm = new Form1();
string abc = fm.VAR;
Define a public property in your form.
public string MyProp { get; set; }
Form1 frm = new Form1();
frm.MyProp = "Value";
Or define the property as static to avoid having to instantiate Form1:
public static string MyProp { get; set; }
Form1.MyProp = "Value";
I ran into this issue recently. I was keeping some methods in a separate class. Maybe not a good design decision in my case, I'm not sure yet. And these methods sometimes needed to communicate with controls in the main Form1. For example, to write to textBox1.
Turns out easy enough. Just write your method signature to include a TextBox instance. For example you pass textBox1 in and inside the method you refer to it as tb. Then when you call that method (even though it is in another class) you set the tb.Text property to whatever you like and it will show on textBox1.
This makes sense when you consider that control is just a special kind of object, graphically represented in the Form. When you pass it as an argument to a method in another class or the same class, you are actually passing the reference. So writing text to it in the method call will write text to the original control.

In a Windows Forms (.Net 4) application, how can I define a base form style for all forms?

For example, I'd like all of my forms to have the same Icon and StartPosition. However I also need to be able to define things in each form how you normally would, dragging and dropping controls, etc.
Is this possible?
Create a form and set the Icon and StartPosition properties the way you want them. Compile. This will be your base form. Now use Project + Add New Item, Windows Forms node and pick the Inherited Form item template. The IDE will prompt you to select the base form.
Antoher way to go, is to make an extension method where you set all the parameters:
public static class FormExtentsions
{
public static void SetDefault(this Form form)
{
form.Icon = new Icon("path");
form.StartPosition = FormStartPosition.CenterScreen;
}
}
The use it like this:
public partial class Form1 : Form
{
public Form1()
{
// Put it here if you want to be able to override everything
this.SetDefault();
InitializeComponent();
// Put it here if you want the defualt to override "local" settings
this.SetDefault();
}
}
Simply create your own base Form class:
class FormBase : Form
{
public FormBase()
{
Icon = SomeIcon;
StartPosition = StartPosition.Whatever;
}
}
You could have a static Icon and Position, initialize it with a static constructor, and then make a constructor where you initialize the instance's Icon and Position properties with the static Icon and position:
Fx.
class Foo : Form {
static Bitmap sIcon { get; private set; }
static Point sPosition { get; private set; }
static Foo() {
sIcon = /* Load from external source */
sPosition = new Point( x, y ); //Insert x and y
}
public Foo()
: base() {
Icon = Foo.sIcon;
Position = Foo.sPosition;
}
}
Then use "Foo" as your base form when creating your forms.
I didn't check references for the "Icon" and "position" so I don't know if they exists, but you get the idea :)
Yes, but bear in mind that forms inheritance is somewhat flaky in terms of designer support. Just keep in mind that any controls that need to be accessible to child forms must have their modifier changed to Protected (Internal will work for forms in the same assembly, but will also expose the control to ANY class in the same assembly; Public should be avoided). This includes things like panels or other containers, which you'll likely want to use if your base form has to define some basic presentation elements, so you'll want to contain the child form to a particular area.
To this, just create your base form as you would any other form, then when you go to create new forms, choose "Inherited Form" instead of "Form", and select your base form.

Showing a hidden form

How do i show a from that have been hidden using
this.Hide();
I have tried
MainMenuForm.Show();
and this just says i need an object ref. I then tried:
MainMenuForm frmMainMenu = new MainMenuForm();
frmMainMenu.Show();
Which seems to show the appropriate form. But when you exit the app, it is still held in memory because it hasn't shown the form that was hidden, instead it has shown a new version of the form. In effect having 2 instances of the form (one hidden, one visible).
Just to clarify, the MainMenuForm is the startup form. When (for example) Option 1 is clicked, the MainMenuForm then hides itself while opening up the Option 1 form. What i would like to know is how to i make the Option 1 form that the MainMenuForm opens "unhide" the MainMenuForm and then close itself.
What's the correct procedure here?
Thanks in advance.
When you do the following:
MainMenuForm frmMainMenu = new MainMenuForm();
frmMainMenu.Show();
You are creating and showing a new instance of the MainMenuForm.
In order to show and hide an instance of the MainMenuForm you'll need to hold a reference to it. I.e. when I do compact framework apps, I have a static classes using the singleton pattern to ensure I only ever have one instance of a form at run time:
public class FormProvider
{
public static MainMenuForm MainMenu
{
get
{
if (_mainMenu == null)
{
_mainMenu = new MainMenuForm();
}
return _mainMenu;
}
}
private static MainMenuForm _mainMenu;
}
Now you can just use FormProvider.MainMenu.Show() to show the form and FormProvider.MainMenu.Hide() to hide the form.
The Singleton Pattern (thanks to Lazarus for the link) is a good way of managing forms in WinForms applications because it means you only create the form instance once. The first time the form is accessed through its respective property, the form is instantiated and stored in a private variable.
For example, the first time you use FormProvider.MainMenu, the private variable _mainMenu is instantiated. Any subsequent times you call FormProvider.MainMenu, _mainMenu is returned straight away without being instantiated again.
However, you don't have to store all your form classes in a static instance. You can just have the form as a property on the form that's controlling the MainMenu.
public partial class YourMainForm : Form
{
private MainMenuForm _mainMenu = new MainMenuForm();
protected void ShowForm()
{
_mainMenu.Show();
}
protected void HideForm()
{
_mainMenu.Hide();
}
}
UPDATE:
Just read that MainMenuForm is your startup form. Implement a class similar to my singleton example above, and then change your code to the following in the Program.cs file of your application:
Application.Run(FormProvider.MainMenu);
You can then access the MainMenuForm from anywhere in your application through the FormProvider class.
The simplest and easiest way is to use LINQ and look into the Application.OpenForms property. I'm assuming you have only 1 instance of the form (hopefully!), otherwise make sure to have to have some public property on the hidden form to be able to differentiate it.
The following code will un-hide the form for you:
var formToShow = Application.OpenForms.Cast<Form>()
.FirstOrDefault(c => c is MainMenuForm);
if (formToShow != null)
{
formToShow.Show();
}
You need to keep a reference to the first form when it's created and then the code that holds that reference can call Show on it.
If you don't open that form from somewhere but it's set as the startup form, then you either need to change it so that you have a Main method that opens that form or you can have that form store a reference to itself somewhere that can be accessed from other places.
For example, an quick and ugly way would be to, add a public static property to your mainform and then when you hide the form it also writes this to that property which can then be retrieved when needed by other parts of the code.
Practically This works for me....
public class MainWindow : Form
{
Form _mainMenuForm = new MainMenuForm();
}
calling it through a button click event.
private void buttonclick()
{
if (_mainMenuForm.Visible)
{
_mainMenuForm.Visible = false;
}
else
{
_mainMenuForm.Visible = true;
}
}
Store a reference to the form and call .Hide() and .Show() on that.
For example:
public class MainWindow : Form
{
private Form _mainMenuForm = new MainMenuForm();
public void btnShowMenuForm_Click(...)
{
_mainMenuForm.Show();
}
public void btnHideMenuForm_Click(...)
{
_mainMenuForm.Hide();
}
//etc
}
This example assumes you have a form which is launching the MainMenuForm.
Call the referenced form.
Like:
Calling parent
----------
public MyForm f {get;set;}
void DoStuff()
{
f = new MyForm();
f.Show();
}
MyForm
----------
void DoOtherStuff()
{
this.hide();
}
Parent
----------
void UnHideForm()
{
f.show();
}
Another simpler method to achieve this is to loop through the open forms to see which are still running and open it...
foreach (Form oForm in Application.OpenForms)
{
if (oForm is MainMenuForm)
{
oForm.Show();
break;
}
}

Categories