Accessing programmatically created controls - c#

I've created a series of Panels within a placeholder, inside each panel is 5 textboxes.
On a button press, I want to get the .Text from each Textbox, and the ID of the Panel. I planned to use a JaggedArray to keep track of all Panels and their internal TextBoxes.
string[][] jaggesaddress = new string[stop][]; //stop is an int and equal to amount of panels on screen.
String[] numbers = new String[stop];
int a = 0;
//Control ctrl;
foreach (Control ctrl in BookingPlaceholder.Controls) //BookingPlaceholder is placehodler ID
{
if (ctrl is Panel)
{
numbers[a] = ctrl.ID;
a++;
//ctrl.ID = numbers[a];
foreach(TextBox tb in ctrl.ID) // error here
{
}
}
}
However the second foreach loop has an error, and I am not 100% sure how to overcome this.
"Cannot convert type 'char' to 'System.Web.UI.WebControls.TextBox'"
I know that the numbers[a] does find the first panel, however it's a string with no extension of ID.
Any suggestions are appreciated.
Josh

Your inner loop is trying to iterate through a string. What you wanted was...
foreach(TextBox tb in ctrl.Controls.OfType<TextBox>())
instead of
foreach(TextBox tb in ctrl.ID)

If for more generic controls available in PlaceHolder then
you need to find textbox controls. so it is safe to check the control type also.
foreach (Control ctr in ctrl.Controls)
{
if (ctr is TextBox)
{
//Do your things
// ((TextBox)ctr).Text
}
}

Related

Foreach button in my panel containing other panels

I'm using a custom Button which contains other elements and color styles like TopColor and BotColor. I need to handle this Button inside a panel with other panels.
I'm trying this:
foreach(CustomButton btn in panel1.Controls)
{
if(btn is CustomButton)
{
btn.TopColor=Color.Red;
}
Inside panel1 I'm containing other panels too. And the error I'm getting is
it can't be conversion element panel in a button.
One solution is to separate buttons in one panel. But I want to ask if there is some way to avoid other elements. The reason I don't want to use foreach (Control a in this.Controls) is it doesn't recognise my custom color style TopColor and BotColor
Take a look
Loop through all your controls (as Controls), check if it's a button, then cast it before you try and set the colour.
foreach(Control c in panel1.Controls)
{
if (c is CustomButton)
{
(c as CustomButton).TopColor = Color.Red;
}
}
I hope this solution works for you.
private void SetStylesToCustomButtons(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is CustomButton)
{
(control as CustomButton).TopColor = Color.Red;
}
else if (control is Panel)
{
SetStylesToCustomButtons((control as Panel).Controls);
}
}
}
The reason you're getting an error is that you're trying to cast all your controls to CustomButton, even the panels. You already know the type that you're looking for, so you don't have to loop through every control in your panel.
Assuming all your custom buttons are in panel1 and that you don't need to recurse, you should rather filter the items down to the type that you want and then work with them:
var customButtons = panel1.Controls.OfType<CustomButton>();
foreach (CustomButton customButton in customButtons)
{
//do what you need here
}

Looping throughTextBoxes in a Panel

