get all control from multiple form in csharp - c#

I want to get all the control from multiple form (Main, Two and Three) and
compare if the control tag equals the variable str_name and if true write the
value of str_value in c.Text.
the code:
private static Form[] getformular()
{
Main main = new Main();
Two f2 = new Two();
Three f3 = new Three();
Form[] form = { main, f2, f3};
return form;
}
private void initcontrol()
{
String str_name = "name";
String str_value = "value";
foreach(Form f in getformular())
{
foreach (Control c in f.Controls)
{
if (f != null && c = null)
{
if (c.Tag.Equals(str_name))
{
c.Text = str_value;
}
}
}
}
}
Could please someone help me?

First, as stated by #JonB some of conditional checking (ifs logic) in your current code seems off.
Second, looping through Form.Controls will only bring you all controls placed directly in the Form. For example if you have tab control (or any other container control) placed in form, and you have a textbox inside that tab control, you'll get only the tab control and couldn't find the textbox by looping through Form.Controls. You can solve that with recursive method as demonstrated below.
private void initcontrol()
{
String str_name = "name";
String str_value = "value";
var result = false;
foreach(Form f in getformular())
{
//if you want to check if f null, it should be here.
if(f != null) result = setControlText(f, str_name, str_value);
}
if(!result) MessageBox.Show("Control not found");
}
private bool setControlText(Control control, string str_name, string str_value)
{
var isSuccess = false;
foreach (Control c in control.Controls)
{
//if c is not null
if (c != null)
{
//check c's Tag, if not null and matched str_name set the text
if (c.Tag != null && c.Tag.Equals(str_name))
{
c.Text = str_value;
isSuccess = true;
}
//else, search in c.Controls
else isSuccess = setControlText(c, str_name, str_value);
//if control already found and set, exit the method now
if (isSuccess) return true;
}
}
return isSuccess;
}

Related

how to show messageBox just once?

