Reputation: 446
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.
Upvotes: 0
Views: 821
Reputation: 30492
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:
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.
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.
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);
}
}
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.
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.
Upvotes: 0
Reputation: 9650
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.
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()
methodBaseIngredientPanel
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.Upvotes: 1