So far in my life, as a .net developer, I have made heavy use of mdi forms to display particular "menu points" such as for instance "module 1" "module 2" and so on.
I have been doing this the following way:
create a parent form with "isMdiContainer" set to "true"
create a menu strip in in the mdi container
create a child form implementing singleton in order for the form to be shown only once
Add something like the following code to the mdi container:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Myapp
{
public partial class MdiContainer : Form
{
private module1 Module1Window;
private module2 Module2Window;
private module3 Module3Window;
public FormContainer()
{
InitializeComponent();
this.Module1Window = modul1.getInstance();
this.Module1Window.MdiParent = this;
this.Module2Window = modul2.getInstance();
this.Module2Window.MdiParent = this;
this.Module3Window = modul3.getInstance();
this.Module3Window.MdiParent = this;
this.Module1Window.Show();
}
private void module1ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module3Window.Hide();
this.Module2Window.Hide();
this.Module1Window.Show();
}
private void module2ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module1Window.Hide();
this.Module3Window.Hide();
this.Module2Window.Show();
}
private void module3ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module1Window.Hide();
this.Module2Window.Hide();
this.Module3Window.Show();
}
}
}
Now, this obviously works fine. But it is a a pain to maintain. Everytime I want to add another child form I have to:
implement Singleton
create the corresponding property in the mdi container
get the instance and set the mdi parent
Hide the new form when other buttons are clicked
Show the form and hide all other Forms when the corresponding button is clicked
Whats a more elegant or lets say efficient approach to archive this?
When do you create the menu items? Are these dynamically created along with the child forms?
If so what you can do is create the form and add it to a list and assign the menu item's Tag property to the form. Assign all the menu items click event to the same handler and within the handler do this...
private void menuStrip_Click(object sender, EventArgs e)
{
var menu = (ToolStripItem)sender;
var viewForm = (Form)sender.Tag;
foreach(Form childForm in _childForms)
childForm.Hide();
viewForm.Show();
}
This same handler can be used no matter how many forms you have.
Alternatively you can have a key as the Tag and have a Dictionary<string, Form> so you can more lazily create the forms, however the concept is the same.
Related
I am writing a C# Windows Forms App Online Store GUI that interfaces with a database. One of the things I have to do is handle customers that are already in the database. From the main menu form they click the 'Returning Customer' button, and enter their email and password. The data entered is then checked against the customers stored in the database, and if it's verified, their user information is filled into text boxes (Name, Credit Card info, CVS, etc...) and the order form becomes visible. I have no issues there. The issue I'm having is that if a returning customer successfully logs in, then cancels out back to the main menu, the next person to click the 'Returning Customer' button pulls up the form with the first user's information already filled in and visible, since both the this.Close() and the this.DialogResult = DialogResult.Cancel methods both only hide the form rather than actually close and free it. But then if I use this.Dispose() on the Returning Customer Form to free it, it can't be reopened.
My question is: is there an easy way to handle this? I'm self taught in C# so forgive my inexperience. Thank you for any help you can give.
Per request see Form1 (Main Menu Form) code below:
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database_Interface_Project
{
public partial class Form1 : Form
{
// Removed SqlConnectionString for security purposes.
public SqlConnection cnn = new SqlConnection(connectionString);
// Main Menu Form
public Form1()
{
InitializeComponent();
}
// New Customer Form
Form2 newCustomer = new Form2();
private void newCusButt_Click(object sender, EventArgs e)
{
newCustomer.ShowDialog();
}
// Returning Customer Form
ReturningCustomer returningCustomer = new ReturningCustomer();
private void RetCusButt_Click(object sender, EventArgs e)
{
returningCustomer.ShowDialog();
}
private void exitButt_Click(object sender, EventArgs e)
{
this.Close();
}
// Manager Menu Form
Manager managerMenu = new Manager();
private void managerButt_Click(object sender, EventArgs e)
{
managerMenu.ShowDialog();
}
}
}```
You just need to re-instantiate returningCustomer form in order to reset its fields.
private void RetCusButt_Click(object sender, EventArgs e)
{
using (var returningCustomer = new ReturningCustomer())
{
returningCustomer.ShowDialog();
}
}
Using statement calls Dispose() automatically after the using-block is left.
Note: In your case you need to dispose ShowDialog appropriately to avoid GDI leak, since it has side effect of keeping the GDI objects alive.
I am writing a simple code it has 3 buttons 2 that will need to open up other forms and one to close the program. When i start the program the exit button will not work even though i have it coded the same as any other time i have wrote a program.
When i press any of the buttons nothing happens. Im not 100% sure how to use the buttons to open another form but i know the exit button should work as is.
Here is the code:
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 _3343_ParksJ_Lab02
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void workerButton_Click(object sender, EventArgs e)
{
WorkerForm workersForum = new WorkerForm();
}
private void suppervisorButton_Click(object sender, EventArgs e)
{
SupervisorForm workersForum = new SupervisorForm();
}
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
You have to subscribe your buttons' click events to the event methods before they'll fire correctly.
You can check the Designer.cs file to see if this has already been done, though I'm guessing it hasn't. You'll be looking for something like this:
this.workerButton.Click += new System.EventHandler(this.workerButton_Click);
One way to do so is directly in the constructor:
public MainForm()
{
InitializeComponent();
workerButton.Click += workerButton_Click;
suppervisorButton.Click += suppervisorButton_Click;
exitButton.Click += exitButton_Click;
}
Normally, I'd do this through the designer. Select each Button in turn, then open the properties panel and double-click on the event you wish to subscribe to, which will create the corresponding event method in the code-behind for you.
Look at .Designer.cs file and make sure your button is adding the correct delegate method. In your case it should exitButton_Click.
Sometimes when you change names of a button VS designer does not make the name change correctly in the .Designer file. Very rare but it happens.
So.. i've googled around and everywhere i've seen different ways of creating this..
But so far, i haven't managed to make a single working menu.
So i wanted to ask, how does one create a notifyIcon menu?.. (prefered explained in details, as i'm rather new to this)
which way would be best and which should i use.. (so far people seemed to like contextmenu overally, but all i can find is contextmenustrip, not sure if it's the same.)
Currently i got a form, set to visible = false, windowstate minimized, showintaskbar = false.
that's about all it is for now. i wanted to have the menu before going wider.
Thank you for your time and effort for this (not sure if it's formulated properly)
EDIT: i've seemed to manage to make a menu, but how would i make it "appear" on my notify icon, it's a ContextMenu o_o
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 TrayTest.events
{
public partial class TrayMenu : Form
{
public TrayMenu()
{
InitializeComponent();
TrayMenuContext();
}
private void TrayMenuContext()
{
this.notify_icon.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
this.notify_icon.ContextMenuStrip.Items.Add("Test1", null, this.MenuTest1_Click);
this.notify_icon.ContextMenuStrip.Items.Add("Test2", null, this.MenuTest2_Click);
this.notify_icon.ContextMenuStrip.Items.Add("Exit", null, this.MenuExit_Click);
}
void MenuTest1_Click(object sender, EventArgs e)
{
Application.Exit();
}
void MenuTest2_Click(object sender, EventArgs e)
{
Application.Exit();
}
void MenuExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
}
This worked fine for me. So i'll just leave it here, for other to take a peak at it.. (this is my Form1, just made 1 with a different name, and it's inside a folder named events (kinda why it has that .events))
"EDIT: i've seemed to manage to make a menu, but how would i make it "appear" on my notify icon, it's a ContextMenu o_o"
I believe you can only assign a ContextMenuStrip to the NotifyIcon using the IDE. For a ContextMenu, you'd have to wire it up via code. Double click your Form to get the Load() event, and wire it up in there:
private void Form1_Load(object sender, EventArgs e)
{
notifyIcon1.ContextMenu = contextMenu1;
}
notifyIcon1->ContextMenu = gcnew System::Windows::Forms::ContextMenu();
System::Windows::Forms::MenuItem^ nI_Open_Item = gcnew System::Windows::Forms::MenuItem("Open");
System::Windows::Forms::MenuItem^ nII_Close_item = gcnew System::Windows::Forms::MenuItem("Close");
notifyIcon1->ContextMenuStrip->Items->Add(status_Item);
notifyIcon1->ContextMenu->MenuItems->Add(nI_Open_Item);
So here's my situation. I am designing a program that requires new Image objects to be created in real-time on a Canvas, when the user clicks a certain Button. Seeing as I don't know exactly how many of said Images any given user will create, I can't assign names in the code for each and every one of them. The Images need to be named "Image0", "Image1", "Image2", etc, depending on how many Images already exist on the page. Kinda like how Visual Studio itself works, where each time you drop a control onto the design view, it automatically appends a number to the name of the control.
Does anyone have a code snippet capable of performing this function?
You don't have to explicitly name all controls. Just add them to the canvas "controls" list.
Create a windows app with a single button and a flowLayoutPanel.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
int i = 1;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var button = new Button { Text = string.Format("Button {0}", i) };
button.Click += new EventHandler(button_Click);
flowLayoutPanel1.Controls.Add(button);
i += 1;
}
void button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
button.Text = " clicked!";
}
}
}
I don't have a direct answer to your question, but from the sounds of it, and I could be wrong because I don't know what you're trying to do, you're viewing the problem from a newbie programmer perspective. You might want to consider using a collection of some kind (perhaps a list) and dynamically adding image objects to that. If you want a string name associated with each object, you could consider a dictionary of type Dictionary<string,Image>
I have create the class HoverButton which derives from Form.Button. Here I override the OnMouseEnter/OnMouseLeave events.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace DSLiteWizardLib
{
class HoverButton : Button
{
#region Constructor
public HoverButton()
{
InitializeComponent();
bMouseHover = false;
}
#endregion
#region Methods
private void OnMouseEnter(object sender, System.EventArgs e)
{
bMouseHover = true;
}
private void OnMouseLeave(object sender, System.EventArgs e)
{
bMouseHover = false;
}
private void InitializeComponent()
{
this.MouseEnter += new System.EventHandler(this.OnMouseEnter);
this.MouseLeave += new System.EventHandler(this.OnMouseLeave);
}
}
}
Eventually I want to pass an image for the hover state, pressed state, etc.
How can I get the button that is placed on my Form to use my HoverButton class instead of the standard Form.Button class?
If you're using a seperate assembly to store your control, you could right click the control toolbar and add an item for your assembly. You could then drag and drop your control just like any of the other builtin control.
If you're looking for something a little less elegant, you could go into the Designer.cs file and change the type of the button from Button to HoverButton there.
If you look in your toolbox in your Form Designer you should see the HoverButton that you created. (After a successful build of course.) You then drag it onto your form just like a regular button.
How to add and create a Usercontrol in Visual Studio 2008
NOTE: For the control to show in the toolbox automatically, make sure to set this option in VS:
Tools > Options > Windows Forms Designer > General : AutoToolboxPopulate