I have a panel that contains 5 textboxes, I am trying to loop through the Panel and insert the value of the textbox into the database if it is not 0.
my panel name is Panel1
I honestly do not know from where to start or how to loop in a Panel that contains textfields, any suggestions are appreciated:
Here is my try which it does not compile (I am not sure how to write a loop that loops through a panel)
const string query = "INSERT INTO deductible (number) VALUES (#yes)";
using (var command = new SqlCommand(query, conn))
{
foreach (Panel1 c in this.Controls)
{
if (c.ToString() != "0")
{
command.Parameters.AddWithValue("#yes", c.Text);
command.ExecuteNonQuery();
}
}
I also attached a screenshot of my Panel1.
Thank you.
The simple answer is
foreach(Control control in this.Controls) {
if (control is TextBox) {
// The code here ...
}
}
The problem though is that you then need to make sure that the order the textboxes are looped over is correct, which adds more maintenance work that is entirely unnecessary. A better approach would be to learn about data binding. Or even more simply, just name your textboxes and assign them directly. Either of those is preferable to using a loop I think.
One way is to iterate each control within your Panel that is a TextBox.
foreach (TextBox tb in Panel1.Controls.OfType<TextBox>())
{
if (tb.Text != "0")
{
}
}
You're trying to loop through items of type Panel1 in this.Controls. What you want to do is loop through items of type TextBox in Panel1.Controls.
foreach(Control c in Panel1.Controls) {
var textbox = Control As TextBox;
if(textbox != null){
// do stuff...
}
}
You also want to look at the Text property of the TextBox, not call ToString on it.
if(textbox.Text != "0"){ //do stuff... }
And you add a #yes parameter to the same command multiple times within the loop, without clearing out the parameters list. I'm not certain if that will work, but if it causes a problem, you should just be able to call command.Parameters.Clear to clear the old parameter before adding the new one.

Text from textboxes to list

I'm REALLY new to C# and programming overall, so my question might be stupid in your opinion but here it is.
I have created a form which contains 7 textboxes and i want to collect text from these textboxes and add them to a list. I however get an error saying, System.Windows.Forms.TextBox is a 'type' but is used like a 'variable". What should I do?
for (int i = 1; i < 8; i++)
{
if (TextBox[i].Text == "")
{
days.Add("Restday");
}
else
{
days.Add(TextBox[i].Text);
}
}
TextBox is a type. so TextBox[i] is causing you trouble.
You can alway do something like this
foreach(Control ctrl in yourform.Controls)
{
Textbox = ctrl as TextBox;
if(txtBox != null)
{
if (txtBox.Text == "")
{
days.Add("Restday");
}
else
{
days.Add(txtBox.Text);
}
}
}
This work for a basic form. If you have pannel and other container to organize your controls the approch described in Guffa answer might be better. This could also be rewritten as method who accept a collection of Control recursive use to reach all controls.
Put the textbox references in an array so that you can easily loop through them. If your textboxes are named TextBox1 to TextBox7:
TextBox[] boxes = {
TextBox1, TextBox2, TextBox3, TextBox4, TextBox5, TextBox6, TextBox7
};
foreach (TextBox box in boxes) {
if (box.Text == "") {
days.Add("Restday");
} else {
days.Add(box.Text);
}
}
I guess you don't have an array named TextBox that is why the error. You can try following:
List<strig> days = this.Controls.OfType<TextBox>
.Select(r=> string.IsNullOrWhiteSpace(r.Text)
? "Restday" : r.Text)
.ToList();
But the above would give you the textboxes added on the form directly, If these textboxes are inside other control then you can look for recursively
Go into the form editor and select one of your textboxes. Now find the properties window. If it's not visible then click View->Properties Window
One of the properties in there will be the name of the textbox control. Use that to access it's text value like so:
days.Add(txtMyTextboxName.Text);
If you must iterate through the textboxes you can do this:
foreach(var Textbox in this.Controls.OfType<TextBox>())
{
if (Textbox.Text == "")
{
days.Add("Restday");
}
else
{
days.Add(Textbox.Text);
}
}
But bear in mind this is a pretty non-standard approach and not recommended.

C# loop through an array of given labels

It's a bit difficult for me to describe, but this pseudo C# should explain what I'm trying to do.
There is a large number of labels on a windows form.
I'd like to change the text colour of some of those labels.
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i in lray)
{
label[i].Forecolor = Color.Black;
}
}
I hope that explains what I am trying to do here.
Now it's obvious it won't work due to the label[i], but how would I get around this?
It might not work, because your Labels aren't held in an array. The following code will work, considering you know the names of the label to be changed:
Label[] lray = { labelOne, labelDifferent, labelWhatElse };
foreach (Label label in lray)
{
label.ForeColor = Color.Black;
}
That would work fine if you actually had an array of labels.
If you've only got lots of variables, like this:
private Label label1;
private Label label2;
private Label label3;
private Label label4;
private Label label5;
then it's harder. Options:
Change the code to use an array instead. Not as nice in the designer, but more logical
Use Controls.Find with each ID
Iterate over Controls to find all Label controls, regardless of name
foreach (Control c in this.Controls)
{
if (c is Label)
{
// do stuff
}
}
That'll grab all of the form's child controls (provided this code is in the form's code-behind) and check to see if they're labels. Just do any manipulation you want in place of the comment.
You could create the array yourself. This involves a bit of maintenance cost/risk each time your form changes though. Note: you probably want to put the array creation bit in a Form Loaded event, not a constructor, or at least, after the InitializeComponent call, so your controls are setup.
Or you could iterate on all the children of your Form (this.Controls from a Form method), mark your labels with a specific Tag, or get all Labels if that's your purpose here.
Please note that the first solution is probably much faster in runtime performance terms if you have many controls in your form.
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i = 0; i < lray.Length; i++)
{
((Label)this.Controls["label" + i]).ForeColor = Color.Black;
}
}
If you want to achieve this for all labels on the form then something like this may help:
foreach (Control control in this.Controls) {
if (control is Label) {
(control as Label).Forecolor = Color.Black;
}
}
However if you only need to change a subset of all the labels then you need to either store the names or the indexes of the labels which need changing. This is because this.Controls has two indexers, an int32 and a string one. Thus you could try something like this
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i in lray)
{
this.Controls[i].Forecolor = Color.Black;
}
}
It is defiantly worth noting however that the ordering in this.Controls will most likely not be as liniear looking as your lray array.
Hope this helps
Try some thing like this:
List<string> ListLabelNames = new List<string>() { /* Your label name list*/ };
foreach (Label TmpLabel in this.Controls.OfType<Label>())
{
foreach (string strTmp in ListLabelNames)
{
if (String.Compare(TmpLabel.Name, strTmp, true) == 0)
TmpLabel.ForeColor = System.Drawing.Color.Black;
}
}
Hope this helps.
I noticed that you excluded 4 from the "lray" array in your example. If you are looking to exclude one or more labels from being automatically updated by code (perhaps to highlight one among a group), try this.
private void allBlackLabels()
{
foreach (Control control in this.Controls)
{
if (control is Label && control.Name != "label4")
{
(control as Label).Forecolor = Color.Black;
}
}
}
in pseudo c#:
List<String> controlsToChange =new List<String>{"lable1Name","lable2Name"};
foreach(Control control in form.Controls)
{
if(control.GetType().Equals(typeof(Lable))
{
if( controlsToChange.Contains(control.Name)
{
control.Forecolor=Colour.Black;
}
}
}

Iterating through textbox controls in a panel C#

I have seen many others with similar problems but I cannot find the flaw in my logic here. Any help would be greatly appreciated.
I have a Panel which I have added numerous label and textbox controls to, ie:
myPanel.Controls.Add(txtBox);
These controls are created and added in a method called previous to the iteration method.
I want to iterate through each textbox and use its Text property as a parameter in another method but I am not having any luck. Here is my attempt to iterate:
public void updateQuestions()
{
try
{
foreach (Control c in editQuestionsPanel.Controls)
{
if (c is TextBox)
{
TextBox questionTextBox = (TextBox)c;
string question = questionTextBox.Text;
writeNewQuestionToTblQuestions(question);
}
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
The problem I am having is that the controls are not in the Panel when I arrive at this updateQuestions() method. Here is the process involved:
A commandButton is clicked and the questions are read from a DB, for each question a method is called which adds 2 labels and a textbox to editQuestionsPanel.Controls. This panel is inside a PlaceHolder which is then made visible.
When a button inside the PlaceHolder is clicked, the updateQuestions() method is called and the editQuestionsPanel.Controls.Count = 1. As there are approx 12 questions in the DB it should be around 36. The one control inside the Panel is of type:
System.Web.UI.LiteralControl
It contains no controls.
I am sure that somwhere in the lifecycle the Panel's controls are being cleared but I do not know how to step thru the life cycle. I have a Page_load method which is called as soon as a button is clicked but once the button which calls updateQuestions() is clicked the editQuestionsPanel.Controls.Count is already back to 1 so it must be cleared before this but I do not know how to correct this...
Any help you can give to help me solve this would be greatly appreciated - its killing me!
This selects from collection controls only that which are of type TextBox.
(the same as control is TextBox or (control as TextBox) != null)
If controls are contained in editQuestionsPanel.Controls:
using System.Linq;
IEnumerable<TextBox> textBoxes = editQuestionsPanel.Controls.OfType<TextBox>();
foreach (TextBox textBox in textBoxes)
{
// do stuff
}
To select all child controls use next extension method:
public static IEnumerable<T> GetChildControls<T>(this Control control) where T : Control
{
var children = control.Controls.OfType<T>();
return children.SelectMany(c => GetChildControls<T>(c)).Concat(children);
}
Using:
IEnumerable<TextBox> textBoxes = editQuestionsPanel.GetChildControls<TextBox>();
When you add controls dynamically, you need to do that on every request - asp.net doesn't do that for you!
Add the controls in the Init or Load phase, then they will get populated with the postback values.
A frequently made mistake: Container.Controls only contains the first level child controls in this container. That is: TextBox1 in PanelA, PanelA in PanelB, you can't get TextBox1 in PanelB.Controls.
My solution is to write an extension method:
public static IEnumerable<Control> AllControls(this Control ctl)
{
List<Control> collection = new List<Control>();
if (ctl.HasControls())
{
foreach (Control c in ctl.Controls)
{
collection.Add(c);
collection = collection.Concat(c.AllControls()).ToList();
}
}
return collection;
}
Now TextBox1 is in PanelB.AllControls(). To filter all controls with type, using PanelB.AllControls().OfType<TextBox>()
If the other answers don't help, try doing your code but add recursivity. Your code would not work if it's editQuestionsPanel => Panel => Textbox
You can do something like this instead:
var questions = from tb in editQuestionsPanel.Controls.OfType<TextBox>()
select tb.Text;
foreach(var question in questions)
{
writeNewQuestionToTblQuestions(question);
}
Try this
int Count = 0;
foreach (Control ctr in Panel1.Controls)
{
if (ctr is TextBox)
Count++;
}

Categories