让我们说我有一个类似... 3控件的面板。我可能最终会添加更多控件或更改该面板中的定位。程序启动时,我将以编程方式隐藏控件。最终,用户可以单击一个按钮,该按钮将创建原始面板的副本以填充表单上的区域。该按钮最终应具有另一次单击的选项,这意味着可以在这个区域中填充多个这些实例。请记住,这些控件可能包含文本标签,可以在以后以编程方式单独设置或更改。我假设要做这个程序,我需要制作一个控件列表,也许是一个面板列表?考虑到我需要多次重复多个控件,我不确定如何做到这一点。
有一个很好的,简单的方法吗?我真的不想与任何类型的第三方包装进行复制。
答案 0 :(得分:2)
你必须在代码中完成它,因此它会像你可以编码一样好;-)
严重的是,最常用的课程是
UserControl
,它是一个与表单相关的类,具有您想要的布局。FlowLayoutPanel
,通常是AutoScroll
这是非常好的和简单的imo。
这是一个很短的步行路程..:
Add-New UserControl
并为其指定您选择的类名。我将使用' BookItem'。PictureBox
,四个Labels
和一个NumericUpDown
。BookItem.Designer.cs
文件:在这里,您可以看到在Form.Desginer.cs
文件中看到的内容:您添加到布局的所有控件的所有设置和所有声明。特别注意声明(在文件的底部):就像Form一样,默认情况下所有控件都声明为private!BookItem.Designer.cs
属性private
从public
更改为Modifiers
或在Designer中更改其声明
在这两种方式之间选择是一个品味问题;如果其他开发人员将使用UC类,那么通过编写访问方法来密切控制您公开的内容可能会更好。
编译完项目后,您可以在工具箱中看到新的UC。
让我们看一个例子:
想象一下书店里的一个简单的订单系统:客户已经对我们商店的书籍进行了搜索,并在DataGridView
< dgv_bookList'中显示了一系列书籍,只读,多选。在右边有一个FlowLayoutPanel
' flp_cart'代表购物车。我们有一个命令按钮' cb_addItems'将所选书籍添加到购物车。
Button
可能是这样的脚本:
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);
}
}
这将为DGV中的每个选定行添加一个BookItem。
以上代码需要注意几点:
我将一个DataGridViewRow传递给UC的构造函数,以便它可以直接设置其标签!这意味着,除了desginer为我们构建的无参数构造函数之外,我们还需要编写第二个构造函数,可能是这样的:
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 setData(DataGridViewRow bookData)
函数。
还要注意我的标签名称是多么愚蠢!我希望你能做得更好!
另请注意我如何访问&#39; label1&#39;并从表单中的按钮修改其文本;要做到这一点,我必须在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() { return (int) numericUpDown1.Value; }
或者,当然是财产:
public int quantity { get { return (int)numericUpDown1.Value; } }
另请注意,我将BookData项的名称设置为第一个数据项的某个变体,即我的书ID。在构造函数中也可能发生这种情况,或者更好;并且应该检查以防止两次添加相同的项目..
总而言之,使用UserControls非常类似于使用Forms,包括用于表单间通信的所有常用方法或技巧:保留引用,公开成员,创建属性和函数..
最后一点注意:与表单或子类控件一样,有一个问题:通过将它们放置在设计器中,您可以在设计时为设计人员分配责任,以显示您的UC。
这通常很好;然而,也有可能引入微妙的错误,使设计师无法显示控件。在设计人员能够显示控件或包含控件的任何表单之前,您需要更正这些问题。让我们来看一个这样一个问题的简单例子:
让我们编写PictureBox的Paint事件&#39; pb_cover&#39;在加州大学:
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的表单,Desginer就会崩溃并告诉你它无法工作,因为Brush是null。这里的补救措施很简单:在Brush声明中添加一个默认值,一切都很好。其他情况可能需要更多思考..
我甚至没有遇到问题btw,因为我没有在Form上放置BookItem的实例;它们只在添加按钮中创建..
我希望能让你开始!