Using labels like arrays - c#

I am working on winform application in asp.net using c#. I have 10 labels on my winform created in the designer mode, called Label0 to Label9. Now I want to change the Text property of all the labels at once as per the data I acquire in the middle of execution of my program.
i want to do something like this :
for (int i = 0; i < 10; i++)
{
Label[i].Text = "Hello, this is label: "+ i.ToString();
}
Now, of course this won't work. But how can this be done? how can i call the label like its done in an array? If not possible, then what can be the best alternative solution for my problem?

If you are talking about WinForms, then you can do like this:
private void Form1_Load(object sender, EventArgs e)
{
// Form1_Load is just sample place for code executing
for (int i = 1; i < 10; i++)
{
var label = Find<Label>(this, "label" + i);
label.Text = "Hello, this is label: " + i.ToString();
}
}
private T Find<T>(Control container, string name)
where T : Control
{
foreach (Control control in container.Controls)
{
if (control is T && control.Name == name)
return (T)control;
}
return null;
}
This code will search label in form controls, and then return it based on control name and type T. But it will use just parent form. So if your label is in some panel, then you need to specify panel as container parameter. Otherwise Find method can be updated as recursive method, so it will search inside all form subcontrols, but if there will be two Label1 controls, then it will return just first one, that might be not correct.

If you can put all Label on a panel after the you can use below code to change the text
foreach (Control p in panal.Controls)
if (p.GetType == Label)
p.Text = "your text";

Related

Panel control with variable name

I have 25 panel control (Visible false).
I want to make it visible.
But it doesn' work:
(Error 1 'string' does not contain a definition for 'Visible' and no extension method 'Visible' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)
)
for (int i = 0; i < 25; i++)
{
string panelID = "panel" + i.ToString();
panelID.Visible = true;
}
Help
Your code is wrong in so many fronts.
As it is, what you're doing is creating 25 strings with values panel0, panel1, panel2 etc., and trying to assign a value to a property of it. But strings don't contain a property named Visible, so obviously you'll get an error.
What you want to do is get hold of controls of type Panel in your form, and set their values.
foreach(var panel in this.Controls.OfType<Panel>())
{
panel.Visible = true;
}
Caveat: the above will only find Panel controls in your topmost form. If there are controls that are nested, you'd want to perhaps write a method to recursively find them. Above is just to give you the idea.
In addition, if you have multiple Panel controls and if you only want to set the property of those panels names fit your naming convention you can filter them out.
foreach(var panel in this.Controls.OfType<Panel>())
{
if( panel name fits your naming convention)
panel.Visible = true;
}
Here, you can look for correct panel name by using a Regex, use a custom function etc.
You can store all the dynamically created Panels to a collection from which you can refer them by their Name. One such collection is Dictionary.
public class Form1 : Form
{
Dictionary<string, Panel> panels = new Dictionary< string, Panel>();
public void Form1_Load(object sender, EventArgs e)
{
for (var i = 0; i < 25; I++)
{
Panel panel = new Panel();
panel.Name = "panel" + i.ToString();
this.Controls.Add(panel);
panels.Add(panel.Name, Panel);
}
}
}
now you can make them visible /invisible as following.
private void ShowHidePanel(int panelNumber, bool visible)
{
panels["panel"+panelNumber.ToString()].Visible = visible ;
}
or if you want to show or hide all the panels you can do as following.
private void ShowHidePanels(bool visible)
{
for (var i = 0; i < 25; i++)
{
panels["panel" + i.ToString()].Visible = visible;
}
}

Referencing a dynamically created control in a new TabPage

