I have a page where I have to modify variables which are strings with pairs of values and labels. I was using a datagrid object but its not sufficient for whats required ( or eventually will not anyway ).
So I have a form which is a text label and textbox, and a flowpanel, and I'm trying to programmatically add instances of this form for each variable to the flowpanel, and Im getting nothing. Googling for the solution bring sup lots of video tutorials involving clicking on buttons in the UI designer and dropping them on flow panels, I want to do this programmatically however.
What is the 'correct' or 'standard' way of doing this.
The data (in pairs) sounds like it might fit better with a TableLayoutPanel, but the theory is the same; just call .Controls.Add(...) and it should work:
FlowLayoutPanel panel = new FlowLayoutPanel();
Form form = new Form();
panel.Dock = DockStyle.Fill;
form.Controls.Add(panel);
for (int i = 0; i < 100; i++)
{
panel.Controls.Add(new TextBox());
}
Application.Run(form);
or with a TableLayoutPanel:
TableLayoutPanel panel = new TableLayoutPanel();
Form form = new Form();
panel.Dock = DockStyle.Fill;
panel.ColumnCount = 2;
form.Controls.Add(panel);
for (int i = 0; i < 100; i++)
{
panel.Controls.Add(new Label { Text = "label " + i });
panel.Controls.Add(new TextBox { Text = "text " + i });
}
Also - I wonder if a PropertyGrid would fit your needs better? This will handle all the "get value", "show value", "parse value", "store value" logic, and can be plugged with things like ICustomTypeDescriptor to allow dynamic properties.
To add instances of a form to a flowlayout panel, I do the following:
Form1 f1 = new Form1();
f1.TopLevel = false;
f1.Visible = true;
flowLayoutPanel1.Controls.add(f1);
Seems to work OK in my test code.
Related
Lately I am working on this personal app, it's form is without border so the Exit Button, Minimize Button and Maximize button, as well as the option to resize and move the form have been custom added. The app contains several User Controls which perform different functions such as Login, a Control Panel for the app and so on. The issue here is that the User Controls, which are placed within a panel (Anchored properly, of course) in the main form are not resizing properly when the window is in a Maximized state.
To detail... the app starts at
this size and while it's manually resized in minimized state the controls have no issue inheriting it's parent's (the panel) size,
like this and this also works if the window is maximized while the control is visible, like this however if the window is already in a maximized state and I call the control with the designated button the control does not resize, it stays to it's minimum dimensions, like so.
At first I thought it may have something to do with the code that resizes the form so I removed everything and made the app with the default windows border and controls, basically set the border Property from none to sizable but that did nothing. Also I have tried accessing the User Control's parent (the panel) using this.Parent and then setting the width and height of the control with Width = this.Parent.Width and Height = this.Parent.Height but the parent returns null for some reason which I am yet to understand. Now, worth mentioning that those user controls are dynamically added (i.e Login loginForm = new Login();) to the panel every time the button is clicked and then Disposed once the control is left.
I looked all over Google for this but found nothing related and at this point I am out of options. I really want the app to be resizable and must resize properly so if anyone has any solutions I am open to anything.
Thanks anticipated.
Meanwhile, for Winforms, I may have an answer.. the key is to use the Resize event of your user control(s), see below. I tested this in Core 3.1 and Net 4.7, you can use an default designer.cs unit with an empty form. It has no issues with resize from maximized state.
My user control for the center app is named CenteredPanel and derived from Panel. Make sure you derive your user controls from Panel and call base() on the constructor, else the docking will not work properly.
Also, your question about parenting: it was not needed to use Parent below, but if you really need it, make sure you assign it !
public partial class Form1 : Form
{
private Panel panel1, panel2, panel3, panel4;
private CenteredPanel panelApp;
public Form1()
{
InitializeComponent();
this.panel1 = new System.Windows.Forms.Panel()
{ Parent = this, Dock = DockStyle.Fill };
this.panel2 = new System.Windows.Forms.Panel()
{ Parent = panel1, Dock = DockStyle.Left, Width = 120, BackColor = Color.FromArgb(60, 60, 60) };
this.panel3 = new System.Windows.Forms.Panel()
{ Parent = panel1, Dock = DockStyle.Fill };
this.panel4 = new System.Windows.Forms.Panel()
{ Parent = panel3, Dock = DockStyle.Top, Height = 60, BackColor = Color.FromArgb(60, 60, 60) };
this.panelApp = new WindowsFormsAppCore.CenteredPanel()
{ Parent = panel3, Dock = DockStyle.Fill, BackColor = Color.FromArgb(90, 90, 90) };
this.panel1.Controls.Add(this.panel3);
this.panel1.Controls.Add(this.panel2);
this.panel3.Controls.Add(this.panelApp);
this.panel3.Controls.Add(this.panel4);
this.Controls.Add(this.panel1);
}
}
public class CenteredPanel : Panel
{
Label label1, label2;
TextBox textbox1;
public CenteredPanel() : base()
{
this.Resize += new System.EventHandler(this.Resizer);
this.label1 = new System.Windows.Forms.Label()
{ Parent = this, AutoSize = true, Name = "label1", ForeColor =Color.White, Text = "Connectare Administrator" };
this.label2 = new System.Windows.Forms.Label()
{ Parent = this, AutoSize = true, Name = "label2", ForeColor = Color.White, Text = "Nume de utilizator" };
this.textbox1 = new System.Windows.Forms.TextBox()
{ Parent = this, AutoSize = true, Name = "textbox1", PasswordChar = '*', Text = "****" };
this.Controls.Add(this.label1);
this.Controls.Add(this.label2);
this.Controls.Add(this.textbox1);
}
public void Resizer(object sender, EventArgs e)
{
Point CenteringAnchor = new Point(Width / 2, Height / 2);
for (int i=0; i<Controls.Count; i++)
{
Control c = Controls[i];
// put your resizing rules here.. this is a very simple one
c.Location = new Point(CenteringAnchor.X - c.Width / 2, -40 + i * ((i == 1) ? 40 : 30) + CenteringAnchor.Y - c.Height / 2);
}
}
}
I have a form which contains a dynamically added TableLayoutPanel, which contains some dynamically added Labels, TextBox, CheckBox. I am obtaining exactly the visualization I would like to have, but I am struggling to get the "tab key" to work for moving from one control to the other.
I have tried to add a:
control.TabIndex = tabIndex++;
control.TabStop = true;
But this doesn't seem to have any impact...
This is the (tested) stub code:
class MyForm : Form
{
public MyForm()
{
InitializeComponent();
string[] titles = {"first","second"};
var myLayout = new TableLayoutPanel();
myLayout.AutoSize = true;
int myTabIndex = 1; //Not really necessary
int rowNumber = 0;
foreach (var title in titles)
{
var label = new Label();
label.Text = title;
myLayout.Controls.Add(label, 0, rowNumber);
var control = new TextBox();
control.TabIndex = myTabIndex++; //Not really necessary
myLayout.Controls.Add(control, 1, rowNumber);
rowNumber++;
}
this.Controls.Add(myLayout);
}
}
This is the window I get, and I am not able to navigate from first to second field using the tab key.
Update:
Applying Visual Studio 2013 Update 5 did not help.
Something must have been corrupted in my project. The best I could do is to move on with a new clean Windows Form project, and everything now is working.
I'm trying to build a form application in Visual Studio 2010 using C#.
The program will be reading a excel file that contains a list of filenames, and will dynamically generate textbox for each filename.
Below is my code, just for clarification. I wanted to make the label a link to the file, that's why I didn't use checkboxes[i].Text = filename
CheckBox[] checkboxes = new CheckBox[fileCount];
Label[] labels = new Label[fileCount];
for (int i = 0; i < fileCount; i++ )
{
//creating a checkbox
checkboxes[i] = new CheckBox();
checkboxes[i].Location = new Point(360, (145 + i * 30));
checkboxes[i].Name = String.Format("checkbox{0}", i.ToString());
this.Controls.Add(checkboxes[i]);
//creating filename label
labels[i] = new Label();
labels[i].Location = new Point(20, (150 + i * 30));
labels[i].Text = existingFiles[i];
labels[i].Width = 330;
this.Controls.Add(labels[i]);
}
Say if fileCount equals to 100, it will make the form really big/long and won't be able to fit properly on most monitors.
Is there a way to make all dynamically generated checkboxes and labels all grouped in a area and just have the user be able to scroll? Something like a panel with scrolling? I don't know if there's anything like that.
I thought about using CheckedListBox, but doing that way I won't be able to make the filename a link. I want the user be able to click on the label and the file will be opened automatically, instead of selecting it.
Any help is appreciated!
Most controls have the AutoScroll property. Set this to true, and the control will automatically add a scrollbar when necessary. You can use the Panel control and add all of your links/checkboxes to that (if you don't want your whole form to scroll).
As we dynamically add controls to a web page, its location is automatically adjusted, one control will not place over another.
Can we do the same in windows Form Application.
I have to add dynamic label, textbox and buttons at last of an existing win form.
Take a look at the FlowLayoutPanel control.
Represents a panel that dynamically lays out its contents horizontally or vertically.
When you drop controls on the FlowLayoutPanel, it will take care of automatically spacing one from another. If you dock it to the form, such that it resizes with the form, then it will also handle moving controls to the next row / column as needed, so they don't become hidden beyond the boundaries of the form.
If you want to group some controls together, place them inside a Panel and then use that inside the FlowLayoutPanel. Here's some code to demonstrate:
for (var i = 0; i < 5; i++)
{
var panel = new Panel { BorderStyle = BorderStyle.FixedSingle, Width = 100, BackColor = Color.LightBlue };
panel.Controls.AddRange(
new Control[]
{
new Label { Text = "Title", Location = new Point(0, 0) },
new Label { Text = "Subtitle", Location = new Point(0, 25) }
});
flowLayoutPanel1.Controls.Add(panel);
}
How do I add padding, or some space between the textboxes when using dockstyle.top property?
for(int i =0; i< 10; i++) {
textboxes[i] = new TextBox();
textboxes[i].Dock = DockStyle.Top;
mypanel.Controls.Add(textboxes[i]);
}
The code above puts textboxes right beneath each other. Can't figure this out without using mass panels or fixed positioning. How to do the following?
1) I would like to add around 10-20pixels between boxes.
2) How to change size (height,width) of the textboxes, since when using dockstyle.top it ignores the size commands ?
With DockStype.Top you can't change the width of your TextBoxes, cause they are docked. You can only change the height. But to change the height of a TextBox you have to set the Multiline = true beforehand.
To get the space between the different boxes you have to put each TextBox within a panel, set the TextBox.Dock = Fill, the Panel.Dock = Top and the Panel.Padding = 10. Now you have some space between each TextBox.
Sample Code
for (int i = 0; i < 10; i++)
{
var panelTextBox = CreateBorderedTextBox();
this.Controls.Add(panelTextBox);
}
private Panel CreateBorderedTextBox()
{
var panel = CreatePanel();
var textBox = CreateTextBox();
panel.Controls.Add(textBox);
return panel;
}
private Panel CreatePanel()
{
var panel = new Panel();
panel.Dock = DockStyle.Top;
panel.Padding = new Padding(5);
return panel;
}
private TextBox CreateTextBox()
{
var textBox = new TextBox();
textBox.Multiline = true;
textBox.Dock = DockStyle.Fill;
return textBox;
}
What i forgot, you can also give a try to the FlowLayoutPanel. Just remove the DockStyle.Top from the panels and put them into the FlowLayoutPanel. Also you should set the FlowDirection to TopDown. Maybe this can also help you to solve your problem, too.
Another work around that suits smaller layouts is to just add a Label control afterwards also docked to the Top, which is not AutoSized, Text=" ", Height=your padding. This is quite useful for the odd bit of padding when using the designer.
I know where you're coming from, this is especially frustrating after returning to WinForms from WPF.
I would suggest using a TableLayoutPanel, in which each TextBox would get its own cell, and adjusting the properties of the cells. This should solve both your padding and size problems.
Another alternative would be to use some more complex layout controls, such as the DevExpress ones (not free).