Displaying a collection of controls in Windows Forms
You can use either of these options:
DataGridView (Example)
You can useDataGridView
to show multiple columns of different types, includingTextBox
,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 orUserControl
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 aPanel
orFlowLayoutPanel
.TableLayoutPanel (Example)
You can use aTableLayoutPanel
containing multiple columns and rows. Each cell ofTableLayoutPanel
can host a control.DataRepeater
You can use aDataRepeater
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:
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 withDock
property of control set toTop
. - If you may want flows other than top-down Use a
FlowLayoutPanel
to add instances of your control to it.
Create a UserControl
Add instances of it to your Panel
or FlowLayoutPanel
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
forForm1
? - 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:
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:
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
How to Detect That C# Windows Forms Code Is Executed Within Visual Studio
How to Use Transactionscope in C#
How to Simulate a Mouse Click at a Certain Position on the Screen
Associate a Private Key with the X509Certificate2 Class in .Net
Micro Optimization of a 4-Bucket Histogram of a Large Array or List
How to Delete a Row from Gridview
Why am I Getting an Out of Memory Exception in My C# Application
Asmx Web Service How to Return JSON and Not Xml
Digital Signature in C# Without Using Bouncycastle
How to Update a Cell Value in a Db Table, Using SQL Server Ce and C# (Visual Studio 2010)
How to Detect Working Internet Connection in C#
Creating Threads - Task.Factory.Startnew VS New Thread()
Can a Tcp C# Client Receive and Send Continuously/Consecutively Without Sleep
Is There a Port of Memcache to .Net