newbie programmer here after hours of searching has left me stumped.
I'm having trouble with referencing a control inside a tab created at RunTime with a button press. Basically what I have is a tabletop RPG calculator, using a Windows Form, that has a tabControl holding tab pages, with each tab page holding user-inputted stats for that individual enemy to be used in calculations.
The problem is that I want the user to be able to click a button to generate a new enemy tab page. Here is my code for generating an enemy tab page with a TextBox.
int enemyNumber = 0;
// Creates a new Enemy Tab
private void button2_Click_1(object sender, EventArgs e)
{
// Create a new TabPage
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
// Add Enemy Name Box
var newEnemyNameBox = new TextBox()
{
Name = "enemyNameBox" + enemyNumber,
Text = "",
Location = new Point(127, 11),
Size = new Size(133, 20)
};
// Add the controls to the new Enemy tab
newTabPage.Controls.Add(newEnemyNameBox);
// Add the TabPage to the TabControl
tabControl1.TabPages.Add(newTabPage);
// Increases the enemy's "reference number" by 1
// So that enemy tabs will be generated in order enemyTab0, enemyTab1, etc.
enemyNumber += 1;
}
This all works nicely. Unfortunately, after this point things have gotten ugly. I need to reference that TextBox named "enemyNameBox" + enemyNumber, and I'm not sure how to do so.
What I did was create "archVariables" to store the values from whatever enemy tab is selected, then use the appropriate archVariable in the program's calculations. IE: archEnemyName. The idea is that whatever tab the user is currently selected on (determined via SelectedIndex) the TextBox from that page will be used for the program's output.
Here are the two things I've tried after researching the matter:
// Attempt 1
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
archEnemyNameBox = ((TextBox)Controls["enemyNameBox" + i]).Text;
}
}
This code simply throws a NullReferenceException when I press the button. So after researching more I tried this:
// Attempt 2
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)));
archEnemyNameBox = tb2.Text;
}
}
This time I got an Error: Cannot convert type 'System.Windows.Forms.Control[]' to 'System.Windows.Forms.TextBox'
I feel like the second method I have here is probably closer to the correct way to do this, but apparently I'm still not getting it right. I've learned a lot by searching the information on stackoverflow and msdn.microsoft but nothing has gotten me past this problem.
Any help would be appreciated.
basically the problem with your second attemp is that enemyTab.Controls.Find("enemyNameBox" + i, true) returns an array of Controls Control[] and you're trying to convert that to a Control here is the problem, you should get the first control in that array and then convert it to a Control so it should be like this:
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)[0]));
archEnemyNameBox = tb2.Text;
}
}
but it is not the BestWay to do so it seems that everytime a user adds a new tabPage it will have the same Controls right? so why not create an userControl with any Control you have on your TabPage? so when you press the user press to add a new tab your code should be like so:
private void CreateNewEnemyTab()
{
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
EnemyTabUserControl enemyTab = new EnemyTabUserControl(enemyNumber);
here the EnemyTabUserControl should have all the components you need;
newTabPage.Controls.Add(enemyTab);
tabControl1.TabPages.Add(newTabPage);
}
and the code to bring the TextBox from the current tab could be as follow (you are going to need to reference LINQ)
using System.Linq;
//First Lets create this property, it should return the selected EnemyTabUserControl inside the tabControl
public EnemyTabUserControl CurrentTab {
get {
return tabControl1.SelectedTab.Controls.OfType<EnemyTabUserControl>().First();
}
}
// then if we make the textbox you want to reference from outside the code we can do this
CurrentTab.NameOfTheTextBox;
Patrick has solved your fundamental problem, but I don't think you need the loop in there at all. Here I've broken the steps out so you can see what needs to happen a little better:
private void defendCalcButton_Click(object sender, EventArgs e)
{
Control[] matches = this.Controls.Find("enemyNameBox" + tabControl1.SelectedIndex.ToString(), true);
if (matches.Length > 0 && matches[0] is TextBox)
{
TextBox tb = (TextBox)matches[0];
archEnemyNameBox = tb.Text;
}
}

Change text property of all items in form

