Displaying a Collection of Controls in Windows Forms

Displaying a collection of controls in Windows Forms

You can use either of these options:

  • DataGridView (Example)

    You can use DataGridView to show multiple columns of different types, including TextBox, Label, CheckBox, ComboBox, Image, Button, Link. You also can customize appearance of the grid by custom painting or adding new custom column types.

  • UserControl

    You can create a composite control or UserControl containing any other controls which you need and use it as a row template, then you can show all rows by hosting multiple instance of that user control in a Panel or FlowLayoutPanel.

  • TableLayoutPanel (Example)

    You can use a TableLayoutPanel containing multiple columns and rows. Each cell of TableLayoutPanel can host a control.

  • DataRepeater

    You can use a DataRepeater control to create a row template and show a list of rows using that template.

Example 1 - DatGridView

If you want to use data binding and show specific controls including TextBox, Label, CheckBox, ComboBox, Image, Button, Link a row, DataGridView is great. It's customize-able and you can add some other different column types or customize painting of the grid or benefit from wide range of useful events for validating and so on.

In following image you can see a DataGridView with RowHeaderVisible and ColumnHeaderVisible set to false to act like a List of fields without header:

Sample Image

Example 2 - UserControl

If you need custom control to host more complicated controls or having more control on components or show them in a different layout than columns, you can create a UserControl hosting your components, then:

  • If you only want top-down flow, Use a Panel and add your user control to it with Dock property of control set to Top.
  • If you may want flows other than top-down Use a FlowLayoutPanel to add instances of your control to it.

Create a UserControl

Sample Image

Add instances of it to your Panel or FlowLayoutPanel

Sample Image

How to create user control for displaying collection of other user controls in WinForms?

It is quite easy (if you know how) and doesn't take so much effort as you might think in the first place (at least for a simple implementation that handles collection of less then 100 items).

So at first lets create a MyType:

public class MyType
{
public static MyType Empty = new MyType(String.Empty, DateTime.MinValue);

public MyType(string myName, DateTime myBirthday)
{
MyName = myName;
MyBirthday = myBirthday;
}

public DateTime MyBirthday { get; private set; }

public string MyName { get; private set; }
}

At next we need a MyTypeControl:

public partial class MyTypeControl : UserControl
{
private MyType _MyType;
private Label labelBirthday;
private Label labelName;
private Label labelSeparator;

public MyTypeControl()
{
InitializeComponent();
}

public event EventHandler MyTypeChanged;

public MyType MyType
{
get { return _MyType; }
set
{
if (_MyType == value)
return;

_MyType = value ?? MyType.Empty;
OnMyTypeChanged(EventArgs.Empty);
}
}

protected virtual void OnMyTypeChanged(EventArgs eventArgs)
{
UpdateVisualization();
RaiseEvent(MyTypeChanged, eventArgs);
}

protected void UpdateVisualization()
{
SuspendLayout();

labelName.Text = _MyType.MyName;
labelBirthday.Text = _MyType.MyBirthday.ToString("F");
labelBirthday.Visible = _MyType.MyBirthday != DateTime.MinValue;

ResumeLayout();
}

private void InitializeComponent()
{
labelName = new Label();
labelBirthday = new Label();
labelSeparator = new Label();
SuspendLayout();
labelName.Dock = DockStyle.Top;
labelName.Location = new Point(0, 0);
labelName.TextAlign = ContentAlignment.MiddleCenter;
labelBirthday.Dock = DockStyle.Top;
labelBirthday.TextAlign = ContentAlignment.MiddleCenter;
labelSeparator.BorderStyle = BorderStyle.Fixed3D;
labelSeparator.Dock = DockStyle.Top;
labelSeparator.Size = new Size(150, 2);
Controls.Add(labelSeparator);
Controls.Add(labelBirthday);
Controls.Add(labelName);
MinimumSize = new Size(0, 48);
Name = "MyTypeControl";
Size = new Size(150, 48);
ResumeLayout(false);
}

private void RaiseEvent(EventHandler eventHandler, EventArgs eventArgs)
{
var temp = eventHandler;

if (temp != null)
temp(this, eventArgs);
}
}

Then comes our magically list control:

public class MyTypeListControl : UserControl
{
private ObservableCollection<MyType> _Items;

public MyTypeListControl()
{
AutoScroll = true;
_Items = new ObservableCollection<MyType>();
_Items.CollectionChanged += OnItemsCollectionChanged;
}

public Collection<MyType> Items
{
get { return _Items; }
}

private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateVisualization();
}

private void UpdateVisualization()
{
SuspendLayout();
Controls.Clear();

foreach (var item in _Items)
{
var control = new MyTypeControl { MyType = item, Dock = DockStyle.Top };
Controls.Add(control);
Controls.SetChildIndex(control, 0);
}

ResumeLayout();
}
}

