重新创建一组控件 [英] Recreate a group of Controls

查看:56
本文介绍了重新创建一组控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我有一个面板,上面有... 3个控件.我可能最终会向其添加更多控件或更改该面板中的位置.程序启动时,我将以编程方式隐藏控件.最终,用户可以单击一个按钮,该按钮将创建原始面板的副本,以填充表单上的区域.该按钮最终应具有用于再次单击的选项,这意味着可能会出现多个单击实例,以填充此区域.请记住,这些控件中可能包含文本标签,以后可以通过编程分别设置或更改这些文本标签.我假设要执行此程序,我需要制作一个控件列表,或者一个面板列表?考虑到我需要多次重复多个控件这一事实,我不确定如何做到这一点.

Let's say that I have a panel with like... 3 controls in it. I may end up adding more controls to it or changing the positioning within that panel. When the program starts, I will programmatically HIDE the control. Eventually, the user can click a button that will create a duplicate of the original panel to populate an area on the form. The button should have the option for another click eventually, meaning that multiple instances of these can come about to populate this area. Remember that these controls may have text labels within them that can be individually set or altered later on, programmatically. I am assuming that to do this program, I need to make a List of controls, maybe a List of panels? I'm not exactly sure how to do this considering the fact that I need multiple controls duplicated multiple times.

是否有一个很好的简单方法来做到这一点?我真的不想对任何第三方包装进行重复.

Is there a nice, simple way to do this? I really don't want to do the duplication with any kind of 3rd-party package.

推荐答案

您将不得不在代码中完成此操作,因此,它会和您可以编写的代码一样好;-)

You will have to do it in code and therefore it'll be as nice as you can code ;-)

严重的是,最常采取的课程是

Seriously the course most often taken is to

  • 创建一个UserControl,它是与表单相关的类,并具有所需的布局.
  • ..并添加越来越多的实例..
  • ..通常是FlowLayoutPanel,通常是AutoScroll
  • create a UserControl which is a class related to a form, with the layout you want..
  • ..and add more and more instances of it..
  • ..often to a FlowLayoutPanel, often with AutoScroll

这是非常好的简单imo.

This is pretty nice and simple imo.

这是很短的步行路程..:

Here is a short walk-though..:

  • 首先,像往常一样,首先为UserObject类选择一个漂亮的名称,例如"DataPanel"或"BookItem".
  • 接下来我们创建它:转到项目资源管理器并右键单击,选择Add-New UserControl并为其提供您选择的类名称.我将使用"BookItem".
  • 现在您可以看到Designer向您显示一个小的空控件.
  • 仔细看看:您还可以看到,在项目浏览器中,现在不仅是新的'BookItem.cs'文件,而且是补充的'BookItem.Designer.cs'甚至是'BookItem.resx'文件;因此,这非常类似于创建新表单的方式.
  • 让我们从工具箱中添加一些控件,我选择添加PictureBox,四个LabelsNumericUpDown.
  • 查看BookItem.Designer.cs文件:在这里您可以看到在Form.Desginer.cs文件中看到的内容:添加到布局的所有控件的所有设置和所有声明.特别要注意声明(在文件底部):就像表单一样,默认情况下所有控件都声明为私有!
  • 我们现在可以处理布局并编写控件脚本.我们还可以像Form一样向UC添加函数和属性.
  • 请注意:您需要从外部访问的任何内容,从表单中读取的内容或其方法都必须是公开的!因此,如果您要访问NUpDown,请将其命名为"nud_quantity"
    • 您可以在BookItem.Designer.cs中将其声明从private更改为public或在Designer中通过更改Modifiers属性
    • 或者您可以在UC中编写一个公共函数以获取/设置其值
    • first we start, as usual, by picking a nice name for the UserObject class, maybe 'DataPanel' or 'BookItem'..
    • Next we create it: Go to the project explorer and right-click, choosing Add-New UserControl and give it the class name you chose. I'll use 'BookItem'.
    • Now you can see the Designer showing you a small empty control.
    • Look closer: You can also see that in the project explorer ther is now not only the new 'BookItem.cs' file but also the complementary 'BookItem.Designer.cs' and even a 'BookItem.resx' file; so this works very much like creating a new Form..
    • Let's add a few controls from the toolbox, I chose to add a PictureBox, four Labels and a NumericUpDown.
    • Have a look at the BookItem.Designer.cs file: Here you can see the very things you see in a Form.Desginer.cs file: All settings and all declarations for all controls you add to the layout. Note especially the declarations (at the bottom of the file): Just like for a Form, all controls by default are declared as private!
    • We can now work on the layout and script the controls. We also can add functions and properties to the UC, just like a Form.
    • Please note: Anything you need to access from outside, read from your form or its methods must be public! So if you want to access the NUpDown, let call it 'nud_quantity' you have a choice
      • You can change its declaration in the BookItem.Designer.cs from private to public or in the Designer by changing the Modifiers property
      • Or you can write a public function in the UC to get/set its value

      在这两种方式之间进行选择是一种品味问题;如果其他开发人员可以使用UC类,最好通过编写访问方法来严格控制您公开的内容.

      Chosing between those two ways is a matter of taste; if other developers will work with the UC class, it will probably be better to put close control over what you expose by writing access methods.

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

      After you have compiled the project you can see the new UC in the Toolbox.

      让我们看一个例子:

      想象一下一个书店中的简单订购系统:该客户在我们的书店中进行了搜索,并在DataGridView'dgv_bookList'中以只读,多选的形式显示了书的列表.右侧有一个FlowLayoutPanel'flp_cart',用于重新设置购物车.并且我们有一个命令按钮'cb_addItems'将选定的书添加到购物车中.

      Imagine a simple order system in a bookstore: The customer has done a search on the books in our store and is presented with a list of books in a DataGridView 'dgv_bookList', readonly, multiselect. To the right there is a FlowLayoutPanel 'flp_cart' represeting a shopping cart. And we have a command button 'cb_addItems' to add selected books to the cart.

      Button的脚本可能是这样的:

      The Button might be scripted like this:

      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.

      This will add one BookItem for each selected row in the DGV.

      上面的代码中需要注意的几件事:

      A few things to note on the above code:

      我将DataGridViewRow传递到UC的构造函数中,以便它可以直接设置其标签!这意味着,除了desginer为我们构建的无参数构造器之外,我们还需要编写第二个构造器,也许像这样:

      I pass a DataGridViewRow into the constructor of the UC so it can directly set its labels! This means that, in addition to the parameterless contructor the desginer has built for us, we need to write a second contructor, maybe like this:

      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)函数.

      Instead you could write a public setData(DataGridViewRow bookData) function.

      还要注意,我的标签命名多么愚蠢!我希望您可以做得更好!

      Also note how stupid my labels are named! You can do better than that, I hope!

      还要注意如何访问"label1"并通过表单"中的按钮修改其Text;为此,我必须在Desginer.cs文件中更改其声明:

      Also note how I access 'label1' and modify its Text from a Button in the Form; to do that I had to change its declaration in the Desginer.cs file:

      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;
      

      通常更可取:一种访问功能,也许像这样:

      Often preferrable: An access function, maybe like this:

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

      或者,当然是财产:

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

      还要注意,我将BookData项目的Name设置为第一个数据项目的某种变体,即我的书本ID.在构造函数中也可能发生这种情况,或者更好.并且应该进行检查以防止两次添加相同的项目.

      Also note, that I set the Name of the BookData item to some variant of the 1st data item, my book id. This might as well, or better, happen in the constructor; and there should be a check to prevent adding the same item twice..

      总而言之,使用UserControls非常类似于使用Forms,包括用于表单间通信的所有常用方法或技巧:保留引用,公开成员,创建属性和函数.

      All in all one can say, that using UserControls is very much like working with Forms, including all the usual ways or tricks for inter-form communication: keep references, expose members, create properties and functions..

      最后一个注意:与表单或子类控件一样,有一个陷阱:通过将其放置在设计器中,您可以将设计器的职责分配给设计器,以在设计期间显示您的UC.

      One final Note: Like with forms or subclassed controls there is one catch: By placing them in the designer, you assign the designer the responsiblity to display your UC during design time.

      这通常很好;但是,也可能会引入一些细微的错误,从而使设计人员无法显示控件.您需要更正这些问题,然后设计人员才能显示控件或包含该控件的任何形式.让我们看一个有关此问题的简单示例:

      This is normally just fine; however it is also possible to introduce subtle mistakes which make it impossible for the designer to display the control. You need to correct these problems before the designer will be able to show a control or any form that contains it. Let have a look at a simple example of such a problem:

      让我们脚本化UC中PictureBox'pb_cover'的Paint事件:

      Let's script the Paint event of the PictureBox 'pb_cover' in the UC:

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

      让我们修改添加"按钮中的代码:

      And let's modify the code in the Add button:

       BookItem book = new BookItem (row);
       book.label1.Text = "#00" + book.label1.Text;
       book.myBrush = Brushes.OliveDrab;
       flp_cart.Controls.Add(book);
      

      现在,如果您运行该程序,一切都会好的.即使您尝试在设计器中查看UC,也可能会出现问题,也可能不会出现问题.但是,一旦您尝试打开放置UC的窗体,设计器就会崩溃,并告诉您它无法工作,因为Brush为null.这里的补救方法很简单:将默认值添加到Brush声明中,一切都很好.其他情况可能需要更多思考..

      Now, if you run the program all will be fine. Even if you try to look at the UC in the designer there may or may not be problems. But once you try to open a Form on which the UC was placed, the Desginer will crash and tell you that it can't work, since the Brush is null. Here the remedy is simple: add a default value to the Brush declaration and all is well. Other situations may need a little more thinking..

      由于我还没有在Form上放置BookItem实例,所以我什至没有遇到问题.它们仅在添加按钮中创建..

      I don't even run into the problem btw, since I have not placed an instance of BookItem on the Form; they are only created in the Add Button..

      我希望这可以帮助您入门!

      I hope that gets you started!

      这篇关于重新创建一组控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