how to give same property to all textboxes present in the same form.
foreach (var textbox in this.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
The above code works only if the textboxes are not in nested format.
In my project I have multiple tabpages in tabcontrol. so i cant implement the above code. but i can implement the below code:
foreach (TextBox textbox in this.Controls.OfType<TabControl>().SelectMany(tc => tc.Controls.OfType<TabPage>().SelectMany(page => page.Controls.OfType<TextBox>())))
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabCarInsurance.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabHomeLoans.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabRetirement.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
Here I am implementing for each tabControl. which still i dont like (because I have more tab pages to take care of). Is there anyway to reduce the above code.
I tried the below code: (not working)
foreach (var textbox in this.Controls.OfType<TabControl>().OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
I got the above code knowledge from my previous question.
Please Help
Thanks in Advance.
private void SetProperty(Control ctr)
{
foreach(Control control in ctr.Controls)
{
if (control is TextBox)
{
control.ContextMenu = new ContextMenu();
}
else
{
if (control.HasChildren)
{
SetProperty(control);
}
}
}
}
How about an extension method to do it, called from your tabcontrol container...
public static class ControlExtensions
{
public static void SetContextMenuOnChildTextBoxes(this Control control)
{
if (control is TextBox)
{
control.ContextMenu = new ContextMenu();
}
if (control.Controls != null)
{
foreach (Control controlChild in control.Controls)
{
controlChild.SetContextMenuOnChildTextBoxes();
}
}
}
}
This could be put in a common area of code so that it could be called from any parents that wanted this functionality.
Just use the recursion to go through all controls subcollections:
void SetControl(ContextMenu menu, Control control)
{
if (control is TextBox)
control.ContextMenu = menu;
else
{
foreach (Control c in control.Controls)
SetControl(menu, c);
}
}
It will find all the textboxes and set one and the same context menu to all of them.
You mal call it,say, from form's OnLoad event handler. While it's assumed that you have yourContextMenu defined for the form.
private void Form1_Load(object sender, EventArgs e)
{
SetControl(yourContextMenu, this);
}
Try:
private void CtxMenu(Control parent)
{
foreach (Control child in parent.Controls)
{
if (child is TextBox)
{
(child as TextBox).ContextMenu = new ContextMenu();
}
}
Related
I started making a small program. The form contains checkbox1,2,3,4,.... and textbox1,2,3,4,5.... there is a code that looks at which of the checkboxes are marked. If there is any possibility to link textbox and checkbox. So that when a code marked with a checkbox is detected, the text is taken from the textbox given to it and transferred to the RichTextBox, using AppendText. Below is a sample code with a cyclic check of all the checkboxes on the form for the presence of checked on my form.
foreach (Control control in this.tabControl1.TabPages[0].Controls) //цикл по форме с вкладками
{
if (control as CheckBox != null) // проверка на пустое значение
{
if (control.Visible == true)// проверка на видимость
{
if ((control as CheckBox).Checked)// проверка на чек
{
}
else if ((control as CheckBox).Checked == false)
{
}
}
}
Use the following method to get CheckBox controls.
public static class ControlExtensions
{
public static IEnumerable<T> Descendants<T>(this Control control) where T : class
{
foreach (Control child in control.Controls)
{
if (child is T thisControl)
{
yield return (T)thisControl;
}
if (child.HasChildren)
{
foreach (T descendant in Descendants<T>(child))
{
yield return descendant;
}
}
}
}
}
In the form, use a Dictionary to pair CheckBox to TextBox. You can also check for visibility in the Where.
public partial class Form1 : Form
{
private readonly Dictionary<string, TextBox> _dictionary =
new Dictionary<string, TextBox>();
public Form1()
{
InitializeComponent();
_dictionary.Add("checkBox1", textBox1);
_dictionary.Add("checkBox2", textBox2);
_dictionary.Add("checkBox3", textBox3);
_dictionary.Add("checkBox4", textBox4);
_dictionary.Add("checkBox5", textBox5);
}
private void button2_Click(object sender, EventArgs e)
{
var list = tabControl1.Descendants<CheckBox>().ToList();
var #checked = list.Where(x => x.Checked).ToList();
var notChecked = list.Where(x => !x.Checked).ToList();
foreach (var checkBox in #checked)
{
TextBox textBox = _dictionary[checkBox.Name];
}
}
}
Create a UserControl with CheckBox and TextBox components. Create properties Checked and TextForAdd:
namespace Sort.UserPanel
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public bool Checked { get { return checkBox1.Checked; } }
public string TextForAdd { get { return textBox1.Text; } }
}
}
On the main form we add UserControl1 the necessary number of times.
private void testCheckBoxes(object obj)
{
if (obj is UserControl1 control)
{
string text = control.TextForAdd;
// .....
}
}
private void button1_Click(object sender, EventArgs e)
{
foreach (Control control in this.LeftPanel.Controls)
{
if (control as UserControl1 != null)
{
if (control.Visible == true )
{
testCheckBoxes(control);
}
}
}
}
I have an issue in my project where I have to use "n" number of Usercontrols with tabcontrol's in them.
I am creating txt files with the name and state of all the controls present in the Usercontrols.
The problem is that I can't seem to access the state of the tabcontrol and all the controls in it.
I use this command that works for all the other controls appart from the tabcontrol one...
Any help would be well appreciated.
sw = new StreamWriter(filename.txt);
foreach (Control crl in theformname.Controls)
{
TabPage tab = new TabPage();
if (crl.GetType() == tab.GetType())
{
sw.WriteLine ("tabcontrol accessed");
if (Ctrl.GetType() == cbx.GetType())
{
CheckBox CheckBoxCrt;
CheckBoxCrt = (CheckBox)Ctrl;
sw.WriteLine(CheckBoxCrt.Checked.ToString()); //State of the checkbox
}
}
}
The following would need one layer above TabControl for your UserControl which would be done by mimicking TabControlList or CheckBoxList
Example
public static List<UserControlType> MyUserControlList(this Control control)
=> control.Descendants<UserControlType>().ToList();
Here are the current methods for use in the next code block.
public static class GenericExtensions
{
public static IEnumerable<T> Descendants<T>(this Control control) where T : class
{
foreach (Control child in control.Controls)
{
if (child is T thisControl)
{
yield return (T)thisControl;
}
if (child.HasChildren)
{
foreach (T descendant in Descendants<T>(child))
{
yield return descendant;
}
}
}
}
public static List<TabControl> TabControlList(this Control control)
=> control.Descendants<TabControl>().ToList();
public static List<CheckBox> CheckBoxList(this Control control)
=> control.Descendants<CheckBox>().ToList();
}
Usage (remember you need to add a list above the TabControl check) using a StringBuilder which can be used to write wherever you want e.g. filename.txt.
StringBuilder builder = new StringBuilder();
var tabs = this.TabControlList();
foreach (TabControl tab in tabs)
{
builder.AppendLine(tab.Name);
foreach (CheckBox box in tab.CheckBoxList())
{
builder.AppendLine($"\t{box.Parent.Name,-20}{box.Name, -20}{box.Checked}");
}
}
Debug.WriteLine(builder);
I have a custom extension method that (is supposed to) find a control via a string, and perform a click to that control. I've set up a break point and it nevers into the if (c is ToolStripMenuItem) Anyone have any idea where I'm going wrong? This is on WinForms.
private void PerformClickfromString()
{
string item = File.ReadAllText(#"C:\controltest.txt");
foreach (var c in this.Controls)
{
if (c is ToolStripMenuItem)
{
var x = (ToolStripMenuItem)c;
if (x.Name == item)
{
x.PerformClick();
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
PerformClickfromString();
}
Any help is appreciated.
To find all nested items you need a recursive search. Here is an example; it collects all items in a List<ToolStripMenuItem> and the checks for the searched name. I have added that string to the signature of your call..:
private void PerformClickfromString(string s)
{
foreach (var c in this.Controls)
{
List<ToolStripMenuItem> items = new List<ToolStripMenuItem>();
if (c is MenuStrip)
{
foreach (ToolStripMenuItem tsItem in ((MenuStrip)c).Items)
{
GetAllMenuItems(items, tsItem);
}
}
ToolStripMenuItem found = items.Find(x => x.Name == s);
if (found != null) found.PerformClick();
}
}
void GetAllMenuItems(List<ToolStripMenuItem> items, ToolStripMenuItem menu)
{
items.Add(menu);
foreach(ToolStripMenuItem m in menu.DropDownItems)
GetAllMenuItems(items, m);
}
The ToolStripMenuItem is not considered a control, you must instead use its container
if(c is MenuStrip)
{
foreach(ToolStripMenuItem tsItem in ((MenuStrip)c).Items)
{
if (tsItem.Name == item)
{
tsItem.PerformClick();
}
}
}
How can I Set the special property of multiple controls to the same value?
For example set the visible property of all labels in the form to true.
I use this code but labels appear to have null values but they have values.
protected void Page_Load(object sender, EventArgs e)
{
foreach ( Label lbl in this.Controls.OfType<Label>()) {
if (lbl == null) continue;
lbl.Visible = false;
}
}
I should mention that I use master page.But I don't want to set the properties of my nested master pages. I want to set the properties of just current ASP page.
You may have some controls within others, so you need to call it recusrively....Here's a similat method I use..............
Notice at the end, I call it from within itself if the Control in question has controls of its' own....
Hope this helps.....
private void ClearControls(ControlCollection controlCollection, bool ignoreddlNewOrExisting = false)
{
foreach (Control control in controlCollection)
{
if (ignoreddlNewOrExisting)
{
if (control.ID != null)
{
if (control.ID.ToUpper() == "DDLNEWOREXISTING")
{
continue;
}
}
}
if (control is TextBox)
{
((TextBox)control).Text = "";
((TextBox)control).Font.Size = 10;
}
if (control is DropDownList)
{
((DropDownList)control).SelectedIndex = 0;
((DropDownList)control).Font.Size = 10;
}
if (control is CheckBox)
{
((CheckBox)control).Checked = false;
}
//A bit of recursion
if (control.Controls != null)
{
this.ClearControls(control.Controls, ignoreddlNewOrExisting);
}
}
}
Note that you can use following to avoid this ugly type check.:
foreach(Label lbl in this.Controls.OfType<Label>())
lbl.Visible= false;
But neither your nor my approach will enumerate all controls recursively. Only the controls which are on top of the page. So you won't find labels in nested controls(f.e. in a GridView) or which are in the MasterPage. Therefore you need a recursive method.
You could use this handy extension method:
public static class ControlExtensions
{
public static IEnumerable<Control> GetControlsRecursively(this Control parent)
{
foreach (Control c in parent.Controls)
{
yield return c;
if (c.HasControls())
{
foreach (Control control in c.GetControlsRecursively())
{
yield return control;
}
}
}
}
}
Then this readable code should hide all labels on the page and in the MasterPage:
var allLabels = this.GetControlsRecursively()
.Concat(this.Master.GetControlsRecursively())
.OfType<Label>();
foreach (Label label in allLabels)
label.Visible = false;
protected void Page_Load(object sender, EventArgs e)
{
SetAllLabelValue(this.Controls);
}
private void SetAllLabelValue(ControlCollection controls)
{
foreach (Control item in controls)
{
if (item.HasControls())
{
SetAllLabelValue(item.Controls);
}
Label lb = item as Label;
if (lb != null)
{
lb.Visible = false;
}
}
}
I have a GUI class. I pass a frmMain (form) to GUI contructor. Then I have the following method to access child controls:
public void assignEvents(frmMain frm)
{
foreach (Control ctl in frm.Controls)
{
ctl.BackColor = Color.GreenYellow;
Log.AddData(ctl.Name.ToString() + ".Backcolor = " + ctl.BackColor.ToString(), 3);
}
}
I get the new updated color in the output (log), but it takes no effect on controls and they are still in default color. Any ideas what I'm doing wrong?
EDIT:
I call it like this:
// GUI.cs
public class GUI {
public GUI(frmMain frm){
assignEvents(frm);
}
}
// frmMain.cs
public frmMain()
{
InitializeComponent();
gui = new M.Gui (this);
}
Based on your comment, you need to try to go recursively through each ControlCollection to set the BackColor property.
Try changing your code to something like this:
public GUI(frmMain frm) {
assignEvents(frm.Controls);
}
public void assignEvents(Control.ControlCollection controls) {
foreach (Control ctl in controls) {
ctl.BackColor = Color.GreenYellow;
assignEvents(ctl.Controls);
}
}