And now simply create the list control in your form or parent control and fill it with some meaningful values:

myTypeListControl.Items.Add(new MyType("Adam", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 40))));
myTypeListControl.Items.Add(new MyType("Eva", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 38))));

How to display controls based on Combobox Selection in Windows Application at edit time?

So you have populated the combobox with items of type CompanyType enum. so the selected item should also the same type. Hope that you are getting a string from company.Element("DataSourceType").Value; so you can modify the code like the following:

cmbbx_companyType.SelectedItem = Enum.Parse(typeof(CompanyType),type);        

Please make a try and let me know whether it solve the issues or not.

Show controls added programmatically in WinForms app in Design view?

Does the designer run my code?

When a form shows in designer, the designer deserialize the code of your form (Form1.Designer.cs or first class in Form1.cs) and creates an instance of the base class of your form and deserialize InitializeComponent and creates controls that you declared in your class and set their properties.

So the codes in Constructor won't run. The designer only creates an instance of the base class of your form and don't look in constructor of your form.

Interesting example of how the designer works

Look at below code and pay attention to this problems:

  • Where are ;s?
  • Constructor Form111111 for Form1?
  • What is NotDefinedFunction()?
  • How can int i = "xxxxxxxxxx"?

Even if you create such file, the designer will show correctly.

using System
using System.Collections.Generic
using System.Drawing
using System.Windows.Forms
namespace Sample
{
public class Form1:Form
{
public Form111111()
{
NotDefinedFunction()
InitializeComponent()
}
public void InitializeComponent()
{
int i = "xxxxxxxxxx"
this.textBox1 = new System.Windows.Forms.TextBox()
this.SuspendLayout()
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(0, 0)
this.textBox1.Name = "textBox1"
this.textBox1.Text = "text of text box 1";
//
// Form1
//
this.Controls.Add(this.textBox1)
this.Name = "Form1"
this.Text = "Form1"
this.Size= new Size(250,100)
this.ResumeLayout(false)
this.PerformLayout()
}
private TextBox textBox1
}
}

And you will see the form in designer:

Sample Image

How can I add controls dynamically at design time?

If you need such functionality, you can create your dynamic controls in constructor of a base class for your form, since constructor of base class will run when you open a child form in designer, then it will run at design time.

But you should know these controls are inherited and can't be changed using designer of child form.

So simply create a Form2:

public Form2()
{
InitializeComponent();
AddDynamicControls();
}

private void AddDynamicControls()
{
this.Controls.Add(
new TextBox() {
Name = "TextBox1", Text = "Dynamic", Location = new Point(100, 0) });
}

Build the project and then change base class of Form1 to inherit from Form2:

public class Form1:Form2

And the result will be:

Sample Image

Is there any other solution?

If you want to generate some controls really at design time, I think you should take a look at T4 Text Templates.

You can use t4 templates to generate code at design-time. Probably you have seen Entity Framework .tt template files. You can add new Text Template item to your project and put the logic for generating items at design-time in your t4 template.

Viewing a list of Controls associated with a class in Visual Studio IDE

View --> Other Windows --> Document Outline

Winform: How to display form controls only when all controls have been loaded?

You could put all of the controls into a "panel" and then set the Panel.Visible to false and when the load and update are complete set the Panel.Visible to true.

The easiest way to signal a busy state is to use Control.UseWaitCursor property. You should be doing the actual loading in another thread.

For example, inside a Form or a UserControl:

panel1.Visible = false;
this.UseWaitCursor = true;
Task.Run(() => {
var data = LoadTheData();
this.BeginInvoke((Action)(() =>
{
labelName.Text = data.Name;
panel1.Visible = true;
this.UseWaitCursor = false;
}));
});

How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?

Here's another option for you. I tested it by creating a sample application, I then put a GroupBox and a GroupBox inside the initial GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a button. This is the code I used (even includes the recursion you were looking for)

public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();

return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}

To test it in the form load event I wanted a count of all controls inside the initial GroupBox

private void Form1_Load(object sender, EventArgs e)
{
var c = GetAll(this,typeof(TextBox));
MessageBox.Show("Total Controls: " + c.Count());
}

And it returned the proper count each time, so I think this will work perfectly for what you're looking for :)

Display Different Windows Within a Panel in a Form (Windows Forms Application)

Rather than instantiate the controls for each application, hide them all, and just show the ones from the selected "application", consider this: design your main selector panel as a placeholder. When the user selects an application, assign the application panel instance in place of the selector panel instance and allow the application to execute to completion. After it exits, restore the placeholder instance.



Related Topics



Leave a reply



Submit