How do I find and use a programatically-created control? - c#

I've created a number of buttons on a form based on database entries, and they work just fine. Here's the code for creating them. As you can see I've given them a tag:
for (int i = 0; i <= count && i < 3; i++)
{
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Tag = i;
this.Controls.Add(btnAdd);
}
I use these buttons for visualising a polling system. For example, I want the button to be green when everything is fine, and red when something is wrong.
So the problem I'm running into is referencing the buttons later so that I can change their properties. I've tried stuff like the following:
this.Invoke((MethodInvoker)delegate
{
// txtOutput1.Text = (result[4] == 0x00 ? "HIGH" : "LOW"); // runs on UI thread
Button foundButton = (Button)Controls.Find(buttonNumber.ToString(), true)[0];
if (result[4] == 0x00)
{
foundButton.BackColor = Color.Green;
}
else
{
foundButton.BackColor = Color.Red;
}
});
But to no avail... I've tried changing around the syntax of Controls.Find() but still have had no luck. Has anyone encountered this problem before or know what to do?

If you name your buttons when you create them then you can find them from the this.controls(...
like this
for (int i = 0; i <= count && i < 3; i++)
{
Button btnAdd = new Button();
btnAdd.Name="btn"+i;
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Tag = i;
this.Controls.Add(btnAdd);
}
then you can find it like this
this.Controls["btn1"].Text="New Text";
or
for (int i = 0; i <= count && i < 3; i++)
{
//**EDIT** I added some exception catching here
if (this.Controls.ContainsKey("btn"+buttonNumber))
MessageBox.Show("btn"+buttonNumber + " Does not exist");
else
this.Controls["btn"+i].Text="I am Button "+i;
}

Put these buttons in a collection and also set the name of the Control rather than using its tag.
var myButtons = new List<Button>();
var btnAdd = new Button();
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Name = i;
myButtons.Add(btnAdd);
To find the button use it.
Button foundButton = myButtons.Where(s => s.Name == buttonNumber.ToString());
Or Simply
Button foundButton = myButtons[buttonNumber];

In your case I would use a simple Dictionary to store and retrieve the buttons.
declaration:
IDictionary<int, Button> kpiButtons = new Dictionary<int, Button>();
usage:
Button btnFound = kpiButtons[i];

#Asif is right, but if you really want to utilize tag you can use next
var button = (from c in Controls.OfType<Button>()
where (c.Tag is int) && (int)c.Tag == buttonNumber
select c).FirstOrDefault();
I'd rather create small helper class with number, button reference and logic and keep collection of it on the form.

Related

C# Dynamicaaly Add and Delete buttons

From the below code, I dynamically create a list of buttons based on client names provided by a TCP connection from the clientNames[i] list.
private void updateClientListUI()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(this.updateClientListUI));
}
else
{
//Debug.WriteLine(clientNames[0]);
int basex = subPanelClient.Location.X;
int basey = subPanelClient.Location.Y;
for (int i = 0; i < clientNames.Count; i++)
{
Button b = new Button();
b.Left = basex;
b.Top = basey;
b.Size = new Size(25, 25); // <== add this line
b.Dock = DockStyle.Top;
b.ForeColor= Color.Gainsboro;
b.FlatStyle= FlatStyle.Flat;
b.FlatAppearance.BorderSize = 0;
b.Padding= new Padding(35, 0, 0, 0);
b.TextAlign = ContentAlignment.MiddleLeft;
basey += 25;
b.Name = clientNames[i];
b.Text = clientNames[i];
subPanelClient.Controls.Add(b);
buttonsAdded.Insert(i, b);
}
}
}
What I am trying to figure out, is how to delete a button (i). What I attempted is the following:
private void removingButtons(int i)
{
if (buttonsAdded.Count > 0)
{
Button buttonToRemove = buttonsAdded[i];
subPanelClient.Controls.Remove(buttonToRemove);
buttonsAdded.Remove(buttonToRemove);
}
}
Or if anyone would know how to update the current list of buttons from updateClientListUI() to the current latest list from clientNames[i] instead of a list being added onto another list.
The issue that Im getting is that obviously every time there is a connection or disconnection the list just keeps getting added instead of refreshing to the current list.
One way to do it would be to clear the old buttons on each update.
foreach (Button b in buttonsAdded)
{
subPanelClient.Controls.Add(b);
}
buttonsAdded.Clear();
for (int i = 0; i < clientNames.Count; i++)
{
Button b = new Button();
...
...
If the subPanelClient only contains those buttons, you could just use
subPanelClient.Controls.Clear();
Last remark: Your removingButtonk function seems to use this.Controls.Remove instead of subPanelClient.Controls.Remove.

Tricky : Array of controls dynamically created causing problems

I put "Tricky" in the title because I'm aware that it will be hard to understand precisely what I want but I'll try to be clear.
I have a textBox with an event for TextChange which allow me to create the number of texboxes the user want (we will call it tChange).
Here is a part of the code for this event :
int tester;
bool flag = false;
if (!Int32.TryParse(tChange.Text, out tester))
{
flag = false;
return;
}
else
{
num = Convert.ToInt16(tChange.Text);
flag = true;
}
if (flag == true)
{
if (num >= 1)
{
for (int i = 0; i < num; i++)
{
this.Size = new Size(590, 225 + 105 * i);
textBoxesQ[i] = new TextBox();
this.Controls.Add(textBoxesQ[i]);
textBoxesQ[i].Size = new Size(45, 20);
textBoxesQ[i].Location = new Point(25, 100 + 100 * i - 1);
}
}
}
So the user enter the value and everything is OK. If he wants to change the number in the tChange, no problem too! The form is resize and the TextBoxes are created. However if he does this (change the value of tChange), everything goes wrong! Errors like
Index out of range
or I can't get the values from the TextBoxes etc..
I started thinking that the TexBoxes were created in front of the previous ones and the error came from this, so I tried to put the new ones to front, bring the old ones to front but none worked..
textBoxesQ[i].BringToFront();
textBoxesQ[i].SendToBack();
I also tried to delete the old ones before creating the new but I think that my code was wacky and it didn't work at all.
textBoxesQ[i].Dispose();
EDIT : As #Dr. Stitch said, It may come from not reinitializing the TextBoxes each time the text in tChange is changed. Now I just need to figure out how to make it happen.
You need to do three things when the number changes:
Remove any existing textboxes
Create a new array with the new size, and save a reference to that new array into your field (textBoxesQ)
Initialize the array
So something like:
if (textBoxesQ != null)
{
foreach (var textBox in textBoxesQ)
{
Controls.Remove(textBox);
}
}
textBoxesQ = new TextBox[size];
for (int i = 0; i < size; i++)
{
var textBox = new TextBox
{
Size = new Size(45, 20);
Location = new Point(25, 100 + 100 * i - 1);
};
Controls.Add(textBox);
textBoxesQ[i] = textBox;
}

How to write to a dynamical number of Textboxes?

I have a form (Windows Forms) with dynamically created textboxes:
TextBox[] tbxCantServ = new TextBox[1];
int i;
for (i = 0; i < tbxCantServ.Length; i++)
{
tbxCantServ[i] = new TextBox();
}
foreach (TextBox tbxActualCant in tbxCantServ)
{
tbxActualCant.Location = new Point(iHorizontal, iVertical);
tbxActualCant.Name = "tbx" + counter++;
tbxActualCant.Visible = true;
tbxActualCant.Width = 44;
tbxActualCant.MaxLength = 4;
this.Controls.Add(tbxActualCant);
}
Now I want to fill them with data, how could I do that?
If I created some textboxes dynamically with the names:
"tbxActualServ.Name = "txt" + counter;"
How can I write in them? How can I access to them?
For example, if I have created tbx1, tbx2 and tbx3, I would have a "for" that fills tbx1.Text with "1", tbx2.Text with "2", and tbx3.Text with "3".
something like
"for from i=0 to counter {
tbx[i] = i
}"
of like:
this.Controls.OfType<TextBox>().Where(r => r.Name == "tbx" + counter).¿¿Write??(r => r.Text = i).ToString();
Thanks!
You could do something like this:
this.Controls.OfType<TextBox>().ToList<TextBox>().ForEach(tb => tb.Text = "bla bla");
Evening,
Guessing from your tags that this is a web forms project.. Im going to have to make some other assumptions.
I am guessing that you are creating your text boxes in code, something like
TextBox tb1 = new TextBox();
form1.Controls.Add(tb1);
TextBox tb2 = new TextBox();
form1.Controls.Add(tb2);
If this is the case then I believe that you could do something like this:
for (int i = 0; i < 2; i++)
{
TextBox tb1 = page.findControl("tb" + i.ToString());
tb1.Text = "This is number " + i.ToString();
}
There is another alternative, you could keep a collection of the controls as you create them, you could then iterate over the collection.
To be honest, without more details about your code it will be difficult to give a full answer, I think that this answers what you are looking for, if not update your question with more details and more of the code (the code where you are dynamically creating the controls would be useful)
While it's possible to access controls by their names (the way you do it depends on the technology - are you using WinForms, WPF, Web Forms, ...?), using an array of controls is a much better solution. Here's some pseudo-C#:
MyControl[] controls = new MyControl[length];
for(int n = 0; n < controls.Length; n++)
{
controls[n] = new MyControl(...);
}
// ...
for(int n = 0; n < controls.Length; n++)
{
DoSomethingWith( controls[n] );
}

