New panel not opening on Windows Form after triggering click event - c#

I have a Windows Forms App.
I created a custom UserControl which extends Panel.
Inside one of my Forms, there is a button which should open that panel when clicked.
However, after clicking, I still don't see the panel displayed on the form.
Form code
public partial class IngredientMenu : Form
{
public IngredientMenu()
{
InitializeComponent();
}
private void btnOpenRegisterBasePanel_Click(object sender, EventArgs e)
{
BaseIngredientPanel baseIngredientPanel = new BaseIngredientPanel();
baseIngredientPanel.Location = new Point(257, 63);
baseIngredientPanel.Show();
baseIngredientPanel.BringToFront();
Console.WriteLine("panel should open");
Console.WriteLine(baseIngredientPanel.Visible);
Console.WriteLine(baseIngredientPanel.Location);
}
}
Panel code
public partial class BaseIngredientPanel : UserControl
{
public BaseIngredientPanel()
{
InitializeComponent();
}
private void btnRegisterBaseIngredient_Click(object sender, EventArgs e)
{
IngredientContext ingredientContext = new IngredientContext();
if (ingredientContext.RegisterIngredient(txtName, txtUnit, lblBaseIngredientNameValidation, lblBaseIngredientUnitValidation))
{
MessageBox.Show("Ingredient Registered."
, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtName.Text = "";
txtUnit.Text = "";
}
else
{
MessageBox.Show("There are errors in the form fields."
, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void BaseIngredientPanel_Load(object sender, EventArgs e)
{
Console.WriteLine("I AM OPEN");
}
}
Additionally, the "I AM OPEN" message never appears, even after clicking, so it seems like in general it's not even loading the control.
How can I make the panel open after clicking a button? I'd rather not manually drag a panel into the designer since I need to have like 5 panels and designer is just gonna try to box them like a russian doll.

All UI controls need to have a parent to whom they belong via the Controls.Add() method.
The parent can be a Form or other controls (not all will accept children). e.g. Your panel can be the parent of textboxes, comboboxes, labels, etc.
private void btnOpenRegisterBasePanel_Click(object sender, EventArgs e)
{
BaseIngredientPanel baseIngredientPanel = new BaseIngredientPanel();
baseIngredientPanel.Location = new Point(257, 63);
//Add user panel to form.
this.Controls.Add(baseIngredientPanel);
//You will probably not need these two rows any more. Try it out! But make sure your usercontrol has Visible = true.
baseIngredientPanel.Show();
baseIngredientPanel.BringToFront();
}
Edit:
to answer your questions in the comment below
If you need to make many UI changes at the same time then it is also best to use this.SuspendLayout() and this.ResumeLayout() to temporarily suspend the UI logic. This will help with performance in such cases. See https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.suspendlayout?view=windowsdesktop-5.0 for more details
If you will need to remove the controls at some stage after adding them then you have two options.
Create a separate List<BaseIngredientPanel> to (also) store your
controls when adding them to the form. This use this list to find
and remove them via this.Controls.Remove() method
Give your BaseIngredientPanel a unique Name when creating it, and
use this to find and remove the control via the
this.Controls.Remove() method. All Controls already have a Name property so you can use this.

If you want to show a Form, the class should be derived from Form. Your BaseIngredientPanel is not a Form, it is a UserControl.
UserControls are similar to other Controls like Buttons, ComboBoxes, Menus, DataGridViews, etc. Usually you use Visual Studio Designer to show them on a Form. In rare occassions you do this programmatically.
I created a custom UserControl which extends Panel.
What do you really want:
I want to create a special kind of Panel, one that behaves like a standard Panel, with only small differences. Users of my class may use almost all Properties of my special Panel: Derive from class Panel
I want to create a special kind of Panel, one that behaves like a standard Panel. I want to control which methods users of my special Panel can call: Create a class derived from UserControl and put a Panel on it.
I want to create a Form, on which I want to put a Panel. This Panel has some behaviour which I only use on this Form.
If you want to create a special kind of Panel, one that is to be reused on several Forms, use derivation. Whether you derive from Panel or UserControl depends on how fool proof you want your class to be, and how many Panel methods users of your class may call.
If your special Panel is only to be used on one Form, don't bother to create a special Panel class. Create a Form that contains the Panel.
Use standard Panel on special Form
If you decided that you don't have to reuse the behaviour of this Panel, you can just put it on a new Form. Use visual studio designer to Create the form and put a Panel on it. Subscribe to the Panel events that you want to react on.
If you want that the form also has a Button, also use visual studio designer to add the Button and subscribe to event Button_Clicked.
To show the PanelForm, you have to decide whether the PanelForm is model or modeless.
Modal: the operator can only use this Form until it is closed. He can't use other forms of this application. This is by far the most used kind of Form: on menu selection, or button click: show the PanelForm, use the PanelForm, close the PanelForm, after which the parent form can read the results of the PanelForm and act accordingly. Modal Dialog boxes are shown using Form.ShowDialog.
Modeless: while the PanelForm is shown, the operator can switch back to the parent form and interact with it. This is not used very often. You can use it to show some extra information about the status of the parent window or application, for instance the position of the mouse, or the selected Shape that you will draw. A modeless Dialog box is shown using Form.Show(). Keep in mind, that before you close the parent form, you will have to close the modeless dialog box
Show Modal
A good example is the OpenFileDialog form
In your parent form:
using (var form = new OpenFileDialog())
{
// set properties of the OpenFileDialog before showing
form.InitialDirectory = this.GetInitialDirectory();
form.DefaultExt = ".txt";
...
// Show the Form as a modal box and wait until it is Closed
DialogResult dialogResult = form.ShowDialog(this);
// the operator has closed the form. Interpret the result:
if (dialogResult == DialogResult.OK)
{
string fileName = form.FileName();
this.OpenFile(fileName);
}
}
Modeless: operator can switch back to this form
private MyPanel PanelForm {get; set;} = null;
private void ShowMyPanel()
{
if (this.PanelForm != null) return; // panel already shown
this.PanelForm = new MyPanel();
// set properties:
this.PanelForm.DisplayedItems = ...
// show the PanelForm
this.PanelForm.Show();
}
The operator can switch back to this form, and probably close this form. In that case you will have to Close the PanelForm:
private void CloseMyPanel()
{
if (this.MyPanel != null)
{
this.MyPanel.Close();
this.MyPanel.Dispose();
this.MyPanel = null;
}
}
private void OnFormClosing(object sender, ...)
{
// if MyPanel is shown, is it allowed to Close this form AND myPanel
// or should you warn the operator to close MyPanel first?
if (this.MyPanel != null)
{
this.CloseMyPanel(); // close immediately
// or:
MessageBox.Show(..., "Please close Panelbox first");
}
}
Of course you should also react if the operator closes the panelbox. Before showing the panel box:
this.MyPane.Closed += OnMyPanelClosed;
private void OnMyPanelClosed(object sender, ...)
{
if (object.ReferenceEquals(sender, this.MyPanel)
{
// my panel is closed
this.MyPanel = null;
You can't dispose the Panel, because it is still being used. The Panel show Dispose itself when Closed.
Special Panel Class
If you have a Special Panel Class (derived from either Panel, or UserControl), then after compiling, the panel control is visible in the toolbox of visual studio designer.
You should use use visual studio designer to create a Form and put the panel on the Form:
class MyPanelForm : Form
{
public MyPanelForm()
{
InitializeComponent();
If you have used visual studio designer to add the special Panel, then you will find it in InitializeComponent. You can also add it yourself in the constructor. In that case, don't forget to add it to this.components, so your panel will be disposed when MyPanelForm is disposed.
To show MyPanelForm, use either ShowDialog or Show, as described in the previous section.

Related

Updating MDI child forms list after closing a form

I am using DevExpress NavBar as main menu for my MDI application, and one of NavBar's groups contains items that represent opened MDI child forms. I am having trouble with updating a menu when a MDI child form closes.
I have to use Form.MdiChildren collection to generate menu group, but the problem is, when using Form.FormClosing event, that closed form is still in Form.MdiChildren collection. I tried to use a System.Timers.Timer to wait 1 second and then update a menu, but I get various exceptions because of asynchronous behavior (when a user closes few forms very fast).
I also cannot maintain my own list of MDI children, because of complexity of classes design.
Does anyone have some elegant solution for this?
I have had success with using this combination of methods:
private List<Form> _childForms = new List<Form>();
protected override void OnMdiChildActivate(EventArgs e)
{
base.OnMdiChildActivate(e);
Form form = ActiveMdiChild;
if (form == null)
return;
else
{
if (!_childForms.Contains(form))
{
_childForms.Add(form);
form.FormClosed += mdiChildForm_FormClosed;
}
}
}
private void mdiChildForm_FormClosed(Object sender, FormClosedEventArgs e)
{
var form = (Form)sender;
if (_childForms.Contains(form))
_childForms.Remove(form);
if (_childForms.Count > 0)
_childForms[_childForms.Count - 1].Activate();
}
Note that the Activate method is called pretty much anytime the user interacts with a child form. That includes opening and closing them.
You can then make use of the childForms collection to always know the open forms and do what you like with them.
"I also cannot maintain my own list of MDI children, because of complexity of classes design."
Is this because of the different class types?
What about holding a list of base classes? like: List<Form> When there is a FormClosed event, just remove that form from the list.

How to change a control property (FlatStyle) in base form?

This might be kind of beginner question but I searched and didn't find any clear answer!
The main question is: How to inherit properties of a control (specially FlatStyle) from a base form which doesn't have that control in C#?
Details: I have Form1 inherited from baseForm. baseForm has a Panel and a Label control but no Button. In Form1 I added a button named Button1. How can I change the style of that Button through the baseFrom?
I don't want to create a custom control or redesign the button using rectangles or similar ways, but only change that property for all buttons in my application.
UPDATE: I want all of the buttons to be affected, whether they already exist or just added. Not matter in which -if any- container they are.
In baseForm, you could hook the ControlAdded event on the Panel where the Button is to be added, and style appropiately via code. This will work for every form inherited from baseForm.
For example (in baseForm)
public partial class BaseForm : Form
{
public BaseForm()
{
InitializeComponent();
// "myPanel" is the panel where the button will be added in inherited forms
myPanel.ControlAdded += myPanel_ControlAdded;
}
private void myPanel_ControlAdded(object sender, ControlEventArgs e)
{
var button = e.Control as Button;
if (button != null)
{
button.FlatStyle = FlatStyle.Flat;
button.ForeColor = Color.Red;
}
}
}
Just made a really quick test... it works even in design mode:
As an alternative, if you are going to use heavily styled buttons everywhere in your application, you may consider creating a custom control inheriting from Button, and assign the properties there, like:
public class FlatButton : System.Windows.Forms.Button
{
public FlatButton()
{
FlatStyle = FlatStyle.Flat;
}
}
After building, you will find it in the Toolbox (under "[Your Project's] components" tab), or you can cram it on your own control library (in a different solution) and add it permanently to the Toolbox in Visual Studio.
You would need to make use of Reflection
You can use a LINQ query to do this. This will query everything on the form that is type Button
var c = from controls in this.Controls.OfType<Button>()
select controls;
foreach(var control in c)
control.FlatStyle = FlatStyle.Flat;

How can I prioritize one form over another without hiding it in Visual Studio 2010?

I've been trying to find a way to disable a form, and put another form in front of it to act as a receiving party for my update command from SQL Server. My only problem is... The appearance of my main form, seems to be simple, and I'd rather keep it that way. I got two exhibits, since I can't post pictures in this state yet... But I'll update so more will understand.
Exhibit 1: My medical records form has several buttons, containing the INSERT, UPDATE, DELETE, View via Crystal Report, Print, Search and the Back buttons. There's also a listview object placed that occupies most of the form.
Exhibit 2: My UPDATE form is consisted of 7 textboxes: 6 containing basic info, and one containing the full name of the user which is by default, read-only. Two buttons, UPDATE and Back are in the form as well. Labels are placed above the basic info textboxes to signal the user's information to be entered.
Here's my question: How will I disable all buttons and the listview (which is the form of Exhibit 1), and place Exhibit 2 over it, WITHOUT hiding Exhibit 1?
To clarify, Exhibit 1 cannot be accessed as long as Exhibit 2 is in place, once it's open (which is my goal). I was trying to find a way to put the Update form over the medical records form, but to no luck, I keep seeing the Medical Records form clickable once the two are open at the same time. Please help me out... I'm just a student who's getting the hang of things in Visual Studio 2010, but I thought of asking just to know if anyone knows.
To those who would answer... thank you. :) It's my first post... so please be patient...
Here is an example which uses a main form mainForm and a button cb_update to open a second form updateForm. Upon opening, the 2nd form places itself over the 1st form and disables all controls of the 1st form. When it is closed it hides itself and re-enables all controls of the 1st form.
Note: both forms have a reference to each other, so they can work with all (public) parts of the other form. (If you need to you can always make a Control public!). One reference is kept from opening, the other is handed in the constructor..
En- or Disabling the controls is done recursively using the Controls collection and the fact that a Form is a Control, too. Here is code for the 1st form:
public partial class mainForm : Form
{
updateForm Uform;
private void cb_update_Click(object sender, EventArgs e)
{
if (Uform == null) Uform = new updateForm(this);
Uform.Show();
}
}
And here the 2nd:
public partial class updateForm : Form
{
mainForm main_Form;
public updateForm(mainForm main)
{
InitializeComponent();
main_Form = main;
}
private void updateForm_Shown(object sender, EventArgs e)
{
this.Size = main_Form.Size;
this.Location = main_Form.Location;
//*1*
setControlState(main_Form, false);
}
private void cb_back_Click(object sender, EventArgs e)
{
setControlState(main_Form, true);
this.Hide();
}
private void updateForm_FormClosing(object sender, FormClosingEventArgs e)
{
setControlState(main_Form, true);
this.Hide();
}
//*2*
public void setControlState(Control Ctl, bool enabled)
{
//*3*
foreach (Control c in Ctl.Controls) setControlState(c, enabled);
Ctl.Enabled = enabled;
//*4*
}
}
Edit: This code assumes that all Controls on the main_form are initially enabled. If that is not the case an exceptions list will take care of that, adding four lines of code:
exceptions.Clear(); //*1*
List<Control> exceptions = new List<Control>(); //*2*
if (!enabled && !Ctl.Enabled) exceptions.Add(Ctl); //*3*
if (enabled && exceptions.Contains(Ctl)) Ctl.Enabled = false; //*4*
Edit 2: I am still not quite sure, what you mean by "Place Exhibit 2 over it, WITHOUT hiding Exhibit 1". If you mean "place it above without hiding it" 1 or 2 lines of the code would be a little different.. Please explain!

Set form as Parent throw exception "Top-level control cannot be added to a control"

I want to access variables of a form from another form. On clicking a button inside my Main form, I want to set my Main form as Parent, then bring up another form (child form) wherein I will access variables of the Main form. My click handler is as follow:
private void btnSystem_Click(object sender, EventArgs e)
{
Form_EnterPassword EP = new Form_EnterPassword();
EP.Parent = this; //error: Top-level control cannot be added to a control
EP.ShowDialog();
}
It compiles fine without any error. However, when I run the Main form and click on the System button, it throws me an exception. I do something similar in another code (not mine) with the same button click, and encounter no error (just with setting Main form as Parent).
What am I doing wrong? Is there something in my Main code that cause this?
Best way would be to use EP.ShowDialog(this) and later use Owner property.
You need the EP.TopLevel property to be set to false. It will let you to set a parent to it.
Further reading.
In case you only want to access variables and controls of another form, then maybe you can reach it in other ways, not trough a Parent relationship.
OK,
apparently the way to do it is to call
Form_Child.ShowDialog(this)
and then I can call
FromParent_aVariable = ((Form_Parent)this.Owner).aVariable;
or if I define aVariable in the namespace Properties then
FromParent_aVariable = NameSpace.Properties.Settings.Default.aVariable;
there are two ways.
Form_EnterPassword EP = new Form_EnterPassword();
EP.MdiParent = this;
EP.Show();
try this way, it helps for me. you need to set principalform as isMdicontainer = true at the form properties
I had a similar situation recently.
I was attempting something similar but by controlling the Child Forms from a different class.
Note(s):
You're trying to set the Child Form(s) "TopMost" to something that does not allow it.
In this case the "MdiContainer".
To accomplish this:
• Disable MainForm "isMdiContainer" property (its use is kind of obsolete anyway).
• Set the Form(s) TopMost properties to true.
• You should now be able to accomplish your feature.
**Code Example:**
/* On your Main Form Class */
private void btnSystem_Click(object sender, EventArgs e)
{
// Instantiate the Form_EnterPassword by passing the MainForm
Form_EnterPassword EP = new Form_EnterPassword(this);
EP.Show(); // No longer as modal Form to display in front.
}
/* Under your EnterPassword Form Class */
// Do not create a new Instance of MyMainForm.
// You want to use the same thread as your MainForm
private MyMainForm mainForm;
/* Constructor */
public Form_EnterPassword(MyMainForm form)
{
mainForm = form;
this.Owner = mainForm; // "this" refers to the: EnterPassword Form.
}
Remarks:
The only additional thing that you (may) have to do, (to achieve perfection) is to check the MainForm > WindowState; and create a code block to minimize or bring the Forms to their specific state.
i.e:
if (WindowState == FormWindowState.Minimized)
{ /* Code to Minimize all the Child Forms. */ }
else { /* Code to bring all Forms to their "Normal" State */ }
Writing this way, made the dialog display on the center of the parent form.
Form_Child.StartPosition = FormStartPosition.CenterParent;
Form_Child.ShowDialog(this);

Panel changing the ownership?

In my C# application there is a main form with a panel main_panel. Whenever the user selects something in the menu, lets say "A", the main panel switches to the form A's panel (look at the code), A_panel.
Since A_panel covers every controls in form A, I can summon all of the controls of form A into main form.
if ((string)MainMenu.SelectedItem == "A")
{
FormA A = new FormA();
new_panel = A.Controls["A_panel"] as Panel;
}
this.main_panel.Controls.Clear();
this.main_panel.Controls.Add(new_panel);
My question is when user selects menu A again, I don't want to recreate FormA again by new FormA(). I did because when I add control to the main_panel, then the A_panel's ownership changes to main form so that it was possible to add the control to main_panel again.
So, how to change the ownership of A_panel to Form A again?
And how to solve my problem generally?
Any reason you can't use a UserControl and keep a reference to it on your form? That way you can just show/hide it when the user wants to change views. It would be much easier to extend and interact with. Here's a walk-through on MSDN to get you started.
It sounds like a UserControl would suit your needs better. Have one instance on FormA and another on your MainForm.
If, for some reason, you can't use user controls, you could at least extract the code outside the autogenerated designer file (which I assume is why you're using FormA at all).
As in:
FormA
public FormA()
{
var mainPanel = CreateMainPanel();
this.Controls.Add(mainPanel)
}
public Panel CreateMainPanel()
{
//...build up your control tree. Cut the code from the designer if necesssary
}
MainForm
FormA _A = new FormA();
public void HandleMainMenuClick(object sender, EventArgs e)
{
if ((string)MainMenu.SelectedItem == "A")
{
new_panel = _A.CreateMainPanel();
}
this.main_panel.Controls.Clear();
this.main_panel.Controls.Add(new_panel);
}

Categories

Resources