newbie in learning c# here, im calculating cgpa and when user pick the number of subject they take, accordingly, the textBox will Enabled true according to the number of user subject and the rest is Enabled false. So when im clicking calculateCGPA, i want to popup message if the user input is empty but messageBox is shown x number of time according to the number that user left empty. How to get it to show only once. Tqvm in advanced. Explanation is very much appreciated.
1.CheckingUserCheckedRadioButton
private void DisplayTextBox(Control con)
{
foreach (Control c in con.Controls)
{
if (rad1.Checked)
{
if (c is TextBox)
{
((TextBox)c).Enabled = false;
txtCCode1.Enabled = true;
txtGrade1.Enabled = true;
}
else
{
DisplayTextBox(c);
}
}
}
}
2.DisplayingMessageBoxWhenClickingCalculate
private void calculate(Control con)
{
foreach (Control c in con.Controls)
{
if (c is TextBox)
{
if (c.Text == "")
{
DialogResult x = new DialogResult();
x = MessageBox.Show("TextBox cannot be Empty");
if (x == DialogResult.OK)
txtCCode1.Focus();
}
else
{
int totalCredHours = 0;
CalcTotalCredHours(credHour1, credHour2, credHour3, credHour4, credHour5, credHour6, ref totalCredHours);
courseGP1 = CalcCourseGradePoint(credHour1, gradePoint1);
courseGP2 = CalcCourseGradePoint(credHour2, gradePoint2);
courseGP3 = CalcCourseGradePoint(credHour3, gradePoint3);
courseGP4 = CalcCourseGradePoint(credHour4, gradePoint4);
courseGP5 = CalcCourseGradePoint(credHour5, gradePoint5);
courseGP6 = CalcCourseGradePoint(credHour6, gradePoint6);
double totalCGP = CalcTotalCGP(courseGP1, courseGP2, courseGP3, courseGP4, courseGP5, courseGP6);
double gpa = CalcGPA(totalCGP, totalCredHours);
lblGPA.Text = gpa.ToString("N");
}
}
else
{
calculate(c);
}
}
}
Create a method that shows the message box with a global flag:
bool showed = false;
private ShowMessageBox(string message)
{
if (!showed)
MessageBox.Show(message);
showed = true;
}
In you code call this method
ShowMessageBox("TextBox cannot be Empty")
instead of
MessageBox.Shows("TextBox cannot be Empty")
You should have following lines:
static bool showed = false; // <---- This line
private void DisplayTextBox(Control con)
{
if (rad1.Checked)
{
foreach (Control c in con.Controls)
{
if (c is TextBox)
{
((TextBox)c).Enabled = false;
txtCCode1.Enabled = true;
txtGrade1.Enabled = true;
}
else
{
DisplayTextBox(c);
}
}
}
showed = false; // <---- This line
}
private void calculate(Control con)
{
foreach (Control c in con.Controls)
{
if (c is TextBox)
{
if (c.Text == "")
{
if (!showed) // <---- This line
{ // <---- This line
showed = true; // <---- This line
DialogResult x = new DialogResult();
x = MessageBox.Show("TextBox cannot be Empty");
if (x == DialogResult.OK)
txtCCode1.Focus();
} // <---- This line
}
else
{
int totalCredHours = 0;
CalcTotalCredHours(credHour1, credHour2, credHour3, credHour4, credHour5, credHour6, ref totalCredHours);
courseGP1 = CalcCourseGradePoint(credHour1, gradePoint1);
courseGP2 = CalcCourseGradePoint(credHour2, gradePoint2);
courseGP3 = CalcCourseGradePoint(credHour3, gradePoint3);
courseGP4 = CalcCourseGradePoint(credHour4, gradePoint4);
courseGP5 = CalcCourseGradePoint(credHour5, gradePoint5);
courseGP6 = CalcCourseGradePoint(credHour6, gradePoint6);
double totalCGP = CalcTotalCGP(courseGP1, courseGP2, courseGP3, courseGP4, courseGP5, courseGP6);
double gpa = CalcGPA(totalCGP, totalCredHours);
lblGPA.Text = gpa.ToString("N");
}
}
else
{
calculate(c);
}
}
}
I you don't want to reshuffle your code much , the best way is to add a break statement if any of the textboxes is Empty.
For e.g
foreach (Control c in con.Controls)
{
if (c is TextBox)
{
if (c.Text == "")
{
DialogResult x = new DialogResult();
x = MessageBox.Show("TextBox cannot be Empty");
if (x == DialogResult.OK)
txtCCode1.Focus();
break;
}

Trying to find controls

I want to add runat=server dynamically to a CheckBoxList so that it can be found by FindControl.
CheckBoxList cbl = new CheckBoxList();
cbl.ID = "cbl" + intQuestionCount.ToString();
// get choices from choice list
int intChoiceListId = Convert.ToInt32(detail.ChoiceListID);
var choiceList = (from cl in _svsCentralDataContext.SVSSurvey_ChoiceListItems
where cl.ChoiceListID == intChoiceListId
orderby cl.Description
select cl);
cbl.DataSource = choiceList;
cbl.DataTextField = "Description";
cbl.DataBind();
cbl.Visible = true;
cbl.CssClass = "PositionCol3";
questionsPanel.Controls.Add(cbl);
I have 2 recursive find control methods:
private HtmlControl FindHtmlControlByIdInControl(Control control, string id)
{
foreach (Control childControl in control.Controls)
{
if (childControl.ID != null && childControl.ID.Equals(id, StringComparison.OrdinalIgnoreCase)
&& childControl is HtmlControl
)
{
return (HtmlControl)childControl;
}
if (childControl.HasControls())
{
HtmlControl result = FindHtmlControlByIdInControl(childControl, id);
if (result != null)
{
return result;
}
}
}
return null;
}
private WebControl FindWebControlByIdInControl(Control control, string id)
{
foreach (Control childControl in control.Controls)
{
if (childControl.ID != null && childControl.ID.Equals(id, StringComparison.OrdinalIgnoreCase)
&& childControl is WebControl
)
{
return (WebControl)childControl;
}
if (childControl.HasControls())
{
WebControl result = FindWebControlByIdInControl(childControl, id);
if (result != null)
{
return result;
}
}
}
return null;
}
The screen is initially created dynamically (if !isPostback), based on an SQL record. The FindControl methods are used after this lot has been displayed, when the user clicks the 'Save' button.
Neither Find control method finds my CheckBoxList!!
You are adding controls through your code behind, they are already server side controls, you don't have to add runat="server". You are not finding them properly.
Make sure they are added to the page before you look for them.

How To Find Checked Radio Button Using Group name My code Attached?

i am trying to find the value of checked radio using group name i have method that return it but what should i pass in that method along with group name
method is here,
private string getRadioValue(ControlCollection clts, string groupName)
{
string ret = "";
foreach (Control ctl in clts)
{
if (ctl.Controls.Count != 0)
{
if (ret == "")
ret = getRadioValue(ctl.Controls, groupName);
}
if (ctl.ToString() == "System.Web.UI.WebControls.RadioButton")
{
RadioButton rb = (RadioButton)ctl;
if (rb.GroupName == groupName && rb.Checked == true)
ret = rb.Attributes["Value"];
}
}
return ret;
}
i use it like
Oc.aProjectSubmited = getRadioValue(RadioButton,"Aps");
where Aps is radio group but getting error "invalid argument" on radio button i pass ??
hopes for your suggestion thanks in advance
This is because you are passing RadioButton. Your method accepts ControlCollection, not a Control.
Why not pass this.Controls to pass the whole ControlCollection of the page? Or any other ControlCollection that you might be using to keep that RadioButton you want to check?
Here's an example:
protected void Page_Load(object sender, EventArgs e)
{
getRadioValue(this.Controls, "Hello");
}
private string getRadioValue(ControlCollection clts, string groupName)
{
string ret = "";
foreach (Control ctl in clts)
{
if (ctl.Controls.Count != 0)
{
if (ret == "")
ret = getRadioValue(ctl.Controls, groupName);
}
if (ctl.ToString() == "System.Web.UI.WebControls.RadioButton")
{
RadioButton rb = (RadioButton)ctl;
if (rb.GroupName == groupName && rb.Checked == true)
ret = rb.Attributes["Value"];
}
}
return ret;
}
Here's a shorter version using Linq to avoid the loops...
public static string GetRadioValue(ControlCollection controls, string groupName)
{
var selectedRadioButton = controls.OfType<RadioButton>().FirstOrDefault(rb => rb.GroupName == groupName && rb.Checked);
return selectedRadioButton == null ? string.Empty : selectedRadioButton.Attributes["Value"];
}
Use LINQ:
container.Controls.OfType<RadioButton>().FirstOrDefault(r => r.GroupName == "GroupName" && r.Checked).Text;
The ToString() is not going to give you what you want: You need somthing more like
private string getRadioValue(ControlCollection clts, string groupName)
{
var ret = "";
foreach (Control ctl in clts)
{
if (ctl.Controls.Count != 0)
{
ret = getRadioValue(ctl.Controls, groupName);
}
if (!string.IsNullOrEmpty(ret)) {
return ret;
}
var rb = ctl as RadioButton;
if (rb != null && rb.GroupName == groupName && rb.Checked)
return = rb.Attributes["Value"];
}
}
return ret;
}
Even more shorter version (in my example I needed the Text of the Radio) Button.
You can also make it as an extension method of HtmlGenericControl which would be div for example.
public static class HtmlGenericControlExtensions
{
/// <summary>
/// Gets selected value of radio button by group name.
/// </summary>
/// <param name="controls">Html generic control.</param>
/// <param name="groupName">Name of the button group.</param>
/// <returns>Selected radio button name.</returns>
public static string GetSelectedRadioButtonName(this HtmlGenericControl control, string groupName)
=> control.Controls
.OfType<RadioButton>()
.FirstOrDefault(rb => rb.GroupName.Equals(groupName) && rb.Checked)?.Text ?? string.Empty;
}

How to eliminate the usage of a nullable bool

I came up with this code, which I thought was rather clever (the requirement is that if the selected date is in the past, the TextBoxes should be readonly, otherwise (today's date or a future date) they should be editable):
bool? setReadOnly = null;
if (SelectedDateIsInThePast() && (!currentlyReadOnly)) {
setReadOnly = true;
} else if (!SelectedDateIsInThePast() && (currentlyReadOnly)) {
setReadOnly = false;
}
if (setReadOnlyToTrue.HasValue) {
foreach (Control ctrl in tableLayoutPanelPlatypus.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
tb.ReadOnly = setReadOnlyToTrue.Value;
}
}
}
...but find that nullable bools are "data type non grata" among my compadres.
Is there a non-complicated way to do the same thing (only loop through the controls if the readonly value needs to be changed?). Of course, I could simply set them regardless of whether they needed to be set this way:
if (SelectedDateIsInThePast()) {
setReadOnly = true;
} else {
setReadOnly = false;
}
foreach (Control ctrl in tableLayoutPanelPlatypus.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
tb.ReadOnly = setReadOnly;
}
}
...but I don't like to perform moot operations, if it's reasonably possible to avoid them.
Factor the loop into a method, and only call the method in the cases you set setReadOnly:
if (SelectedDateIsInThePast() && (!currentlyReadOnly)) {
SetReadOnly(true);
} else if (!SelectedDateIsInThePast() && (currentlyReadOnly)) {
SetReadOnly(false);
}
You can use |=, &=, and two non-nullable booleans to implement the same requirement:
bool forceReadOnly = SelectedDateIsInThePast() && (!currentlyReadOnly);
bool clearReadOnly = !(!SelectedDateIsInThePast() && (currentlyReadOnly));
foreach (Control ctrl in tableLayoutPanelPlatypus.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
tb.ReadOnly |= forceReadOnly;
tb.ReadOnly &= clearReadOnly;
}
}
I think a nullable bool is fine... but another way would be:
public enum ControlState
{
Unknown = 0,
DateInPast,
DateInFuture
}
....
var state = ControlState.Unknown;
if (SelectedDateIsInThePast() && (!currentlyReadOnly)) {
state = ControlState.DateInPast;
} else if (!SelectedDateIsInThePast() && (currentlyReadOnly)) {
state = ControlState.DateInFuture;
}
if (state != ControlState.Unknown) {
foreach (Control ctrl in tableLayoutPanelPlatypus.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
tb.ReadOnly = setReadOnlyToTrue.Value;
}
}
}
Use an enum with three separate, meaningful states ?
enum ShouldSetState
{
No,
SetReadOnly,
SetReadable
}
Then do
ShouldSetState setState = ShouldSetState.No;
if (SelectedDateIsInThePast() && (!currentlyReadOnly)) {
setState = ShouldSetState.SetReadOnly;
} else if (!SelectedDateIsInThePast() && (currentlyReadOnly)) {
setState = ShouldSetState.SetReadable;
}
if (setState != ShouldSetState.No) {
foreach (Control ctrl in tableLayoutPanelPlatypus.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
tb.ReadOnly = setState == ShouldSetState.SetReadOnly;
}
}
}
Your code could be made more consise without using a nullable bool:
bool inThePast = SelectedDateIsInThePast();
if (currentlyReadOnly != inThePast )
{
currentlyReadOnly = inThePast;
foreach(var tb in tableLayoutPanelPlatypus.Controls.OfType<TextBox>())
tb.ReadOnly = currentlyReadOnly;
}
Also, if you have to do a lot of these types of UI manipulations, you might consider data binding.