Check if TextBox is created, then assign it's value

I'm trying to make a small app, for make my job easier creating definitions (new web forms aspx) via WinForms C#.
Now I have this form, where I tell the app how many textboxes I want to create.
After their creation, I want to assign to a string the textboxes values that I wrote.
private void CreateControls()
{
for (int index = 0; index < NumberOfRows; index++)
{
TextBox textBox = new TextBox();
textBox.Name = "TextBox" + (index + 1).ToString();
textBox.Size = new Size(120, 20);
textBox.Location = new Point(X, Y + 26);
ComboBox comboBox = new ComboBox();
comboBox.Name = "ComboBox" + (index + 1).ToString();
comboBox.Size = new Size(75, 20);
comboBox.Location = new Point(141, Y + 26);
comboBox.DataSource = Enum.GetNames(typeof(DataTypes));
Y += 26;
this.Controls.Add(textBox);
this.Controls.Add(comboBox);
}
}
Now, I don't know how to check if the textboxes are created, and then take their values.
Could anyone refer me something? Thanks :)!
You'll need to, on Page_Load, find those controls and grab their values. Since you gave them meaningful names when you created them, this should do the trick:
for (int index = 0; index < NumberOfRows; index++)
{
TextBox textBox = this.FindControl(
string.Format("TextBox{0}", index)) as TextBox;
if (textBox == null) { continue; } // this means it wasn't found
var text = textBox.Text;
// work with the text
}
However, if the ComboBox class you're using isn't a third-party one and it's not an ASP.NET application, the code would work for a Windows Forms application as well with a minor modification:
for (int index = 0; index < NumberOfRows; index++)
{
// you have to use the Find method of the ControlCollection
TextBox textBox = this.Controls.Find(
string.Format("TextBox{0}", index)) as TextBox;
if (textBox == null) { continue; } // this means it wasn't found
var text = textBox.Text;
// work with the text
}
I tend to agree with the community that it's probably a Windows Forms application because you can't set the Location of a standard ASP.NET control. However, if these are user controls, or third-party ones, that support those properties and render the appropriate CSS then we'd never know.
if(Page.FindControl("IDofControl") != null)
//exists
else
//does no exists

Autoexpand textbox while typing

I am needing an autoexpanding textbox like facebook has for it's status updates. I have code for it but for some reason it's not fully working correctly. It's updating the textbox and expanding it, but it is doing it way too soon. i am wanting it to expand when it gets to the end of the line. But it is doing it after 20 characters are entered! I have two different methods i have tried, they both do the same thing. Any suggestions on changing my code?
function sz(t) {
var therows = 0
var thetext = document.getElementById(t.id).value;
var newtext = thetext.split("\n");
therows += newtext.length
document.getElementById(t.id).rows = therows;
return false;
}
function sz(t)
{
a = t.value.split('\n');
b = 1;
for (x = 0; x < a.length; x++)
{
if (a[x].length >= t.cols)
{
b += Math.floor(a[x].length / t.cols);
}
}
b += a.length;
if (b > t.rows)
{
t.rows = b;
}
}
Check out this fiddle.
I think your problem was using txtbox.id rather than just passing the id.

Categories

Resources