C# 重新创建一组控件
假设我有一个面板,上面有。。。其中包含3个控件。我可能会添加更多控件或更改面板中的位置。当程序启动时,我将以编程方式隐藏控件。最终,用户可以单击一个按钮,该按钮将创建原始面板的副本,以填充表单上的一个区域。该按钮应具有再次单击的选项,这意味着这些按钮的多个实例可能会填充此区域。请记住,这些控件中可能有文本标签,可以在以后以编程方式单独设置或更改。我假设要做这个程序,我需要做一个控件列表,也许是一个面板列表?考虑到我需要多次复制多个控件的事实,我不太确定如何做到这一点C# 重新创建一组控件,c#,windows,duplicates,C#,Windows,Duplicates,假设我有一个面板,上面有。。。其中包含3个控件。我可能会添加更多控件或更改面板中的位置。当程序启动时,我将以编程方式隐藏控件。最终,用户可以单击一个按钮,该按钮将创建原始面板的副本,以填充表单上的一个区域。该按钮应具有再次单击的选项,这意味着这些按钮的多个实例可能会填充此区域。请记住,这些控件中可能有文本标签,可以在以后以编程方式单独设置或更改。我假设要做这个程序,我需要做一个控件列表,也许是一个面板列表?考虑到我需要多次复制多个控件的事实,我不太确定如何做到这一点 有没有一个好的,简单的方法来
有没有一个好的,简单的方法来做到这一点?我真的不想用任何类型的第三方软件包进行复制。您必须用代码进行复制,因此它将尽可能好地编码;-) 说真的,最常采取的做法是
- 创建一个
,它是一个与表单相关的类,具有您想要的布局UserControl
- …并添加越来越多的实例
- ..通常用于
,通常用于流程布局面板
自动滚动
- 首先,像往常一样,我们首先为UserObject类选择一个好的名称,可能是“DataPanel”或“BookItem”
- 接下来我们创建它:转到项目资源管理器并右键单击,选择
,并为它指定您选择的类名。我将使用“BookItem”addnewusercontrol
- 现在您可以看到设计器向您显示一个小的空控件
- 仔细看:您还可以看到,在项目浏览器中,现在不仅有新的“BookItem.cs”文件,还有补充的“BookItem.Designer.cs”,甚至还有一个“BookItem.resx”文件;因此,这与创建新表单非常相似
- 让我们从工具箱中添加一些控件,我选择添加一个
、四个PictureBox
标签和一个
NumericUpDown
- 查看
文件:在这里,您可以看到在BookItem.Designer.cs
文件中看到的东西:添加到布局中的所有控件的所有设置和所有声明。特别注意声明(在文件的底部):就像表单一样,默认情况下所有控件都声明为私有李>Form.Desginer.cs
- 我们现在可以处理布局并编写控件脚本。我们还可以向UC添加函数和属性,就像表单一样李>
- 请注意:您需要从外部访问、从表单或其方法读取的任何内容都必须是公共的!因此,如果您想访问NUpDown,让我们称之为“nud_quantity”,您可以选择
- 您可以将其在
中的声明从BookItem.Designer.cs
更改为private
,或者通过更改public
属性在设计器中更改修饰符
- 或者您可以在UC中编写一个公共函数来获取/设置其值
- 您可以将其在
- 在这两种方式之间进行选择是一个品味问题;如果其他开发人员将使用UC类,那么最好通过编写访问方法来密切控制您公开的内容
- 编译项目后,您可以在工具箱中看到新的UC
- 现在,您可以从工具箱中添加它,也可以从
- 您可以像动态创建的任何控件一样将其添加到代码中
DataGridView
“dgv_bookList”中显示了一个书籍列表,该列表为只读、多选。右侧有一个FlowLayoutPanel
代表购物车的“flp_cart”。我们有一个命令按钮“cb_addItems”,用于将所选书籍添加到购物车中
按钮
的脚本可能如下所示:
private void cb_addItems_Click(object sender, EventArgs e)
{
if (dgv_bookList.SelectedRows.Count <= 0) return;
foreach (DataGridViewRow row in dgv_bookList.SelectedRows)
{
BookItem book = new BookItem (row);
book.label1.Text = "#00" + book.label1.Text;
book.Name = book.label1.Text;
flp_cart.Controls.Add(book);
}
}
public bookItem()
{
InitializeComponent();
}
public bookItem(DataGridViewRow bookData)
{
InitializeComponent();
label1.Text = bookData.Cells[0].FormattedValue.ToString();
label2.Text = bookData.Cells[1].FormattedValue.ToString();
label3.Text = bookData.Cells[2].FormattedValue.ToString();
label4.Text = bookData.Cells[3].FormattedValue.ToString();
}
public int quantity() { return (int) numericUpDown1.Value; }
相反,您可以编写一个公共setData(DataGridViewRow bookData)
函数
还要注意我的标签命名有多么愚蠢!我希望你能做得更好
还要注意我是如何访问“label1”并从表单中的按钮修改其文本的;为此,我必须更改Desginer.cs文件中的声明:
private System.Windows.Forms.PictureBox pb_cover;
public System.Windows.Forms.Label label1; // <<----expose this label !
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.NumericUpDown numericUpDown1;
或者,当然是财产:
public int quantity { get { return (int)numericUpDown1.Value; } }
还请注意,我将BookData项的名称设置为第一个数据项my book id的某个变体。这也可能发生在构造函数中,或者更好;应该有一个检查,以防止添加相同的项目两次
总之,可以说,使用UserControls与处理表单非常相似,包括表单间通信的所有常用方法或技巧:保留引用、公开成员、创建属性和函数
最后一个注意事项:与表单或子类控件一样,有一个问题:将它们放置在设计器中,您可以指定设计器负责在设计期间显示您的UC
这通常很好;但是,也可能会引入一些微妙的错误,使设计者无法显示控件。在设计器能够显示控件或包含它的任何窗体之前,需要更正这些问题。让我们看一个此类问题的简单示例:
让我们在UC中为PictureBox“pb_封面”的绘画事件编写脚本:
public Brush myBrush = null;
private void pb_cover_Paint(object sender, PaintEventArgs e)
{
if (pb_cover.Image == null)
{
Size s = pb_cover.ClientSize;
e.Graphics.FillRectangle(myBrush, 0, 0, s.Width, s.Height);
e.Graphics.DrawLine(Pens.Red, 0, 0, s.Width, s.Height);
e.Graphics.DrawLine(Pens.Red, s.Height, 0, 0, s.Width);
}
}
让我们修改添加按钮中的代码:
BookItem book = new BookItem (row);
book.label1.Text = "#00" + book.label1.Text;
book.myBrush = Brushes.OliveDrab;
flp_cart.Controls.Add(book);
现在,如果你运行程序,一切都会好起来。即使您尝试在设计师中查看UC,也可能存在或不存在问题。但是,一旦您尝试打开放置UC的表单,设计工程师将崩溃并告诉您它无法工作,因为笔刷为空。这里的补救方法很简单:在笔刷声明中添加一个默认值,一切正常。其他