How can I loop thru all controls (including ToolStripItems) C#

I need to save and restore settings for specific controls on a form.
I loop thru all controls and return the one whose name matches the one I want, like so:
private static Control GetControlByName(string name, Control.ControlCollection Controls)
{
Control thisControl = null;
foreach (Control c in Controls)
{
if (c.Name == name)
{
thisControl = c;
break;
}
if (c.Controls.Count > 0)
{
thisControl = GetControlByName(name, c.Controls);
if (thisControl != null)
{
break;
}
}
}
return thisControl;
}
From this I can determine the type of control and therefore the property that should be / has been stored.
This works well unless the control is one of the ToolStrip family which has been added to a toolstrip. e.g.
this.toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.lblUsername, // ToolStripLabel
this.toolStripSeparator1,
this.cbxCompany}); // ToolStripComboBox
In this case I can see the control I'm interested in (cbxCompany) when debugging, but the name property has no value so the code does not match to it.
Any suggestions on how I can get to these controls too?
Cheers,
Murray
Thanks for your help guys.
Pinichi set me on the right track, I was checking toolStrip.Controls - should have been toolStrip.Items
The code below now works perfectly for me:
private static Control GetControlByName(string controlName, Control.ControlCollection parent)
{
Control c = null;
foreach (Control ctrl in parent)
{
if (ctrl.Name.Equals(controlName))
{
c = ctrl;
return c;
}
if (ctrl.GetType() == typeof(ToolStrip))
{
foreach (ToolStripItem item in ((ToolStrip)ctrl).Items)
{
if (item.Name.Equals(controlName))
{
switch (item.GetType().Name)
{
case "ToolStripComboBox":
c = ((ToolStripComboBox)item).Control;
break;
case "ToolStripTextBox":
c = ((ToolStripTextBox)item).Control;
break;
}
if (c != null)
{
break;
}
}
}
}
if (c == null)
c = GetControlByName(controlName, ctrl.Controls);
else
break;
}
return c;
}
Try This:
//for toolstrip
if (ctrl is ToolStrip)
{
ToolStrip ts = ctrl as ToolStrip;
foreach (ToolStripItem it in ts.Items)
{
if (it is ToolStrienter code herepSeparator)
{
//-------------------------
}
else
{
//do something
}
}
}//---------------

Categories