触发点击事件后,新面板未在 Windows 表单上打开

New panel not opening on Windows Form after triggering click event

我有一个 Windows 表单应用程序。 我创建了一个扩展 Panel 的自定义 UserControl。 在我的一个表单中,有一个按钮,单击该按钮会打开该面板。

但是,点击之后,我仍然没有看到表单上显示的面板。

表单代码

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);
        }
    }

面板代码

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");
        }
    }

此外,“我已打开”消息从未出现,即使在单击后也是如此,因此通常它似乎甚至没有加载控件。

如何在单击按钮后打开面板?我宁愿不手动将面板拖到设计器中,因为我需要 5 个面板,而设计器只是想把它们像俄罗斯套娃一样装箱。

所有 UI 控件都需要通过 Controls.Add() 方法拥有它们所属的父控件。 父级可以是 Form 或其他控件(并非所有控件都接受子级)。例如您的面板可以是文本框、组合框、标签等的父级。

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();
}

编辑:

在下面的评论中回答您的问题

如果你需要同时做很多UI的改变那么最好也用this.SuspendLayout()this.ResumeLayout()暂时挂起UI的逻辑。这将有助于在这种情况下提高性能。有关详细信息,请参阅 https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.suspendlayout?view=windowsdesktop-5.0

如果您需要在添加控件后的某个阶段删除控件,那么您有两个选择。

  1. 创建一个单独的 List<BaseIngredientPanel> 来(也)存储您的 将它们添加到表单时进行控制。这个使用这个列表来查找 并通过 this.Controls.Remove() 方法
  2. 删除它们
  3. 在创建时为您的 BaseIngredientPanel 指定一个唯一的名称,并且 使用它通过查找和删除控件 this.Controls.Remove() 方法。所有控件都有一个名称 属性,因此您可以使用它。

如果要显示表单,class 应该派生自表单。您的 BaseIngredientPanel 不是表单,而是用户控件。

UserControl 类似于按钮、组合框、菜单、DataGridView 等其他控件。通常您使用 Visual Studio 设计器在窗体上显示它们。在极少数情况下,您可以通过编程方式执行此操作。

I created a custom UserControl which extends Panel.

你真正想要的是什么:

  • 我想创建一种特殊的面板,它的行为类似于标准面板,只有很小的区别。我的 class 的用户可能会使用我的特殊面板的几乎所有属性:源自 class 面板
  • 我想创建一种特殊的面板,其行为类似于标准面板。我想控制我的特殊面板的用户可以调用哪些方法:创建一个派生自 UserControl 的 class 并在其上放置一个面板。
  • 我想创建一个窗体,我想在上面放置一个面板。这个面板有一些我只用在这个表单上的行为。

如果您想创建一种特殊的面板,可以在多个窗体上重复使用,请使用派生。您是从 Panel 还是 UserControl 派生取决于您希望 class 的万无一失,以及 class 的用户可以调用多少 Panel 方法。

如果你的特殊Panel只在一个Form上使用,就不用费心去创建特殊Panel了class。创建一个包含面板的窗体。

在特殊表格上使用标准面板

如果您决定不必重用此面板的行为,您可以将它放在一个新窗体上。使用 visual studio 设计器创建表单并在其上放置一个面板。订阅您要响应的面板事件。

如果您希望表单也有一个按钮,也可以使用 visual studio 设计器添加按钮并订阅事件 Button_Clicked。

要显示 PanelForm,您必须决定 PanelForm 是模型还是非模型。

  • 模态:操作者只能使用这个表单,直到它被关闭。他不能使用此应用程序的其他形式。这是迄今为止最常用的一种表单:在菜单选择或单击按钮时:显示 PanelForm,使用 PanelForm,关闭 PanelForm,之后 parent 表单可以读取 PanelForm 的结果并采取相应行动.使用 Form.ShowDialog.
  • 显示模态对话框
  • 无模式:显示 PanelForm 时,操作员可以切换回 parent 表单并与之交互。这不经常使用。您可以使用它来显示有关 parent window 或应用程序状态的一些额外信息,例如鼠标的位置或您将绘制的选定形状。使用 Form.Show() 显示无模式对话框。请记住,在关闭 parent 表单之前,您必须关闭无模式对话框

显示模式

一个很好的例子是 OpenFileDialog 窗体

在您的 parent 表格中:

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();
}

操作员可以切换回此表单,并可能关闭此表单。在这种情况下,您将不得不关闭 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");
    }
}

当然,如果操作员关闭面板框,您也应该做出反应。显示面板框之前:

this.MyPane.Closed += OnMyPanelClosed;

private void OnMyPanelClosed(object sender, ...)
{
    if (object.ReferenceEquals(sender, this.MyPanel)
    {
        // my panel is closed
        this.MyPanel = null;

您无法处置面板,因为它仍在使用中。面板在关闭时显示自行处置。

特别小组Class

如果您有一个特殊面板 Class(派生自 Panel 或 UserControl),则在编译后,面板控件会在 visual studio 设计器的工具箱中可见。

您应该使用 visual studio 设计器创建一个表单并将面板放在表单上:

class MyPanelForm : Form
{
    public MyPanelForm()
    {
        InitializeComponent();

如果您使用visual studio设计器添加了特殊面板,那么您会在InitializeComponent中找到它。您也可以在构造函数中自己添加它。在这种情况下,不要忘记将它添加到 this.components,这样您的面板将在 MyPanelForm 被释放时被释放。

要显示 MyPanelForm,请使用 ShowDialogShow,如上一节所述。