I am trying to create a menu driven application using MDI forms. My problem is that the menu in the MDI parent will create a new child every time i clicked on it. How do i allow only one particular instance of the child to be open for a particular form but allow multiple forms from different menu to be open. For example, I would want a child from "File" to be open along with an "Edit" child. Also, is there a way to close all other forms whenever a new form is open?
You can do all of that my checking the MdiChildren array of your main form. That array will list all of the open MDI children on your form.
You can determine if an instance of a form is open by looping through the array and checking if a form of the type requested is already open.
To close all open forms, just loop through MdiChildren and call Close on all of the forms.
You can check for an existing instance of your form through the MDIChildren collection:
private void form2ToolStripMenuItem_Click(object sender, EventArgs e) {
Form2 f = this.MdiChildren.OfType<Form2>().SingleOrDefault();
if (f == null) {
f = new Form2();
f.MdiParent = this;
f.Show();
} else {
f.BringToFront();
}
}
If you want to close any previous open form, you can also just go through the MDIChildren collection:
if (f == null) {
while (this.MdiChildren.Count() > 0) {
this.MdiChildren[0].Dispose();
}
// etc...
Related
Where i'm working i have found an application with a big form that has a tabcontrol and 14 tabpages, every tabpage has a lot of controls and panels that overlap each other, this makes windows form designer really slow. It takes 1 minute to save and over 10 seconds to change a tabpage and change a textbox property.
I tried to separate the tabpages in smaller forms and call the forms as children of a tabpage to create the illusion of the tabpages being in the same form, but that didn't work, because when i load the form into a tabpage then all sizes and locations are messed up.
There is a way to improve the performance of the windows form designer without changing drastically the way the application works?
Create 14 UserControls and resize the tab control to only show the tabs header and place a Panel as placeholder below the tab control. Then when a tab page is selected dynamically add one of the user controls to the panel with docking set to Fill.
public Form1()
{
InitializeComponent();
SelectUserControl();
}
private void TabControl1_Selected(object sender, TabControlEventArgs e)
{
SelectUserControl();
}
private void SelectUserControl()
{
UserControl? uc = (tabControl1.SelectedIndex + 1) switch {
1 => new UserControl1(),
2 => new UserControl2(),
3 => new UserControl3(),
...
14 => new UserControl14(),
_ => null
};
if (uc is not null) {
while (panel1.Controls.Count > 0) {
panel1.Controls[0].Dispose();
}
uc.Dock = DockStyle.Fill;
panel1.Controls.Add(uc);
}
}
Of course you will have add code to load and save values when the user control changes or to set the Data Binding source.
But if you say that it takes 1 minute to save, then maybe your saving procedure is suboptimal.
How to make the child form follow main form.
for example: open a winform [.net2], winform opens form, form follows the mainform if mainform is moving.
Use the LocationChanged event from the MainForm to always set the location of the ChildForm.
Working example:
Form childForm = new Form();
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
childForm.StartPosition = FormStartPosition.Manual;
childForm.Width = this.Width;
childForm.Height = 96;
childForm.Location = new Point(this.Left, this.Bottom);
childForm.Show();
}
protected override void OnLocationChanged(EventArgs e) {
base.OnLocationChanged(e);
if (childForm != null) {
childForm.Location = new Point(this.Left, this.Bottom);
}
}
Superficially simple answer is just to add handlers for when Mainform is moved or resized and then set childform Location and size accordingly.
However do you say want to stop main form being moved such that childform end up off screen.
Can child form be moved independantly.
What about minimise and maximise?
Might you want other arrangements, nore than one child, left and right, child form above main form...
Be worth writing a layout class, and shoving all this stuff off to it.
I am working on a Compact Framework application. This particular hardware implementation has a touchscreen, but its Soft Input Panel has buttons that are simply too small to be useful. There are more than one form where typed input is required, so I created a form with buttons laid out like a keypad. The forms that use this "keypad" form are modal dialogs. When a dialog requiring this "keypad" loads, I load the "keypad" form as modeless:
private void CardInputForm_Load(object sender, EventArgs e)
{
...
keypadForm = new KeypadForm();
keypadForm.Owner = this;
keypadForm.SetCallback(keyHandler);
keypadForm.Show();
}
The SetCallback method tells the "keypad" form where to send the keystrokes (as a Delegate).
The problem I'm having is that the modeless "keypad" form does not take input. It is displayed as I expect, but I get a beep when I press any of its buttons, and its caption is grayed-out. It seems like the modal dialog is blocking it.
I've read other posts on this forum that says modal dialogs can create & use modeless dialogs. Can anyone shed light on this situation? Is there a problem with my implementation?
I found the answer: Set the keypad form's Parent property, not its Owner property, to the form instance wanting the keystrokes. The keypad dialog's title bar stays grayed out, but the form is active.
private void CardInputForm_Load(object sender, EventArgs e)
{
// (do other work)
keypadForm = new KeypadForm();
keypadForm.Parent = this;
keypadForm.Top = 190; // set as appropriate
keypadForm.Show();
}
Be sure to clean up when done with the parent form. This can be in the parent's Closing or Closed events.
private void CardInputForm_Closing(object sender, CancelEventArgs e)
{
// (do other work)
keypadForm.Close();
keypadForm.Dispose();
}
There are two panels on the keypad form, one with numerals and one with letters and punctuation that I want. There is also an area not on a panel that is common to both, containing buttons for clear, backspace, enter/OK, and cancel. Each panel has a button to hide itself and unhide its counterpart ('ABC', '123', for example). I have all the buttons for input on the keypadForm fire a common event. All it does is send the button instance to the parent. The parent is responsible for determining what action or keystroke is desired. In my case I named the buttons "btnA", "btnB", "btn0", "btn1", "btnCancel", etc. For keystrokes, the parent form takes the last character of the name to determine what key is desired. This is a bit messy but it works. Any form wishing to use the keypad form inherits from a base class, defining a method for callback.
public partial class TimeClockBase : Form
{
public TimeClockBase()
{
InitializeComponent();
}
// (other implementation-specific base class functionality)
public virtual void KeyCallback(Button button)
{
}
}
The click event on the keypad form looks like this.
private void btnKey_Click(object sender, EventArgs e)
{
// play click sound if supported
(Parent as TimeClockBase).KeyCallback(sender as Button);
}
The method in the parent form looks like this.
public override void KeyCallback(Button button)
{
switch (button.Name)
{
case "btnCancel":
// setting result will cause form to close
DialogResult = DialogResult.Cancel;
break;
case "btnClear":
txtCardID.Text = string.Empty;
break;
// (handle other cases)
}
}
I am working on a application in which I have to show different forms stacked one upon the other. Due to some restrictions, I cannot use MDI and also it has a lot of issues.
I am able to get what I want but with a problem. The forms will be stacked, but they do not remain in the parent form.
Lets take it by an example. The structure goes like this.
1) There is a form A (My parent form)
2) a second form "B" opens on a button click event on Form "A". (Note: B.ShowInTaskBar=False)
3) again, a third form "C" opens on a button click event on Form "B". (Note: C.ShowInTaskBar=False)
Now, when I minimize form A, it gets minimized but the Form B and C, remains as it is. I want them to get minimized at the same time. I want form B and C should remain as a child form of form A.
How to get that.
Just use MDI forms. There is no technical restriction about FormBorderStyle's value for MDI children. Remember to set the IsMdiContainer property to true for the parent form and then set the child form's MdiParent property to the parent form before Show() is called.
Edit:
I'm not exactly sure what you mean by stacking. You can easily control the child positions if that is what you mean:
public void ShowChildren()
{
Child child1 = new Child();
Child child2 = new Child();
child1.MdiParent = this;
child2.MdiParent = this;
child1.Show();
child2.Show();
child1.Size = new System.Drawing.Size(100, 100);
child1.Location = new System.Drawing.Point(0, 0);
child2.Size = new System.Drawing.Size(100, 100);
child2.Location = new System.Drawing.Point(0, 100);
}
Edit #2:
Are you trying to nest the forms? If so you can make the parent a normal form and place a UserControl A in the parent. Then place UserControl B in UserControl A. Allowing the user to move these around becomes more difficult, but if you already wanted no border this may not be an issue for you.
public void formMain_buttonShowA_click() {
FormA formA = new FormA();
formA.ShowDialog();
}
public void formA_buttonShowB_click() {
FormB formB = new FormB();
formB.ShowDialog();
}
I'm new to Outlook add-in programming and not sure if this is possible:
I want to display a pop-up form (or selection) and ask for user input at the time they click Send. Basically, whenever they send out an email (New or Reply), they will be asked to select a value in a dropdown box (list items from a SQL database, preferrably).
Base on their selection, a text message will be appended to the mail's subject.
I did my research and it looks like I should use Form Regions but I'm not sure how can I display a popup/extra form when user click Send.
Also, it looks like Form Regions can be used to extend/replace current VIEW mail form but can I use it for CREATE NEW form?
Thanks for everybody's time.
You can probably add the Item Send event handler in the ThisAddIn Internal Startup method and then in the Item Send Event, call the custom form (a windows form).
In the below sample I call a custom windows form as modal dialog before the email item is send and after the send button is clicked.
private void InternalStartup()
{
this.Application.ItemSend += new ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
void Application_ItemSend(object Item, ref bool Cancel)
{
if (Item is Microsoft.Office.Interop.Outlook.MailItem)
{
Microsoft.Office.Interop.Outlook.MailItem currentItem = Item as Microsoft.Office.Interop.Outlook.MailItem;
Cancel = true;
Forms frmProject = new ProjectForm();;
DialogResult dlgResult = frmProject.ShowDialog();
if (dlgResult == DialogResult.OK)
System.Windows.Forms.SendKeys.Send("%S"); //If dialog result is OK, save and send the email item
else
Cancel = false;
currentItem.Save();
currentItem = null;
}
}