c# using dynamic tools - c#

in c# form application, when i click the button i create a listBox.
and I add Item to the ListBox from a TextBox
When I click the button, I want the listBox to be created if it does not exist.
Therefore when assigning the ListBox creation code to an if block, the code to assign the data in the textBox to the listBox fails.
how can i fix this?
if (araclar_eklendi == false)
{
ListBox listB_X = new ListBox();
listB_X.******** = new Point(380, 45);
this.Controls.Add(listB_X);
araclar_eklendi=true;
}
listB_X.Items.Add(txtBox_X.text);

You can use foreach statement to traverse the form's Controls to check if a ListBox exists. And define a boolean to store the result.
Here is a demo you can refer to.
// bool to check if a listbox exists
bool flag = false;
private void button1_Click(object sender, EventArgs e)
{
Control control = new Control();
// traverse the form
foreach (Control c in this.Controls)
{
if (c is ListBox)
{
control = c;
flag = true;
break;
}
}
if (flag) // if true, access the listbox and add new item from tb
{
((ListBox)control).Items.Add(textBox1.Text);
}
else // if false, create a new listbox
{
ListBox listBox = new ListBox();
listBox.Location = new Point(380, 45);
this.Controls.Add(listBox);
listBox.Items.Add(textBox1.Text);
}
}

Related

Can't raise click event of a UserControl in C#

I have a dynamically added UserControl:
var listItem = new ListItem(/* arguments */);
listItem.Click += SetListItemColor;
panel.Controls.Add(listItem); // "panel" is FlowLayoutPanel
SetListItemColor:
private void SetListItemColor(object sender, EventArgs e)
{
var listItem = (ListItem)sender;
if (listItem.BackColor == Color.LightGray)
{
listItem.BackColor = Color.White;
}
else
{
listItem.BackColor = Color.LightGray;
}
}
No change to the color happens when I click on the UserControl. However, for test purpose, I tried to change the event to EnabledChangedand change the Enabled property, the color does change:
var listItem = new ListItem(/* arguments */);
listItem.Enabled = false;
listItem.EnabledChanged += SetListItemColor;
listItem.Enabled = true;
panel.Controls.Add(listItem);
What's the problem?
EDIT:
Since docking doesn't work in a FlowLayoutPanel, suggest setting the size of your control to the size of the panel. Set the ListItem margins to empty as below to get maximum fill. For debugging set the backcolor different to make sure you can see it:
var listItem = new ListItem(/* arguments */);
listItem.BackColor = Color.Yellow; // Debugging only
listItem.Margin = Padding.Empty;
listItem.Size = panel.Size;
listItem.Click += SetListItemColor;
Note that if the control is resized you will need to resize your ListItem again.

How to save data to a text file from several text boxes to a text file

