I have the WinForm, there I have a lot of controls, and on certain moments I need to change the properties for some of them.. so, I create the Control array and determines what should be changed
controls = new Control[] {loadFromFile_btn, logout_btn, postBtn, waitFrom_tb, waitTo_tb, messageTB, recurs_check};
ChangeStatus.activStatus(controls);
Then in my class ChangeStatus make changes to all of these elements are in an array
public static void activStatus(Control[] controlObj)
{
for (int i = 0; i < controlObj.Count() - 1; i++)
{
controlObj[i].BeginInvoke((Action)delegate
{
if (controlObj[i] is TextBox || controlObj[i] is CheckBox || controlObj[i] is Panel)
controlObj[i].Enabled = true;
else
{
controlObj[i].BackColor = Color.DarkGray;
controlObj[i].Enabled = true;
}
});
}
}
But I have a problem... the change applies only to the last element in the array. Help me please..
That's because of the closure.Try storing i in a local variable and use it in your anonymous method
for (int i = 0; i < controlObj.Count() - 1; i++)
{
int j = i;
controlObj[i].BeginInvoke((Action)delegate
{
if (controlObj[j] is TextBox || controlObj[j] is CheckBox || controlObj[j] is Panel)
controlObj[j].Enabled = true;
else
{
controlObj[j].BackColor = Color.DarkGray;
controlObj[j].Enabled = true;
}
});
}
Related
I have a property grid and a combo box, Based on the value of the combo box i change the propertygrid.SelectedItem and refresh the property grid.
The problem is that whenever i select a value to edit the whole screen starts flickering like it's repainting or redrawing. This only happens when i select a property on the property grid, it goes away when i go to another screen and comeback. I have not written any redraw functions on click events.
[edit1]I've added a code snippet of combo box selected item change
if (this.comboBoxHomerSelectSettings.SelectedItem.ToString() == "AppSettings")
{
this.comboBoxHomerSublist.Visible = false;
this.propertyGridEditSettings.SelectedObject = Settings.SingleInstance.SettingsValues.AppSettings;
}
else if (this.comboBoxHomerSelectSettings.SelectedItem.ToString() == "WaferSpecificSettings")
{
this.comboBoxHomerSublist.Visible = true;
this.comboBoxHomerSublist.Items.Clear();
for (int i = 0; i < Settings.SingleInstance.SettingsValues.WaferSpeicificSettingsList.WaferSpeicificInformationList.Count;i++ )
{
this.comboBoxHomerSublist.Items.Add(Settings.SingleInstance.SettingsValues.WaferSpeicificSettingsList.WaferSpeicificInformationList.ElementAt(i));
}
this.comboBoxHomerSublist.SelectedIndex = 0;
this.propertyGridEditSettings.SelectedObject = this.comboBoxHomerSublist.SelectedItem;
}
else if (this.comboBoxHomerSelectSettings.SelectedItem.ToString() == "BinColorMapping")
{
this.comboBoxHomerSublist.Visible = true;
this.comboBoxHomerSublist.Items.Clear();
for (int i = 0; i < Settings.SingleInstance.SettingsValues.BinColorInfoList.BinColorInformationList.Count; i++)
{
this.comboBoxHomerSublist.Items.Add(Settings.SingleInstance.SettingsValues.BinColorInfoList.BinColorInformationList.ElementAt(i));
}
this.comboBoxHomerSublist.SelectedIndex = 0;
this.propertyGridEditSettings.SelectedObject = this.comboBoxHomerSublist.SelectedItem;
}
else if (this.comboBoxHomerSelectSettings.SelectedItem.ToString() == "CommonSettings")
{
this.comboBoxHomerSublist.Visible = false;
this.propertyGridEditSettings.SelectedObject = Settings.SingleInstance.SettingsValues.CommonSettings;
}
else if (this.comboBoxHomerSelectSettings.SelectedItem.ToString() == "DOETypeMapping")
{
this.comboBoxHomerSublist.Visible = true;
this.comboBoxHomerSublist.Items.Clear();
for (int i = 0; i < Settings.SingleInstance.SettingsValues.DOETypeMapingInfoList.DOETypeMapingInformationList.Count; i++)
{
this.comboBoxHomerSublist.Items.Add(Settings.SingleInstance.SettingsValues.DOETypeMapingInfoList.DOETypeMapingInformationList.ElementAt(i));
}
this.comboBoxHomerSublist.SelectedIndex = 0;
this.propertyGridEditSettings.SelectedObject = this.comboBoxHomerSublist.SelectedItem;
}
this.propertyGridEditSettings.Refresh();
I have a form which changes Title depends on users selection. Then i want to create a properties for the control, either radiobutton or checkbox. They have same properties but i cant implement well.
private void DeleteEdit()
{
Control[] EmployeesControl; //I think this is the problem, but i cant figure it out.
if (Form_AddEmployee.Text.Contains("Edit"))
{
EmployeesControl = new RadioButton[numberOfEmployees];
}
else if (Form_AddEmployee.Text.Contains("Delete"))
{
EmployeesControl = new CheckBox[numberOfEmployees];
}
for (int i = 0; i < EmployeesControl.Count(); i++)
{
EmployeesControl[i] = new EmployeesControl();
InitializeControls(EmployeesControl[i]);
EmployeesControl[i].Visible = true;
panelEmployee.Controls.Add(EmployeesControl[i]);
EmployeesControl[i].Text = stringTemp;
EmployeesControl[i].Location = new Point(100, 100 * (i+1));
EmployeesControl[i].Font = MyFont;
EmployeesControl[i].CheckedChanged += EmployeesDeleteEditEmployees_CheckedChanged;
}
}
How can i make a variable if a certain control is a radiobutton or checkbox.
You can use GetType to check, after you will change EmployeesControl[i] to CheckBox or RadioButton.
private void DeleteEdit()
{
Control[] EmployeesControl; //I think this is the problem, but i cant figure it out.
if (Form_AddEmployee.Text.Contains("Edit"))
{
EmployeesControl = new RadioButton[numberOfEmployees];
for (int i = 0; i < EmployeesControl.Count(); i++)
{
EmployeesControl[i] = new RadioButton();
}
}
else if (Form_AddEmployee.Text.Contains("Delete"))
{
EmployeesControl = new CheckBox[numberOfEmployees];
for (int i = 0; i < EmployeesControl.Count(); i++)
{
EmployeesControl[i] = new CheckBox();
}
}
ButtonBase b;
CheckBox chk;
RadioButton rdo;
for (int i = 0; i < EmployeesControl.Count(); i++)
{
b = (ButtonBase)EmployeesControl[i];//You use b to set property
if (EmployeesControl[i].GetType() == typeof(RadioButton))
{
rdo = (RadioButton)EmployeesControl[i];
//Your code
//................
rdo.CheckedChanged += EmployeesDeleteEditEmployees_CheckedChanged;
}
else
{
chk = (RadioButton)EmployeesControl[i];
//Your code
//...............
chk.CheckedChanged += EmployeesDeleteEditEmployees_CheckedChanged;
}
//EmployeesControl[i] = new EmployeesControl();
//InitializeControls(EmployeesControl[i]);
//EmployeesControl[i].Visible = true;
//panelEmployee.Controls.Add(EmployeesControl[i]);
//EmployeesControl[i].Text = stringTemp;
//EmployeesControl[i].Location = new Point(100, 100 * (i + 1));
//EmployeesControl[i].Font = MyFont;
//EmployeesControl[i].CheckedChanged += EmployeesDeleteEditEmployees_CheckedChanged;
}
}
I hope it will help you.
You can use ButtonBase class to your perpouse.
Declare array of controls by ButtonBase, so common properties of CheckBox and RadioButton you can use without casting.
Properties of CheckBox or RadioButton you can access by
var a = EmployeesControl[i] as CheckBox;
if (a != null)
{
//this is checkbox
continue;
}
var b = EmployeesControl[i] as RadioButton;
if (b != null)
{
//this is RadioButton
}
Is it possible to set a components visible attribute based on its name?
I have 12 "master" components (comboboxes) if you want to call them that and based on the selection in these I want to display anywhere from 1 to 16 textboxes. These are named in numeric order such as combobox1_textbox_0, combobox1_textbox_1 and so on. What I would like to do ideally is take the index of the combobox and pass it as a parameter to a method that sets the textboxes visible attribute to visible/hidden depending on the index passed into the method.
Is this possible? in pseudocode or what you call it I would like it to work something like this:
private void methodToSetVisibleAttribute(int indexFromMainComboBox)
{
for(int i = 0; i < 15; i++)
{
if(i < index)
{
combobox1_textbox_+i.Visible = true;
}
else
{
combobox1_textbox_+i.Visible = false;
}
}
}
I could do panels or something for the choices but seeing as all the selections from the combobox will use the same textboxes but in different amounts it seems like alot of work to make a panel for every possible selection not to mention difficult to expand the program later on.
Assuming you are using Windows Forms and not WPF, you can use ControlCollection.Find() to find controls by name:
var textBox = this.Controls.Find(string.Format("combobox1_textbox_{0}", i), true).OfType<ComboBox>().FirstOrDefault();
if (textBox != null)
textBox.Visible = (i < index);
else
Debug.Assert(false, "textbox not found"); // Or throw an exception if you prefer.
I'll suggest an alternative to your approach, maybe not quite what you're looking for:
Place your combo boxes in a List<ComboBox> and you can access them by an index number.
List<ComboBox> myCombos = new List<ComboBox>();
for (int i = 0; i < 16; i++)
{
ComboBox cb = new ComboBox();
//do what ever you need to do here. Set its location, add items, etc.
Form1.Controls.Add(cb); //Alternatively add it to another container.
myCombos.Add(cb); //Now it's in a list.
}
Modify them like this:
for(int i = 0; i < 15; i++)
{
if(i < index)
{
myCombos[i].Visible = true;
}
else
{
myCombos[i].Visible = false;
}
}
Or even more succintly:
for(int i = 0; i < 15; i++)
{
myCombos[i].Visible = i < index;
}
OK, I have a code (see below):
void M1()
{
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" +
(i - 1).ToString() +
"CheckBox", true);
if ((carr != null) && (carr.Length > 0))
{
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = i % 2 == 0 ? true : false; // or any other value
}
}
}
I don't like iteration with using Controls.Find method. Can I replace it with something easier ?
PS: all the NumberXCheckBox (X>=0 and X<=8) presented on the form.
LINQ enabled, .net 3.5, Visual studio 2008.
Instead of searching by name, can you wrap your CheckBox controls in a container that means you can just iterate through the controls in the container?
I would encourage you to introduce a field in your type to keep references to your checkboxes (an array, a list, a dictionary -- you choose.) This way you'll no longer need to use this non-typed and somewhat ugly find-control-by-key-method.
Anyway, if you're still in .NET 2.0 and prefer to use the Find method, you could simplify a little bit your loop:
for (var i = 0; i <= 8; i++)
{
var controls = Controls.Find("Number" + i + "CheckBox", true);
if (controls.Length > 0)
{
var checkBox = controls[0] as CheckBox;
if (checkBox != null)
checkBox.Checked = i%2 == 0;
}
}
The latest non-nullity test on checkbox can probably be omitted.
If you are using 3.5 or otherwise have LINQ available you could do the following
for ( int i = 0; i < 9; i++) {
var control = this.Controls
.Find(String.Format("Number{0}Checkbox", i))
.Cast<CheckBox>()
.FirstOrDefault();
if ( control != null ) {
control.Checked = (i % 2) != 0;
}
}
More linq-y
for (int i = 0; i < 10; i++) {
var c = (from CheckBox c in this.Controls.Find(String.Format(CultureInfo.InvariantCulture, "Number{0}CheckBox", i-1), true)
select c).FirstOrDefault();
if (c != null) {
c.Checked = i % 2 == 0 ? true : false;
}
}
Here's one without linq, but cleaned up the code a little bit.
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" + (i - 1) + "CheckBox", true);
if (carr.Length <= 0) continue;
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = (i % 2) == 0;
}
[Edit: added the Find(..) code to show why you don't have to check for null]
Here's the frameworks internal code for the Find function. I've added a couple of comments in it
public Control[] Find(string key, bool searchAllChildren)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
}
// Will always return an ArrayList with zero or more elements
ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
// Will always return an Array of zero or more elements
Control[] array = new Control[list.Count];
list.CopyTo(array, 0);
return array;
}
How do I do this in a loop.
protected void ddlTool_SelectedIndexChanged(object sender, EventArgs e)
{
lblTool1.Visible = false;
txtTool1.Visible = false;
lblTool2.Visible = false;
txtTool2.Visible = false;
lblTool3.Visible = false;
txtTool3.Visible = false;
lblTool4.Visible = false;
txtTool4.Visible = false;
lblTool5.Visible = false;
if (ddlTool.SelectedValue == "1")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
}
if (ddlTool.SelectedValue == "2")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
}
if (ddlTool.SelectedValue == "3")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
lblTool3.Visible = true;
txtTool3.Visible = true;
}
if (ddlTool.SelectedValue == "4")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
lblTool3.Visible = true;
txtTool3.Visible = true;
lblTool4.Visible = true;
txtTool4.Visible = true;
}
Instead of having a separate variable for each textbox and label, have a collection of them - whether that's a List<T> or an array or whatever.
Then you can do:
// Potentially use int.TryParse here instead
int visibleLabels = int.Parse(ddlTool.SelectedValue);
for (int i = 0; i < labels.Count; i++)
{
labels[i].Visible = (i < visibleLabels);
textBoxes[i].Visible = (i < visibleLabels);
}
(Alternatively use two loops, one to set some Visible properties to true, and one to set some to false.)
You can access a control by its name using
container.Controls["nameofcontrol"]
So technically, you could use this to lookup your control
(Untested code)
for(int index = 1; index <= Convert.ToInt32(ddlTool.SelectedValue); index++)
{
this.Controls["lblTool" + index.ToString()].Visible = true;
this.Controls["txtTool" + index.ToString()].Visible = true;
}
Use a UserControl for each set of connected controls and then enable/disable the UserControl instead of all the component controls. This is classic, basic modularization of your user interface.
Note that this will still require a little "redundant" code because you're working with an unusual UI paradigm by enabling up-to the ddlTool's selected value of your control. E.g., create your user control that contains a single Label and TextBox. Call it LabeledTextBox or something similar. Then you'd create a collection of your labeled text boxes and enable them up to int.Parse(ddlTool.SelectedValue) - 1.
foreach (Control ctrl in this.Controls)
{
int index = (int)ctrl.Name.Substring(ctrl.Name.Length - 1);
int maxIndex = (int)ddlTool.SelectedValue;
ctrl.Visible = (index <= maxIndex);
}
Here is an example with no error checking, but should match your code functionality.
protected void ddlTool_SelectedIndexChanged(object sender, EventArgs e)
{
int selectedValue = int.Parse(ddlTool.SelectedValue.ToString());
for (int i = 1; i <= 4; ++i)
{
bool state = i <= selectedValue;
this.Controls["lblTool" + i.ToString()].Visible = state;
this.Controls["txtTool" + i.ToString()].Visible = state;
}
}