Changing properties of controls that were added at runtime - c#

I have a form in which several buttons are added at runtime via a 'for' method
public Form()
{
for (int i = 0 ... )
Button b = new Button()
b.text = (string) i ;
etc..
etc..
}
. now i wish to change the text property of the buttons on a certain event. How can this be accomplished? I have tried a few things but none worked.. since the buttons variables are inside the method , they are not available outside.
Thanks

The variables aren't important (although you could store them in a single List<T> field if it made things easier). The normal way to do this is to look through the Controls collection (recursively, if necessary).
foreach(Control control in someParent.Controls) {
Button btn = control as Button;
if(btn != null) {
btn.Text = "hello world";
// etc
}
}
The above assumes all the buttons were added to the same parent control; if that isn't the case, then walk recursively:
void DoSomething(Control parent) {
foreach(Control control in parent.Controls) {
Button btn = control as Button;
if(btn != null) {
btn.Text = "hello world";
// etc
}
DoSometing(control); // recurse
}
}

You can keep the reference of the button you have created ie you can either have a List with all the dynamic controls in it or if it is only one button, make the button object a class level object so that you can access it anywhere.

Related

How to create shortcut of a button on a panel at runtime?

I have a panel that contains a lot of buttons(right panel). I want to add a shortcut of selected button to another panel(left panel) with the same properties and events dynamically at runtime.
Buttons have so many properties like image, text, backcolor, forecolore, ... etc.
Also the buttons will open new form inside main panel:
private void butntest_Click(object sender, EventArgs e)
{
this.main_panel.Controls.Clear();
Form1 myForm = new Form1();
myForm.TopLevel = false;
myForm.AutoScroll = true;
this.main_panel.Controls.Add(myForm);
myForm.Show();
}
How Can i create a shortcut on left panel?
You can create a clone method which accepts a button as input and creates another button based on the input button's properties, also handle click event of the cloned button and just call PerformClick method of the input button:
public Button Clone(Button input)
{
var output = new Button();
output.Text = input.Text;
// do the same for other properties that you need to clone
output.Click += (s,e)=>input.PerformClick();
return output;
}
Then you can use it this way:
var btn = Clone(button1);
panel1.Controls.Add(btn);
Also instead of a panel, it's better to use a FlowLayoutPanel or TableLayoutPanel, so you don't need to handle the location and the layout yourself.
Note: If it's a dynamic UI and users can reorder command buttons or create whatever you called shortcut, the probably for the next step you may need to store the status of the panel to be able to reload buttons at the next load of the application after the application closed. In this case it's better to consider a pattern like command pattern. Then you can have your commands as classes. The then you can say which button is responsible to run which command at run-time and you can simply store the relation between buttons and commands using their names.
Create class Button like so
Button leftpannelbutton = new Button();
leftpannelbutton = button1.Clone();
Now leftpannelbutton is eqaul to button1. Now just add that to your form.
Find Below ( Reflection)
public static class ControlExtensions
{
public static T Clone<T>(this T controlToClone)
where T : Control
{
PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
T instance = Activator.CreateInstance<T>();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if(propInfo.Name != "WindowTarget")
propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null);
}
}
return instance;
}
}

Using findControl to find a child element

I have a Placeholder and I have a dynamically created panel in the placeholder, I also have some dynamically added radio buttons in the panel, now I can usefindControl() to find the radio buttons if they are direct children of the placeholder.
I've literally spent the whole of yesterday trying to find them when they are the child elements of the Panel. How is there a way to do this?
Here's my code below:
PlaceHolder1.Controls.Add(myPanel); //add the panel to the placeholderenter code here
myPanel.Controls.Add(myRadioButton); //add the radiobutton to the panel
You should make method that recursively searches for a control using it's Id. That mean that the method will search for a control inside of (in your case) placeholder. If method finds control, it will return it. If not, it will go search every placeholder's subcontrol, going "deeper". And then, if nothing is found, it will search one more level down, in every placeholder subcontrols' subcontrol etc.)
private Control FindControl(string ctlToFindId, Control parentControl)
{
foreach (Control ctl in parentControl.Controls)
{
if (ctl.Id == ctlToFindId)
return ctl;
}
if (ctl.Controls != null)
{
var c = FindControl(ctlToFindId, ctl);
if (c != null) return c;
}
return null;
}
and then use it like this:
Control ctlToFind = FindControl(myRadioButton.Id, Placeholder1);
if (ctlToFind != null)
{
//your radibutton is found, do your stuff here
}
else
{
// not found :(
}
Finding Controls recursive is an option, but it also has a couple of down-sides.
If you know the ID's of all the controls you can just use FindControl
RadioButtonList myRadioButton = PlaceHolder1.FindControl("Panel1").FindControl("RadioButtonList1") as RadioButtonList;
Label1.Text = myRadioButton.SelectedValue;
But you will need to give your dynamically added controls an ID.
Panel myPanel = new Panel();
myPanel.ID = "Panel1";
RadioButtonList myRadioButton = new RadioButtonList();
myRadioButton.ID = "RadioButtonList1";
PlaceHolder1.Controls.Add(myPanel);
myPanel.Controls.Add(myRadioButton);

Accessing variables dynamically in C#

I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.

How to disable a List of buttons

I have a number of buttons on a Windows Form. I only want to disable a number of them.
I have created a list of buttons and added the buttons that i want to disable. When i run the code the buttons are still enabled.
Below is what i have tried.
private List<Button> buttonsToDisable = new List<Button>();
buttonsToDisable.Add(btn1);
buttonsToDisable.Add(btn2);
buttonsToDisable.Add(btn3);
foreach (var control in this.Controls)
{
if (control is Button)
{
Button currentButton = (Button)control;
if (buttonsToDisable.Contains(currentButton))
{
currentButton.Enabled = false;
}
}
}
Can anyone see why this wont disable the button for me.
Any advice is welcome.
Why not simply?:
foreach(Button btn in buttonsToDisable)
{
btn.Enabled = false;
}
currentButton.Enabled = false;
this.Controls.Add(currentButton);
answering your question - your code would work if the buttons were direct descendants of the form - i.e. they were placed straight onto it.
If however you placed them in another container (e.g. a groupbox), then your code would need to change to something like:
foreach (var control in groupBox1.Controls)
If you have multiple levels of complexity, then you'd be looking at a recursive function to get to the buttons within their parents, and their parents, etc.
As others have pointed out, you could always just iterate over buttonsToDisable.
If is directly added to the form, then u just foreach Controls collection and disable buttons.
Button btn1 = new Button();
this.Controls.Add(btn1);
Button btn2 = new Button();
this.Controls.Add(btn1);
Button btn3 = new Button();
this.Controls.Add(btn1);
buttonsToDisable.Add(btn1);
buttonsToDisable.Add(btn2);
buttonsToDisable.Add(btn3);
foreach (var control in this.Controls)
{
((Button)control).Enabled = false;
}
or
foreach (var button in buttonsToDisable)
{
button.Enabled = false;
}

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.

Categories