I am developing awindows form application with one button. Each time I press the button it will generate text boxes. For example if I click that button 5 times, 5 text boxes will be there. Now user will enter data to those text boxes. And when he will press enter(another button) it has to store to a text file. I struct at this point as I am generating text boxes during run time.
Can any one help me out.
my code is
private void create_pos(object sender, EventArgs e)
{
counter_1++;
if (counter_1 == count)
{
left += 300;
top = 50;
count = count + 25;
}
List<Button> buttons = new List<Button>();
Button newButton = new Button();
buttons.Add(newButton);
this.Controls.Add(newButton);
newButton.Left = left;
newButton.Top = top;
TextBox newtextbox = new TextBox();
Controls.Add(newtextbox);
if (counter_1 == 100)
{
button1.Enabled = false;
}
newtextbox.Left = left + 100;
newtextbox.Name = "text" + counter_1;
// TextWriter tsw = new StreamWriter(#"d:\test.txt", true);
//tsw.WriteLine(newtextbox.Text);
// tsw.Close();
newtextbox.Top = top;
top += newButton.Height + 2;
newButton.Text = "position" + counter_1;
textBox1.Text = newtextbox.Name;
}
private void Save_Click(object sender, EventArgs e)
{
foreach (Control item in Controls)
{
if (item.GetType() == typeof(TextBox))
{
savetext[counter_1] = item.Text.ToString();
}
System.IO.File.WriteAllText("d:\\test.txt", savetext.ToString());
}
}
I would keep track of your dynamic text boxes so that you can differentiate between the ones you are concerned with now and any other text boxes that might already be on the form, or that you might add later. I'll assume that, as you generate a TextBox and add it to the form, you also store a reference to it in a list, e.g.
List<TextBox> dynamicTextBoxes = new List<TextBox>();
In the event handler for the Enter key (or any other event handler that you want to trigger the writing), you can gather the text from the controls and write it out. It isn't clear exactly what your requirement is here, so let's write a function that accepts a list of TextBox and a file name to write the text to, one line at a time
private void WriteTextBoxes(string path, List<TextBox> textBoxes)
{
// Here we use some Linq to quickly get all of the text, but you could
// also use an explicit loop
string text = string.Join(Environment.NewLine, textBoxes.Select(t => t.Text));
File.WriteAllText(path, text);
}
You could then call that method from your event handler, passing in the list of dynamic TextBox controls
WriteTextBoxes(#"C:\Temp\My.txt", dynamicTextBoxes);
what you want to do is, Iterate through the child controls of type TextBox then Collect its Texts and make a string with those collected values. Now you have the text to write to the file and a path of the file. Then you can use File.WriteAllText method to perform the action:
StringBuilder contentBuilder = new StringBuilder();
foreach (TextBox dynamicText in this.Controls.OfType<TextBox>())
{
contentBuilder.AppendFormat("Text in {0} is {1} \n", dynamicText.Name, dynamicText.Text);
}
string pathOfFile = #"path here";
System.IO.File.WriteAllText(pathOfFile,contentBuilder.ToString());
Find the controls on your form using this.FindControl method and check if it is text box. If it is text box read the content using its .Text property. Use loop to iterate through the controls.
If you are not mainting a list of generated controls then do this:
string filePath = "path to text file";
StringBuilder contentBuilder = new StringBuilder();
foreach (Control item in Controls)
{
//i don't remember if this check would work. if it doesn't work try item.GetType() == typeof(TextBox)
if (item is TextBox)
{
contentBuilder.Append(((TextBox)item).Text);
}
}
string content = contentBuilder.ToString();
if(!string.IsEmptyOrWhiteSpace(content))
{
using(StreamWriter writer = new StreamWriter(filePath))
{
//check if Write or WriteLine or something else would work.
writer.Write(content);
}
}
if you are using list to maintain the generated controls then just change the for part of the loop.

C# Win Forms issues deleting dynamically created controls

I have a function that reads info from a db and dynamically creates checkbox controls when a menu item is selected from a combobox.
When the user selects a different item from the combobox, I am attempting to delete any existing checkboxs already on the page. However, the delete function only deletes every other checkbox. Any idea what im doing wrong?
The form is super basic, just one form, no tabs, only this single combobox and the dynamically created checkboxes.
private void serverModels_SelectedIndexChanged(object sender, EventArgs e)
{
DeleteBoxes();
List<string> eqpIDs = new List<string>();
try
{
DataExtractor dataExtract = new DataExtractor(DataBase.TCDBServerName, DataBase.TCDBname, DataBase.TCDBUserID, DataBase.TCDBPassword);
eqpIDs = dataExtract.GetToolsByServerModel(Convert.ToString(serverModels.SelectedItem));
}
catch (Exception ex)
{
Logger.InsertSystemLog(e.ToString());
MessageBox.Show(ex.ToString());
return;
}
for(int i = 0; i < eqpIDs.Count; i++)
{
CheckBox box = new CheckBox();
box.Checked = true;
box.Tag = "TOOL";
box.Text = eqpIDs[i];
box.AutoSize = true;
box.Location = new Point(50 + 75 * (i / 17), (i % 17) * 25 + 120);
this.Controls.Add(box);
}
}
private void DeleteBoxes()
{
foreach (Control c in this.Controls)
{
if (c is CheckBox && c.Tag.ToString() == "TOOL" )
c.Dispose();
}
}
Dispose is removing the control from the Controls collection as well as disposing of the control.
As noted here,
When a Control is removed from the control collection, all subsequent controls are moved up one position in the collection.
That is why your logic is skipping every other CheckBox.
Try using a for loop in reverse like this:
for (int ii = Controls.Count - 1; ii >= 0; ii--)
{
if (Controls[ii] is CheckBox && Controls[ii].Tag.ToString() == "TOOL")
Controls[ii].Dispose();
}
This appears to be happening because you are modifying your control's Controls collection while iterating over it. Try something like this instead:
private void DeleteBoxes()
{
List<Control> toDispose = new List<Control>();
foreach (Control c in this.Controls)
{
if (c is CheckBox && c.Tag.ToString() == "TOOL" )
toDispose.Add(c);
}
foreach (Control c in toDispose)
{
c.Dispose();
}
}

Assign checkboxes to an checkbox-array using a for loop in C#

I'd like to do this:
CheckBox[] boxarray = new CheckBox[4];
boxarray[0] = checkBox1;
boxarray[1] = checkBox2;
boxarray[2] = checkBox3;
boxarray[3] = checkBox4;
using a for loop - because I have about 600 checkboxes. I thought about this:
for (int i = 0 ; i<= 600; i++)
{
boxes[i] = checkBox[i] ;
}
But whatever I tried - it didn't work. I hope you know what I mean.
Thanks for your help!
If you have these CheckBoxes on your form, then you can add them to an array (or List, which would be much easier to do) like that:
List<CheckBox> checkBoxesList = new List<CheckBox>();
foreach (Control ctrl in FormName.Controls)
{
if (ctrl.GetType() == typeof(CheckBox))
{
checkBoxesList.Add(ctrl as CheckBox);
}
}
Remember, simply writing:
checkBox1, checkBox2
won't make it possible to get them like checkBox[0] - it's not an array, it's just a name with '1' or '2' in the end.
Using the current setup, you'll have to use FindControl (assuming ASP.net, winforms and WPF work differently):
for(int i = 0; i <= 600; i++)
{
boxes[i] = Page.FindControl("checkbox" + i);
}
Update for windows forms: There is actually a method you can use to find all controls of a specific type:
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 :)
If you have other checkboxes on your form that you don't want to add, you'll have to use the following method:
for(int i = 0; i <= 600; i++)
{
boxes[i] = this.Controls.Find("checkbox" + i, true).FirstOrDefault() as CheckBox;
}
you are not able to specifiy the name of the checkboxes in the code like you have done, because i wont get changed.
you have to create new instances of CheckBox like:
for (int i = 0 ; i<= 600; i++)
{
//This will create a new instance of a CheckBox
CheckBox cb = new CheckBox()
//At this point the checkbox is empty and not visible anywhere
//So you have to change some properties:
cb.Text = "Check me!";
cb.Top = Ycoord; //you should change this depending on i like +(i*30)
cb.Left = Xcoord;
cb.name = "checkbox" + i.toString();
//To recognize if one of your Checkboxes is checked/unchecked you need to add
//an event like this (for the event see down below)
cb.CheckedChanged += checkedChangedEvent;
//then you need to add the checkbox to your Array
boxes[i] = cb;
//to make those checkboxes visible you need to add them to your form
//or Panel:
myForm.Controls.Add(cb);
}
The Event:
public void checkedChangedEvent(Object sender, EventArgs e)
{
MessageBox.Show(((CheckBox)sender).name + " is now Checked == " + ((CheckBox)sender).Checked.toString();
}
you have to specify which Checkbox was Checked/Unchecked by its name, because every CheckBox is firing the same event.
EDIT2:
to get the number of the checkbox you can do something like this in the event:
int cbNumber = 0;
try
{
cbNumber = System.Convert.toInt32(((CheckBox)sender).name.Replace("checkbox",""));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n\n" + ex.StackTrace);
}

How to change properties of a Control that is in List<UIControl> without using Loop?

I have the following code where a click event will dynamically create additional Canvas to the WrapPanel, and each Canvas contains a TextBox and a Button. Once the Button on one Canvas is click, TextBox.Text and Button.Content change from "Foo" to "Jesus".
The below code works, but it's not ideal. Because each property Change ("Foo" to "Jesus), I have to run a loop. I have to run two loops just to change the text on the TextBox and Button. Is there a direct way to change the Properties other then a Loop? My actually application contains 30+ controls in a Canvas, I don't want to run 30+ loops each time just to change some text.
List<Canvas> cvList = new List<Canvas>();
List<TextBox> tbList = new List<TextBox>();
List<Button> FooList = new List<Button>();
WrapPanel wp = new WrapPanel();
private void createbtn1_Click(object sender, RoutedEventArgs e)
{
Canvas cv = new Canvas();
StackPanel sp = new StackPanel();
TextBox tb = new TextBox();
Button Foo = new Button();
sp.Orientation = Orientation.Vertical;
sp.Children.Add(tb);
sp.Children.Add(Foo);
cv.Children.Add(sp);
wp.Children.Add(cv);
cvList.Add(cv);
tbList.Add(tb);
FooList.Add(Foo);
cv.Width = 100;
cv.Height = 100;
tb.Text = "#" + (cvList.IndexOf(cv)+1);
tb.Width = 50;
tb.Height = 30;
Foo.Content = "Foo";
Foo.Click += destroy_Click;
}
private void Foo_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
var bIndex = FooList.IndexOf(b);
foreach (TextBox t in tbList)
{
if (tbList.IndexOf(t) == bIndex)
{
t.Text = "Jesus";
}
}
foreach (Button f in FooList)
{
if (FooList.IndexOf(t) == bIndex)
{
t.Content = "Jesus";
}
}
}
Just access the text boxes by index and set the content of the button directly:
if(bIndex < tbList.Count && bIndex != -1)
tbList[bIndex].Text = "Jesus";
if(b != null && bIndex != -1)
b.Content = "Jesus";
why can't you just get the item at the index and set that items text:
tbList[bindex].Text="Jesus";
As for setting the buttons content, you already have the button from the click event, so just use that:
b.Content = "Jesus";
You current code just loops through each item in the list and gets the index of the item and sees if it is the index you want. Accessing by the indexer of the list directly will give you what you want.
You will probably want to do some error checking, but that is not currently done in your existing code either.
Some info on using indexers from MSDN

Categories