Add text box with corresponding combo box dynamically - c#

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).

Related

How to output and input values of textboxes / comboboxes in wpf

So I made a program that contains a lot of textboxes and comboboxes for some calculations. The program has an Output button and an Input button. At the moment I have managed the Input through skipping lines and inserting the information like this:
ComboBoxes like this.
if (File.ReadLines(filename).Skip(23).Take(1).First() == "TEMP")
{
TEMP5.SelectedIndex = 2;
}
Textboes like this.
TEMP1.Text = File.ReadLines(filename).Skip(25).Take(1).First();
and the Output is just a massive block of Output containing newlines
System.IO.File.WriteAllText(filename,bla bla bla
Is there a better way?? There has to be.
EDIT: So one button "Output" saves all data contained in textboxes and comboboxes in a txt file.
The "Input" button makes you able to choose the txt file and copy the data into the boxes.
I usually find that if someone has to name boxes "Box1", "Box2", "Box3"... "Box99" then their doing something wrong. Unless each value has a specific, unique calculation that needs to be done with it, you can usually make things cleaner with a list.
In WPF, you can use ItemsControls like DataGrid to generate rows of TextBoxs that will link back to your list with data binding. If that looks like something that might fit, I would highly recommend looking into it. It will save you a lot of work in the long run.
That being said, if you do have a series of controls named consecutively ("Box1", "Box2", "Box3", etc), you can use FindName() to access them dynamically:
var outputBuilder = new StringBuilder();
for (int i = 1; i < 100; i++)
{
ComboBox box = (ComboBox)FindName("TEST" + i.ToString());
outputBuilder.AppendLine(box.Text);
}
System.IO.File.WriteAllText(filename, outputBuilder.ToString());

Is there any Efficient way to display lots of labels in form?

I have a GUI Program, that creates labels containing names of files according to the search query provided by the user at runtime and displays them. The no of labels displayed can vary considerably based on the user input.
The no can vary between 0 to 2000(approx) . When the no of labels exceed 1000 or so, the time taken for the form in which the labels are contained takes a lot of time to display.
The time taken to display the form completely outweighs the time saved in making a good algorithm(for some cases)!. I am looking for an efficient way so that I can display the form easily in less amount of time. Currently, It takes 1minute 45 seconds to display a form containing 1499 Labels.
Currently , I am doing like this:-
foreach(string Elements in FileList)
{
Label LabelA = new Label() ;
// other code here to modify the appearence of label
LabelA.Show() ;
}
MyForm.Show();
// File List is the List of file names which are to be displayed.
//MyForm is the name of the form in which labels are added at runtime.
There could be at least a couple of techniques:
it's technically impossible that one can look on all of them contemporary, so solution is just devide them into Tabs. So divide them into groups of your application logic.
defered scrolling. So when user scrolls the window, only the data inside them changed (and also corresponding data field)
Just to give an idea, but basically to invite attention to a simple fact that you for sure do need all that controls at once on UI. If these solutions are not ok, change control, so rapresentation of data.
Asyn get result Maybe you can use BackGroundWorker to asynchronously query the result and create the label. The way will give you a well user experience .
Suspend then Resume When you add the label you should use Control.SuspendLayout() and Control.ResumeLayout()
Page the Result Other way you can page for the result.
If you want to use labels with that create labels on program startup and add them a list for instant access to them
// create a list on there
List<Label> lblList = new List<Label>;
public Form1()
{
InitializeComponent();
for(int i = 0 ; i<1500;i++)
{
Label LabelA = new Label() ;
// other code here to modify the appearence of label
LabelA.Show() ;
lblList.Add(LabelA);
}
}
if you do this on a backGroundWorker your program will open fast and you can make a prograss bar for label creation. this will create labels and add them a list. You can access them with their indexes and change their text like that:
int index=0;
foreach(Label o in lblList)
{
o.Text="Text";
index++;//you can use this index if you want to know which label you editing
}
if you create labels on start up this will take some time but when you use them this way will be faster from creating them and values will display instantly.
Sorry for bad english.

C# WinForms need to automatically align a set of labels inside a control in a simple topleft fashion

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.

Problem with ComboBox autocomplete when adding values dynamically

In WinForms application, I have a combobox which I am trying to populate with values based on user input. For example if the user types m it should show him all the values that starts with the letter m, but I dont want to add all the values in the beginning because there are a lot of values.
To achieve this, I created an event textchanged and when a user inputs for example the letter m my program goes to my database and adds all the values with the letter m to the combobox.
The problem that I think that the combobox first sees if it should autocomplete (suggest) values and only after that it adds the values.
How can I make it add the values first or make the combobox check again if it should suggest values?
Here is my code:
private void comboBox1_TextChanged(object sender, EventArgs e)
{
comboBox1.Items.Clear();
for (int i = 0; i < MilkProducts.Length; i++)
{
if (MilkProducts[i].StartsWith(comboBox1.Text))
{
comboBox1.Items.Add(MilkProducts[i]);
}
}
}
It seems you may have to use Win32 API (using PInvoke) here by sending appropriate message to the Combo box to show the search result "after" the event handling is done
Please refer to the below URL and you may find the what you are looking for:
http://msdn.microsoft.com/en-us/library/bb775792(VS.85).aspx
i think problem is you are clearing all the items in ComboBox at comboBox1.Items.Clear() and then accessing its contents at comboBox1.Text may be you should try doing it differently. or clear it at the end.

Read a dynamically created textbox in a Gridview

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.

Categories