2014-10-30 45 views
0

假设我有一个具有类似... 3控件的面板。我最终可能会添加更多控件或更改该面板中的位置。当程序启动时,我将以编程方式隐藏控件。最终,用户可以单击一个按钮,该按钮将创建原始面板的副本以填充表单上的区域。该按钮应该有最终的另一个点击的选项,这意味着它们的多个实例可以用来填充这个区域。请记住,这些控件可能包含文本标签,可以通过编程方式单独设置或更改。我假设要做这个程序,我需要制作一个控件列表,也许是一个面板列表?我不确定如何做到这一点,考虑到我需要多次重复多次控制。重新创建一组控件

有没有一个很好的,简单的方法来做到这一点?我真的不想与任何第三方软件包进行重复。

回答

2

你将不得不做的代码,因此它会像你一样,你可以编写;-)

认真经常采取的做法是

  • 创建UserControl这是..和相关的表格,你想要的布局一类..
  • 添加越来越多的实例吧..
  • ..often到FlowLayoutPanel,经常与AutoScroll

这是相当不错,简单的imo。

这里是几步之遥,但..:

  • 首先我们开始像往常一样,通过为UserObject类捡好听的名字,也许“dataPanel上”或“BookItem” ..
  • 接下来我们创建它:转到项目浏览器并右键单击,选择Add-New UserControl,并为其选择类名称。我将使用'BookItem'。
  • 现在您可以看到Designer向您展示一个小的空白控件。
  • 仔细观察:您还可以看到,在项目浏览器中,ther现在不仅是新的'BookItem.cs'文件,而且是互补的'BookItem.Designer.cs',甚至是'BookItem.resx'文件;所以这很像创建一个新窗体..
  • 让我们从工具箱中添加一些控件,我选择添加一个PictureBox,4个LabelsNumericUpDown
  • 查看BookItem.Designer.cs文件:在这里,您可以看到在Form.Desginer.cs文件中看到的所有内容:您添加到布局的所有控件的所有设置和所有声明。特别注意声明(在文件底部):就像一个窗体一样,默认情况下所有控件都声明为私有!
  • 我们现在可以处理布局并编写控件脚本。我们也可以将功能和属性添加到UC,就像表单一样。
  • 请注意:您需要从外部访问的任何内容,从您的表单或其方法中读取必须公开!所以,如果你想访问NUpDown,让我们把它叫做“nud_quantity”你有一个选择
    • 您可以通过改变Modifiers性质及其在BookItem.Designer.csprivate声明更改为public或在设计
    • 或者你可以在UC中写公共功能来获取/设置其值
  • 在这两种方式之间进行选择是一种品味问题;如果其他开发人员将与UC类一起工作,最好通过编写访问方法来严格控制您公开的内容。

  • 编译完项目后,您可以在工具箱中看到新的UC。

  • 您可以现在要么从工具箱中添加它或
  • 你可以像你动态地创建任何控制代码添加它。

让我们来看一个例子:

想象在书店一个简单的订单系统:客户已做了我们店里的书籍搜索和呈现的书在DataGridView“dgv_bookList列表',只读,多选。在右边有一个代表购物车的'flp_cart'FlowLayoutPanel。并且我们有一个命令按钮'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); 

    } 
} 

这将增加一个BookItem在DGV每个所选行。

有几件事情要注意,上面的代码:

我传递的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)功能。

另请注意我的标签是多么愚蠢的命名!你可以做得比这更好,我希望!

另请注意我如何访问'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; 

经常preferrable:接入功能,也许是这样的:

public int quantity() { return (int) numericUpDown1.Value; } 

或者,当然还有一个属性:

public int quantity { get { return (int)numericUpDown1.Value; } } 

另请注意,我将BookData项目的名称设置为第一个数据项的一些变体,即我的书籍ID。这可能会更好,或者更好,发生在构造函数中;并且应该进行检查以防止两次添加相同的项目。

所有的一切可以说,在使用用户控件是非常喜欢使用表单,包括所有常见的方法或技巧形式间通信:保持引用,揭露成员,创建属性和功能..

最后一个注意:与表单或子类控件一样,有一个问题:通过将它们放置在设计器中,您可以在设计时指定设计师对您的UC的显示器的责任。

这通常很好;但也可能引入微妙的错误,使设计师无法显示控件。在设计人员能够显示控件或包含它的任何表单之前,您需要纠正这些问题。让我们来看看这样的问题的一个简单的例子:

让我们的脚本中的图片框在UC“pb_cover”的Paint事件:

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为空。这里的补救很简单:给Brush声明添加一个默认值,一切都很好。其他情况可能需要更多的思考..

我甚至没有遇到问题顺便说一句,因为我没有放置在Form上的BookItem的实例;他们只在添加按钮中创建。

我希望能让你开始!

+0

你介意分享一些信息吗?我试着制作一个UserControl,然后使用Add()函数创建一个副本,但是看起来Add()函数将控件从原始面板中移除并放入UserControl中。 – crait 2014-11-02 05:46:21

+0

事实上,你是对的。添加听起来不像,但真的是一个'移动'。如果你创建了一个UserControl,你可以像使用其他Control一样使用它。如果你想在代码中添加另一个副本到你的表单中,你可以通过声明动态创建它,就像其他任何对象一样动态创建它,也许作为新类型的新元素,并通过调用'new'来实例化它。.. I在短时间内会在答案中添加几行,好吗? (你是怎么称呼UC的?) – TaW 2014-11-02 06:55:10

+0

我的问题是我不想以编程的方式做到这一点。我想以一种使用我在[设计]模式下制作的面板的方式来做到这一点。这是因为这个大型项目肯定需要通过更多的控件更新该面板。我的意思是,如果我最终必须,我会,但我会非常喜欢复制父面板并创建基于此的UserControl列表。 – crait 2014-11-02 07:16:29