I need to create a new textbox every time I click a button. I see how it will work once, but not multiple times.
TextBox NewTB = new TextBox();
NewTB...// set textbox properties
this.Controls.Add(NewTB);
I need NewTB to be different everytime I click the button (NewTB1, NewTB2, etc), I tried a List<> that contained the names I wanted, then assigned the name as the List<> member, but that didn't work. Can I use some type of List<> that contains TextBoxes? I'm not really sure how to implement that.
The name "NewTB" in your example is just a variable name. It is not assigned to that textbox in any way. The "list" of textboxes resides within the control structure. In other words, when you say this.Controls.Add(NewTB), you are adding that textbox to the list of controls.
If the code that you show us happens as part of a click handler, it will be run each time the button is clicked, and therefore a new textbox will be added each time. this.Controls is essentially the List that keeps track of the controls (including textboxes) on your form.
If you want to maintain the ability to reference the textbox, you will need to you a list (which will give you the ability to create an indefinite number of them), and then add a reference to a new textbox the list every time you add the same reference to the control. Every time you click the button, it should set your textbox to a new instance of textbox, and then add the reference of that instance to both the control and the list.
EXAMPLE:
To make the TextBoxen:
boolean iNeedMoreTextBoxes = true; //A simple boolean to be changed when you want
//want to stop adding TextBoxes
List<TextBox> textBoxes = new List<TextBox>(); //This makes a list of TextBoxes
TextBox tb = new TextBox(); //tb is nothing more than a pointer to the new TextBox
while(iNeedMoreTextBoxes){
textBoxes.add(tb); //The pointer is added to the List
control.add(tb); //The same pointer is added to the control
tb = new TextBox(); //Make another TextBox
iNeedMoreTextBoxes = checkToSeeIfINeedMoreTextBoxes();
}
Ok, so what that did was make a bunch of objects that and give a reference of each of those objects to the List and the control. Now, whenever you use the List's reference to change the object, the control will change as well, because it has a reference to the same object. Thus,
To retrieve the TextBoxen:
for(int i = 0; i < testBoxes.length(); i++){
textBoxes.get(i).makeChanges(); //makeChanges isn't really a function, just an example
}
Now, if you need to be able to make a change to one specific TextBox, the TextBox class MUST have some identifying field, and then you would likely use this:
int id = getTheIDofTheTextBoxINeed(); //this can be any identifier that you can check
for(int i = 0; i < testBoxes.length(); i++){
if(textBoxes.get(i).getID() == id) //Yay we found the right one, now make the changes
textBoxes.get(i).makeChanges();
}
And that's more or less how you do it.
EDIT: This is java code, because I am not very familiar with C#. However, I do know that underlying principles apply in both languages, just some of the syntax is different.
Related
I'm making an app which uses a checkbox list. Each item has to have a "description", so I decided to make it with a HelpProvider. But the problem is that when I make a loop that should fill all the checkboxes in checkbox list with a helprovider, Visual tells me that it is an object which cannot be converted into System.Windows.Forms.Control
Any ideas for a workaround?
for (int i = 0; i < CheckedListBox.Items.Count; i++)
{
this.AdditionalInfos.SetShowHelp(CheckedListBox.Items[i], true);
this.AdditionalInfos.SetHelpString(CheckedListBox.Items[i], "example description");
}
So, the reason you get that error is because and SetShowHelp and SetHelpString expect a Control object (a Button, a Label, etc...) but you're giving it a string which can't be handled by the HelpProvider.
I believe that in order to do what you want to do, you'll have to write a custom thing (since the elements of the CheckBoxList aren't Controls). You can either write a "complex" thing that can show descriptions on hover or you can just listen to the SelectedIndexChanged and show a description on a label or something.
So I want to be able to pass a combobox from one form to another as its the only things that remains the same. When I do it, is passes fine, has the correct items, however when I open the drop down there are no items, any idea why?
Hmmm, I don't know why that is, but what you might try doing is the following:
Rather than just passing in the entire combobox, just pass in the items from the previous combobox, and then make a new combobox on the form you are trying to pass it to, then populate it with the items you previously passed in as a parameter. Hope this helps!
I have now tried doing this and it now contains the items as it should
foreach (var loc in locations.Items)
Location_Selector.Items.Add(loc.ToString());
Location_Selector.SelectedIndex = locations.SelectedIndex;
But just setting one combo box to equal the other does not work, which makes no sense to me
Location_Selector = locations;
It is probably just easier to pass the items like this:
List<String> items = new List<string>();
items.AddRange(comboBox1.Items.Cast<String>());
int index = comboBox1.SelectedIndex;
Form2 form2 = new Form2();
form2.comboBox1.Items.AddRange(items.ToArray<object>());
form2.comboBox1.SelectedIndex = index;
form2.Show();
So you'd get the items to a list, then access a combobox on the next form and add the list to it. This will also copy the selected index too.
You could copy the ComboBox over, but it's more practical to just copy the items over.
I am creating a windows form app with the following goal:
get a list of products, each with a unique name and a category (from an enumerated list) from a user (and then do some things after, but this is not relevant to the question).
The idea is I would like to have the user specify they would like to configure "n" products by entering a value in a text box. I have the event handler for the text box calling a method which sets a variable to this value n. This value, "n", will be used as the loop counter, or what have you - the point is it will create the bound for the number of boxes to create.
I would then like to add (dynamically based on n), n number of (text box / combo box) pairs to the form. If there is no room to add another (text box / combo box) pair below the last one created, it should create another column.
n is unbounded, but, realistically, will likely never exceed 20. In any event, I'd like to be able to handle it if there are more products than this.
the options in the combo box will be filled from a string list that is passed in at run time, but will be consistent per box, per instance of this Form application.
i tried to enter a mock up image but stack overflow won't let me until i have earned some reputation points :(
I understand how to create a number of boxes using something like the code below, but its the finer points i'm stuck on. Can anyone help?
thanks!
` private void Method1()
{
int boxes = Int32.Parse(NumProducts.Text);
for (int i = 0; i < boxes; i++)
{
TextBox tb = new TextBox();
tb.Location = new System.Drawing.Point(40, i * 20);
tb.Name = "TextBoxName" + i.ToString();
tb.Size = new System.Drawing.Size(184, 20);
tb.TabIndex = i + 2;
tb.Text = String.Empty;
panel1.Controls.Add(tb);
}
}
private void NumProducts_TextChanged(object sender, EventArgs e)
{
Method1();
}`
Sounds to me like a DataGridView would be the better choice here. You can configure it with a DataGridViewTextBoxColumn as the first column and a DataGridViewComboBoxColumn for the second. It supports a "new row" as the last item.
Read the docs. Drop one on a form and play with it.
Asking the user for the number of rows in advance is not very good from a usability viewpoint.
You should rather create an interface that keeps creating new boxes as the user inputs things, either by having a "new row" row that activates when the user types something into it (the empty row isn't saved) or by having a "new row" button.
To achieve the layout, use a FlowLayoutPanel control, and add the controls to this instead of to the panel as you are already doing. That should transparently take care of the columns issue, and add scroll bars if the user goes beyond your anticipated maximum number of edit boxes. General info on the FlowLayoutPanel here (as well as many others).
I want to make a gui for what i explained here C# visual control for editing statements / equations / conditions?
Basically its an expression editor. Each expression consists of a list of stuff, which can be a text string or a parameter. For example, an expression:
If x is greater than 0
consists of:
String "If"
Parameter "variable" (= "x")
String "is"
Parameter "comparator" (= "greater than")
Parameter "value" (= "0")
So, when user wants to edit such expression, i must create (dynamically) five labels, and place them inside the control (Panel) and add onclick events to those of them that arent just strings, so that user can open a window to change the comparator or the variable name etc. The labels must obviously arrange themselves inside the control they are bound to.
Thing is, i dont know if there is already a way to do it automatically. I'd like those labels to arrange themselves just like the words arrange on this page. While it fits, put it to the right of the previous label, when it doesnt, put it on the start of the next row.
Do i have to manually move them OnResize() of the control they are in, or is there an automated way to do it?
Thanks!
Try using a FlowLayoutPanel
//Sample:
//Assuming you are creating your labels from
//List<string>
List<string> labels=new List<string>();
labels.Add("If");
labels.Add("variable");
labels.Add("=");
labels.Add("5");
for (int i = 0; i < labels.Count; i++)
{
Label lbl = new Label();
lbl.Text = labels[i];
flowLayoutPanel1.Controls.Add(lbl);
}
Take a look a the FlowLayoutPanel.
From the docs:
The FlowLayoutPanel control arranges its contents in a horizontal or
vertical flow direction. Its contents can be wrapped from one row to
the next, or from one column to the next. Alternatively, its contents
can be clipped instead of wrapped.
I am dynamically adding a textbox to certain rows (one column only) of a gridview. I add the controls with this insdie of a test condition (works fine):
TextBox txtASIN = new TextBox();
txtASIN.ID = "TxtASIN" + e.Row.RowIndex;
e.Row.Cells[4].Controls.Add(txtASIN);
int i = e.Row.Cells[4].Controls.Count; //TEST: This returns 1 correctly
I want the user to be able to enter values into one or more of these textboxes and then update the database with a single button click (not one click for each row). The problem I'm having is how to access those values on a button click event. I did a simple test this way to try to see the value in the second row but get null in temp1 (I am certain there is a value entered in that textbox):
protected void btnUpdate1_Click(object sender, EventArgs e)
{
TextBox temp = (TextBox)GridView2.Rows[1].FindControl("txt1");
string temp1 = temp.Text;
int i = GridView2.Row.Cells[4].Controls.Count; //TEST: This returns 0 incorrectly }
Once I can make this work, I can iterate through the rows and do what I need to do with the values. I don't know if the text entered in the textbox is actually readable without a postback but I'm otherwise stumped. Open to better suggestions on how to do this.
Thanks.
EDIT: Here is where I am now. I can see the textboxes in my column fine. I put a break in on a button that attempts to read them and this is what I'm seeing. If I check GridView2.Rows[0].Controls.Count, I get 8, which is the correect number of columns. If I check GridVeiw2.Rows[0].Cells[4].Controls.Count, I get 0, which is wrong because the textbox is there. I can get a Count of 1 right after I dynamically create it but not when I perform a subsequent button click.
Can anyone explain this? I feel if I can get past this holdup, I can get the rest done.
Thanks again.
You need to assign an ID to the TextBox controls and then access them by that ID in FindControl(). Also, make sure you're adding the controls in the Page's Init() method of the life-cycle. That way it gets added to ViewState.
TextBox txt1 = new TextBox();
txt1.ID = "txt1";
e.Row.Cells[4].Controls.Add(txt1);
EDIT: I just remembered another possible solution. Instead of programatically creating the TextBox controls in the code-behind just create a TemplateField in the GridView.
Add Textbox TemplateField Column To GridView Programmatically
I would try a different approach, putting the text box in the html markup of the page and then control the visible or readonly property of it on the ItemDataBound event. That way, the control will always be there and you don't have to worry about the lifecycle stuff.