How to access controls in windows form shown event? - c#

I am trying to change the Visible state of controls from the form shown event.
I am reading the name of the controls from the database table and accessing it using this.Controls["controlname"].Visible. But some of the controls are not able to access from within this event. It is showing exception.
How can I access the controls from form shown event?

Use Controls.Find() to search for it. As scheien pointed out, the control is probably inside a different container causing it not to be "found" with your original syntax. Here's a quick example:
private void Form1_Shown(object sender, EventArgs e)
{
string ctlNameFromDatabase = "textBox1";
Control[] matches = this.Controls.Find(ctlNameFromDatabase, true);
if (matches.Length > 0)
{
// ... do something with "matches[0]" ...
// you may need to CAST to a specific type:
if (matches[0] is TextBox)
{
TextBox tb = matches[0] as TextBox;
tb.Text = "Hello!";
}
}
else
{
MessageBox.Show("Name: " + ctlNameFromDatabase, "Control Not Found!");
}
}
EDIT:
For MenuItems you'll have to flag the control name in the database as a "menu item" and then use this code, where menuStrip1 is the name of your MenuStrip, to find them:
string menuName = "copyToolStripMenuItem";
ToolStripItem[] matches = menuStrip1.Items.Find(menuName, true);
if (matches.Length > 0)
{
matches[0].Visible = true;
}
The same code will work for ToolStrips as well. For example, replace menuStrip1 with toolStrip1.

Related

Using labels like arrays

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";

Adding a twin tabPage to tabControl through a user command

I'm a newbie in c# and probably going to ask a very easy question, but I've not been able to find anything on the web to help.
I have a tabControl with a TabPage which is containing a TextBox object; this object, when the event "Text changed" is invoked, will perform the change of the parent tabPage's name.
The textbox where I typed "text changed by me" has a method which is managing changing the name of the tabPage:
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (this.textBox1.Text != "")
this.tabControl2.SelectedTab.Text = this.textBox1.Text;
else
this.tabControl2.SelectedTab.Text = "(no name)";
}
Into the current page menu is contained a control to add a new page, which runs this method when the user click on it:
private void addNewPageToolStripMenuItem_Click(object sender, EventArgs e)
{
int numPagine;
string strPagine;
numPagine = this.tabControl2.TabCount;
strPagine = numPagine.ToString();
this.tabControl2.TabPages.Add("new page" + strPagine);
}
...and here is the output, which is expected since I'm just asking to add a new empty tabPage:
So, my question is: how can I make possible that when the user is clicking on "Add new page", rather than creating an empty new tabPage the program is rather creating a page like the first one (i.e. containing a textbox into the same position which has a method to change the text of the parent tabPage that I have just created?
Here is an example.
//..
// create the new page
TabPage tpNew = new TabPage("new page..");
// add it to the tab
this.tabControl2.TabPages.Add(tpNew);
// create one labe with text and location like label1
Label lbl = new Label();
lbl.Text = label1.Text;
lbl.Location = label1.Location;
// create a new textbox..
TextBox tbx = new TextBox();
tbx.Location = textBox1.Location;
tpNew.Controls.Add(lbl);
tpNew.Controls.Add(tbx);
// add code to the new textbox via lambda code:
tbx.TextChanged += ( (sender2, evArgs) =>
{
if (tbx.Text != "")
this.tabControl2.SelectedTab.Text = tbx.Text;
else
this.tabControl2.SelectedTab.Text = "(no name)";
} );
For more complicated layout you may want to consider creating a user control..
You also may want to create the first page with this code; the, of course with real values for text and positions!
For creating a UserControl you go to the project tag and right click Add-UserControl-UserControl and name it, maybe myTagPageUC. Then you can do layout on it like on a form. A rather good example is right here on MSDN
The problem is that is has no connection to the form, meaning you'll have to code all sorts of references to make it work..
I'm not really sure if you may not be better off writing a complete clonePage method instead. It could work like the code above, but would loop over the Controls of the template page and check on the various types to add the right controls..
It really depends on what is more complicated: the Layout or the ties between the pages and the form and its other controls..

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