I have used a button for creating a set of textboxes as follows:
public partial class Form1 : Form
{
private int a = 75;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox1.Location = new System.Drawing.Point(50, a);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;
this.Controls.Add(this.textBox1);
this.textBox2 = new System.Windows.Forms.TextBox();
this.textBox2.Location = new System.Drawing.Point(200, a);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(100, 20);
this.textBox2.TabIndex = 0;
this.Controls.Add(this.textBox2);
this.button1.Location = new System.Drawing.Point(650, a);
a += 25;
}
}
So there might be created many textbox1 and textbox2 for many button clicks. Say 10 textbox1 and 10 textbox2. How can I get data from all of them and to store in database. each textbox1 and textbox2 to be in a row of table?
Any help will be welcomed.
First of all: I think you are looking for a DataGrid.
If not, there are several steps to be taken. First of all, textbox1 and textbox2 are members of the class and not the method, so with every click you edit the same TextBoxes again and again. To create new TextBoxes use
TextBox newBox = new TextBox();
inside the method and continue using it instead of this.textbox1 (or textbox2). Keep in mind, that you should change to Location of the TextBoxes every time you click the button so that they don't overlap. You could use a class variable as click count.
I think the easiest way would be to store the created TextBoxes in a collection, for example a Dictionary:
public partial class...
{
Dictionary<TextBox, TextBox> tbPairs = new Dictionary<TextBox, TextBox>();
private void button1_Click(...)
{
... //create newBox1 and newBox2
tbPairs[newBox1] = newBox2; //adds the Pair to the Dictionary
}
}
To recall the content of the Dictionary after the TextBoxes are filled use
foreach (KeyValuePair<TextBox, TextBox> in tbPairs)
{
... //write to Server here - but that is an issue too big for handling here - look it up
}
For how to write Data to a database check out how to use SqlCommands
Related
I'm creating a ComboBox control using ToolStripControlHost and ToolStripDropDown that can host any kind of control in the DropDown window. For example, the DropDown window might display a listview or treeview or even another usercontrol.
I'm posting a simplified code below where dropdown host a usercontrol with a listview and a button like this:
The problem occurs when the control is positioned at the bottom of the screen in such a way that the dropdown window will extrapolate the lower boundary of the screen. When this occurs, the dropdown ends up hiding the control.
In this case, I'd like to fix the _dropDown.Show method call to show dropdown window as follows:
To repeat the problem, just run the code below and drag the window to the bottom of the screen and open the dropdown.
using System;
using System.Windows.Forms;
public class CustomComboBox : UserControl
{
ToolStripDropDown _dropDown;
public CustomComboBox()
{
var textbox = new TextBox();
textbox.Location = new System.Drawing.Point(0, 0);
textbox.Size = new System.Drawing.Size(this.Width - 22, 20);
textbox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
this.Controls.Add(textbox);
var button = new Button();
button.Location = new System.Drawing.Point(this.Width - 22, -1);
button.Size = new System.Drawing.Size(22, 22);
button.Text = "\u2BC6";
button.Anchor = AnchorStyles.Right | AnchorStyles.Top;
button.Click += new System.EventHandler(this.Button_Click);
this.Controls.Add(button);
var dropDownControl = new DropDownControlTest();
var controlHost = new ToolStripControlHost(dropDownControl);
_dropDown = new ToolStripDropDown();
_dropDown.AutoSize = true;
_dropDown.Items.Add(controlHost);
}
void Button_Click(object sender, EventArgs e)
{
_dropDown.Show(this, 0, this.Height);
}
}
public class DropDownControlTest : UserControl
{
public DropDownControlTest()
{
var listview = new ListView();
listview.Location = new System.Drawing.Point(3, 1);
listview.Size = new System.Drawing.Size(400,300);
listview.View = View.Details;
listview.Columns.Add("Col 1",100);
listview.Columns.Add("Col 2",100);
this.Controls.Add(listview);
var button = new Button();
button.Location = new System.Drawing.Point(3, 305);
button.Text = "More...";
this.Controls.Add(button);
}
}
public class Form1 : Form
{
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public Form1 ()
{
CustomComboBox ccBox = new CustomComboBox();
ccBox.Location = new System.Drawing.Point(10, 10);
ccBox.Height = 20;
this.Text = "Test CustomComboBox";
this.Controls.Add(ccBox);
}
}
You can use the ToolStripDropDown.Show Method (Control, Point, ToolStripDropDownDirection) overload to control the drop direction. The code will need to perform bounds checking to decide whether to place the dropdown above or below the textbox.
The following is a simplistic method for doing the bounds checking and was only tested on a single screen configuration.
First, make textbox a class level variable.
private TextBox textbox;
public CustomComboBox()
{
//var textbox = new TextBox();
textbox = new TextBox();
The display logic is as follows.
void Button_Click(object sender, EventArgs e)
{
Point textBoxScreenLocation = textbox.PointToScreen(textbox.Location);
// try to position _dropDown below textbox
Point pt = textBoxScreenLocation;
pt.Offset(0, textbox.Height);
// determine if it will fit on the screen below the textbox
Size dropdownSize = _dropDown.GetPreferredSize(Size.Empty);
Rectangle dropdownBounds = new Rectangle(pt, dropdownSize);
if (dropdownBounds.Bottom <= Screen.GetWorkingArea(dropdownBounds).Bottom)
{ // show below
_dropDown.Show(pt, ToolStripDropDownDirection.BelowRight);
}
else
{ // show above
_dropDown.Show(textBoxScreenLocation, ToolStripDropDownDirection.AboveRight);
}
}
}
I can not comment that is why I am answering your question. You can use the reflection and then re-position you control. I have found a custom combobox control same as you developed. Please check this. At least, you will get some idea what you need to do.
I am trying to remove textboxes and labels one by one by pressing a button.
I have a list of textboxes called inputTextBoxes.
Here is the code for adding :
private void onClickAdd(object sender, EventArgs e)
{
inputTextBoxes = new List<TextBox>();
Label label1 = new Label();
label1.Name = "label1";
label1.Text = "w" + i;
label1.Location = new System.Drawing.Point(5, 10 + (20 * i));
label1.Size = new System.Drawing.Size(30, 20);
this.Controls.Add(label1);
TextBox text1 = new TextBox();
text1.Name = "text1";
text1.Location = new System.Drawing.Point(35, 10 + (20 * i));
text1.Size = new System.Drawing.Size(25, 20);
inputTextBoxes.Add(text1);
this.Controls.Add(text1);
i++;
}
For removing I am trying this :
private void onClickRemove(object sender, EventArgs e)
{
foreach(TextBox text1 in inputTextBoxes)
{
this.Controls.Remove(text1);
}
}
But it removes only the last textbox added,clicking againg on the button doesn't do anything.
You are constantly creating a new list in your OnClickAdd() method:
inputTextBoxes = new List<TextBox>();
Try to check if the inputTextBoxes is null and only then do this line of code. Otherwise, just let the rest of the code run.
Also, remember about clearing the inputTextBoxes list after the onClickRemove() method finishes removing textboxes/labels.
You want to remove only one TextBox at a time, why do you need a foreach loop? just grab the last or first TextBox and if it is not null remove it from the Controls:
private void onClickRemove(object sender, EventArgs e)
{
var textBoxToRemove = inputTextBoxes.LastOrDefault();
// or
// var textBoxToRemove = inputTextBoxes.FirstOrDefault();
if (textBoxToRemove != null)
{
this.Controls.Remove(textBoxToRemove);
inputTextBoxes.Remove(textBoxToRemove);
}
}
Make sure you remove it from inputTextBoxes also so the next time you will ask to remove a TextBox it will not try to remove it again and go on to the next one.
Edit
#Piotr Nowak has pointed one more problem you have, you allocate a new list for inputTextBox every time you add a new TextBox, you should allocate the list only once when you create your class.
Remove this from onClickAdd method:
inputTextBoxes = new List<TextBox>();
And use this when you declare the list as a field it your class:
private readonly inputTextBoxes = new List<TextBox>();
I have program with multi methods .
We create all the controls with methods .
One of methods is for creating textBox . It is like :
private TextBox textBox1;
public void CreateTextBox()
{
this.textBox1 = new System.Windows.Forms.TextBox();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(100, Position);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
Position += 30;
this.Controls.Add(this.textBox1);
}
There are several textBoxes in a form (the count of textbox might change between 10 to 20 ) .
So , If I want to create several textBoxes , Call methods like :
CreateTextBox();
CreateTextBox();
CreateTextBox();
If I want to have the Text of this textboxes , A code like this return me the last textBox Text :
MessageBox.Show(textBox1.Text);
My problem is ,,,, How can I detect the text of first called of CreateTextBox() and second called of CreateTextBox() ?
Thank u for read
You can use an array containing all TextBoxes:
var form = new Form();
var boxes = new TextBox[10];
for (int i = 0; i < boxes.Length; i++)
{
var box = new TextBox();
box.Location = new Point(10, 30 + 25 * i);
box.Size = new Size(100, 20);
form.Controls.Add(box);
boxes[i] = box;
}
var button = new Button();
button.Text = "Button";
button.Click += (o, e) =>
{
var message = String.Join(", ", boxes.Select(tb => tb.Text));
MessageBox.Show(message);
};
form.Controls.Add(button);
Application.Run(form);
I am trying to create a form for collecting information about an item. There are two types: default item and special item. The fields of item shows on the form by default.
public class Item
{
Id
Name
Quantity
Type //default, special
}
public class SpecialItem : Item //inherits from item
{
//extra fields here
ExpiryDate
SafeForChildren
}
How will I take the extra fields of SpecialItem to user.
I think the fields of SpecialItem should not show until the user indicates he wants to add special item by selecting the type.
I think of using a tab to show extra fields
A collapsible control - I don't if this exists
Hiding the controls and showing them when necessary
Any other idea
If the two class have a clear relation between them and this relation is well comprensible to your user, I think it's a good thing to show every field.
Put all the fields inside a groupbox and add two option buttons for the Item and SpecialItem class.
By default (at form load) the Item class will be selected and the two extra field are disabled.
If the user choose the SpecialItem class option button, enable the other two fields.
I have seen this behavior in many options dialogs when selecting an option will enable other specific options.
Try this out - it simply reflects the given type and then puts the controls onto a TableLayoutPanel adds a couple of buttons and then binds two event handlers to the click event of the buttons. It is by no means a masterpeice, but I think will get you started.
public MyForm(Type typeToDisplay)
{
InitializeComponent();
PropertyInfo[] settableProperties = typeToDisplay.GetProperties(BindingFlags.Instance | BindingFlags.Public);
TableLayoutPanel panel = new TableLayoutPanel();
panel.ColumnCount = 2;
panel.RowCount = settableProperties.Length+1;
panel.Name = "LayoutPanel";
this.Controls.Add(panel);
int rowIndex = 0;
foreach (PropertyInfo info in settableProperties)
{
Label propLabel = new Label();
propLabel.Text = info.Name;
TextBox propField = new TextBox();
panel.Controls.Add(propLabel, 0, rowIndex);
panel.Controls.Add(propField, 1, rowIndex);
rowIndex++;
}
panel.Controls.Add(new Button() { Text = "OK", Name="OK" }, 0, rowIndex);
panel.Controls.Add(new Button() { Text = "Cancel", Name="Cancel" }, 1, rowIndex);
panel.Controls["Cancel"].Click += new EventHandler(CloseForm);
panel.Controls["OK"].Click += new EventHandler(SaveChanges);
panel.Height = this.Height;
panel.Width = this.Width;
}
private void CloseForm(object sender, EventArgs e)
{
this.Close();
}
private void SaveChanges(object sender, EventArgs e)
{
MessageBox.Show("Save changes was clicked!");
this.Close();
}
Here is a full example solution to demonstrate my suggestion above. Note that it is all done in code and uses only a single column, but can work with designer-produced controls (of course) and multiple columns, too. Just be sure to set all the controls in a row (say, a label and its corresponding input control) to Visible = false to have the unused rows collapse properly.
TableLayoutPanel tlp = new TableLayoutPanel();
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));
tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));
TextBox b1 = new TextBox(); b1.Dock = DockStyle.Fill;
TextBox b2 = new TextBox(); b2.Dock = DockStyle.Fill;
TextBox b3 = new TextBox(); b3.Dock = DockStyle.Fill;
CheckBox special = new CheckBox(); special.Text = "Special?";
TextBox b4 = new TextBox(); b4.Dock = DockStyle.Fill; b4.Visible = false;
TextBox b5 = new TextBox(); b5.Dock = DockStyle.Fill; b5.Visible = false;
Button button = new Button(); button.Text = "Save";
special.CheckedChanged += new EventHandler((sender, args) => { b4.Visible = b5.Visible = special.Checked; });
tlp.Controls.Add(b1, 0, 0);
tlp.Controls.Add(b2, 0, 1);
tlp.Controls.Add(b3, 0, 2);
tlp.Controls.Add(special, 0, 3);
tlp.Controls.Add(b4, 0, 4);
tlp.Controls.Add(b5, 0, 5);
tlp.Controls.Add(button, 0, 6);
Controls.Add(tlp);
tlp.Dock = DockStyle.Fill;
tlp.BringToFront();
I have a little demonstration below of a peculiar problem.
using System;
using System.Windows.Forms;
namespace WindowsApplication1
{
public class TestForm : Form
{
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.TextBox textBox1;
public TestForm()
{
//Controls
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.textBox1 = new System.Windows.Forms.TextBox();
// tabControl1
this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(12, 12);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(260, 240);
this.tabControl1.TabIndex = 0;
this.tabControl1.Selected += new System.Windows.Forms.TabControlEventHandler(this.tabControl1_Selected);
// tabPage1
this.tabPage1.Controls.Add(this.textBox1);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Size = new System.Drawing.Size(252, 214);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "tabPage1";
// tabPage2
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Size = new System.Drawing.Size(192, 74);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "tabPage2";
// textBox1
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(6, 38);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(240, 20);
this.textBox1.TabIndex = 0;
// TestForm
this.ClientSize = new System.Drawing.Size(284, 264);
this.Controls.Add(this.tabControl1);
this.Name = "Form1";
this.Text = "Form1";
}
//Tab Selected
private void tabControl1_Selected(object sender, EventArgs e)
{
this.Text = "TextBox Width: " + this.textBox1.Width.ToString();
}
}
//Main
static class Program
{
static void Main()
{
Application.Run(new TestForm());
}
}
}
If you run the above C# code you will have a small form containing a tabcontrol. Within the tabcontrol is a texbox on the first tab. If you follow these steps you will see the problem:
Select tabPage2 (textBox1's width is reported in the form title)
Resize the form
Select tabPage1 (The wrong textBox1 width is reported)
Any ideas what is going on here? The textbox is obviously bigger than what is being reported. If you click again on tabPage2 the correct size is then updated. Obviously there is an event updating the width of textBox1. Can i trigger this when tabPage1 is selected?
Firstly, thanks for the complete program - it made it much easier to work out what was going on!
While the textbox isn't visible, it isn't resized. When you select tabPage1, the Selected event fires before the controls become visible and the textbox gets laid out again.
Now, that's why it's happening - but what's your real situation? If you actually want to capture the size of controls changing, subscribe to their Resize events. If not, could you explain more about what you're trying to achieve?
I'm pretty sure that what's happening is the Selected event is raised slightly before the tab page becomes visible. The text box is not resized until the tab page becomes visible, so you end up checking the value of the text box's size before it is actually resized. When you change tabs again, the text box is already resized, so you get the correct value.
Change the last few lines of your example form to look like this and it will become apparent:
this.textBox1.SizeChanged += TextboxSizeChanged;
}
//Tab Selected
private void tabControl1_Selected(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("tab selected");
this.Text = "TextBox Width: " + this.textBox1.Width.ToString();
}
private void TextboxSizeChanged(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Textbox resized");
}
If you modify your code a little by adding an event handler to the textbox1.Resize event you will see what happens.
The tabPage1.Selected event occurs before the controls in the tab page is resized so when you check the width of the textbox you are checking it before it is resized.
Normally this wouldn't be a problem, for the resizing is done properly afterwards, but I guess that you will be using the size of the textbox for something?
You should be able to write your own TabControl that fixes this problem, but you will have to experiment to see what works here.
Not sure if I understand the problem.
But, you might use textbox's resize event to capture the width change OR form's resize.
In your example, does the select event of tabPage1 fire when you do step 3?