I have many buttons and labels on my c# form. I have a button that changes all butons' and labels' text properties (change language button). Do i have to write all items in click event of button or is there a method that scans all form control items and change their text properties.
There are many other controls that contains labels or buttons. For example a label is added to the control of a panel and when i iterate form controls, i can't reach this label. I want to change all items' text properties at one time.
Thank you.
foreach (Control objCtrl in yourFormName.Controls) {
if (objCtrl is Label)
{
// Assign Some Text
}
if (objCtrl is Button)
{
// Assign some text
}
}
If a CS0120 error happens, change yourFormName.Controls to this.Controls;
Assuming ASP.NET's ITextControl Interface (works similar for Winforms-Controls' Text-Property ):
var text = "Hello World";
var allTextControls = this.Controls.OfType<ITextControl>();
foreach(ITextControl txt in allTextControls)
txt.Text = text;
http://msdn.microsoft.com/en-us/library/bb360913.aspx
Edit: You could easily make it an extension(e.g. ASP.NET, for Winforms replace ITextControl with Control):
public static class ControlExtensions
{
public static void SetControlChildText(this Control rootControl, String text, bool recursive)
{
var allChildTextControls = rootControl.Controls.OfType<ITextControl>();
foreach (ITextControl txt in allChildTextControls)
txt.Text = text;
if (recursive) {
foreach (Control child in rootControl.Controls)
child.SetControlChildText(text, true);
}
}
}
Now you can call it for example in this way:
protected void Page_Load(object sender, EventArgs e)
{
Page.SetControlChildText("Hello World", true);
}
This will apply the given text on every child control implementing ITextControl(like Label or TextBox).
If it's winforms you should read about localizing your application here:
Walkthrough: Localizing Windows Forms
I think if you are using javascript, you can simply go through the DOM and modify the texts of the buttons and labels. Using jQuery this will be very simple
For a web application, you could do this quite easily with jQuery. Have a look at this: http://api.jquery.com/category/selectors/
$('label').each(function(){this.value = 'something else';});
For Winforms, you can use this:
foreach (var c in Controls.OfType<TextBox>())
c.Text = "TextBox Text";
foreach (var c in Controls.OfType<Label>())
c.Text = "Label text";
But I agree with #ionden, you should consider localizing your application.
There is a Controls property that contains all controls of your form. You can iterate over it:
foreach(var control in Controls)
{
var button = control as Button;
if(button != null)
button.Text = Translate(button.Text);
else
{
var label = control as Label;
if(label != null)
label .Text = Translate(label .Text);
}
}
foreach( Control ctlparent in this.Controls)
{
if(ctlparent is Panel or ctlparent is GroupBox)
{
foreach(Control ctl in ctlparent.Controls)
{
if(ctl is Label or ctl is Button)
{
ctl.Text= newtext;
}
}}
This will work.

Problems changing properties on a control using the controls name

This should work.. I think..
string ctrlName = "btnSomeButton" + someIndexValue;
this.Controls[ctrlName].Text = "Some value";
I get 'Object reference not set to an instance of an object.', the control does exist on the form. I've tried casting it.
Solution:
string ctrlName = "btnSomeButton" + someIndexValue;
Control[] ctrl = this.Controls.Find(ctrlName, True);
Button btn = (Button)ctrl[0];
btn.Text = "Some Value";
Thank you.
The control might be a nested control so you're going to have to dig deeper in the control tree of "this"
Here is a simple recursive control search tool, i wrote it without testing it but i think it should work for your needs:
private Control FindControl(Control ctr, string name)
{
Control c = null;
for (int i = 0; i < ctr.Controls.Count; i++)
{
if (string.Equals(ctr.Controls[i].ID, name, StringComparison.CurrentCultureIgnoreCase))
{
c = ctr.Controls[i];
break;
}
if (ctr.Controls[i].Controls.Count > 0)
{
c = FindControl(ctr.Controls[i], name);
if (c != null)
break;
}
}
return c;
}
Are your buttons actually controls on the form, or do they have a different parent? For instance, if you buttons reside inside a a Panel or GroupBox you will not be able to access them by name by just using this. You will need to find them in their container.
Example: myPanel.Controls[ctrlName].Text = "Some Value"
You can use the control methods in addition to this below to determine where the control is located i.e. what parent might have this control assigned.
{
Control[] ctls = this.Controls.Find("Button2", true);
if (ctls.Length > 0)
{
Button btn = ctls[0] as Button;
if (btn != null)
btn.PerformClick();
}
else
MessageBox.Show("Not Found");
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Button2 Clicked");
}
Depending on your requirements, you may want to consider creating a Dictionary<string, Control> collection that allows you to quickly refer to the control by name. This also frees you from requiring the control name containing the index.
Do you really have a control named like ctrlName in your immediate Controls collection? It may be the name of a control that is deeper in the hierarchy, or even a control which doesn't exist.
Try finding the control recursively:
string ctrlName = "btnSomeButton" + someIndexValue;
Control[] matchingControls = this.Controls.Find(ctrlName, true);
foreach (Control c in matchingControls)
c.Text = "Some value";

Multi-tab application (C#)

I'm creating a multi-tabbed .NET application that allows the user to dynamically add and remove tabs at runtime. When a new tab is added, a control is added to it (as a child), in which the contents can be edited (eg. a text box). The user can perform tasks on the currently visible text box using a toolbar/menu bar.
To better explain this, look at the picture below to see an example of what I want to accomplish. It's just a mock-up, so it doesn't actually work that way, but it shows what I want to get done. Essentially, like a multi-tabbed Notepad.
View the image here: http://picasion.com/pic15/324b466729e42a74b9632c1473355d3b.gif
Is this possible in .NET? I'm pretty sure it is, I'm just looking for a way that it can be implemented.
You could use a simple extension method:
public static void PasteIntoCurrentTab(this TabControl tabControl)
{
if (tabControl.SelectedTab == null)
{
// Could throw here.
return;
}
if (tabControl.SelectedTab.Controls.Count == 0)
{
// Could throw here.
return;
}
RichTextBox textBox = tabControl.SelectedTab.Controls[0] as RichTextBox;
if (textBox == null)
{
// Could throw here.
return;
}
textBox.Paste();
}
Usage:
myTabControl.PasteIntoCurrentTab();
I suggest you keep some "current state" variables updated so you always have a pointer to the selected Tab Page, and its child control (in the case of a tabbed-notepad emulation discussed here : a TextBox). My preference would be to keep track of the TabPage<>TextBox connections using a Dictionary to avoid having to cast the TextBoxes if they are accessed using the TabPage.Controls route : the following code assumes you have a TabControl named 'tabControl1 on a Form :
Dictionary<TabPage, TextBox> dct_TabPageToTextBox;
int tabCnt = 1;
TabPage currentTabPage;
TextBox currentTextBox;
So, as you create each new TabPage at run-time you call something like this :
private void AddNewTabPage()
{
if (dct_TabPageToTextBox == null) dct_TabPageToTextBox = new Dictionary<TabPage, TextBox>();
currentTabPage = new TabPage("Page " + tabCnt.ToString());
tabControl1.TabPages.Add(currentTabPage);
currentTextBox = new TextBox();
dct_TabPageToTextBox.Add(currentTabPage, currentTextBox);
currentTabPage.Controls.Add(currentTextBox);
currentTextBox.Dock = DockStyle.Fill;
currentTextBox.Text = "sample text for page " + tabCnt.ToString();
tabControl1.SelectedTab = currentTabPage;
tabCnt++;
}
As the end-user changes the selected TabPage you can simply update your current state variables like this :
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
currentTabPage = tabControl1.SelectedTab;
currentTextBox = dct_TabPageToTextBox[currentTabPage];
MessageBox.Show("text in current Tab Page is : " + currentTextBox.Text);
}
So now have the code that is invoked by your menu choices applied only to the currentTextBox.
best, Bill
I tried this for fun ... I made a form with a ToolStripContainer, and a ToolStrip inside it, with the standard buttons (which includes the paste button). I renamed the paste button to pasteButton, and hooking everything up you get:
public Form2()
{
InitializeComponent();
TabControl tc = new TabControl();
toolStripContainer1.ContentPanel.Controls.Add(tc);
tc.Dock = DockStyle.Fill;
TextBox selectedTextBox = null;
pasteButton.Click += (_, __) => selectedTextBox.Paste(Clipboard.GetText(TextDataFormat.Text));
int pages = 0;
newTabButton.Click += (_,__) => {
TextBox tb = new TextBox { Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Vertical };
TabPage tp = new TabPage("Page " + (++pages).ToString());
tc.Selected += (o, e) => selectedTextBox = e.TabPage == tp ? tb: selectedTextBox;
tp.Controls.Add(tb);
tc.TabPages.Add(tp);
tc.SelectedTab = tp;
selectedTextBox = tb;
};
}

Categories