Search function for controls at run time - c#

I have a tab control where I can add custom controls made from a button and a label underneath. I want to add a search function to my project so that when a user type a name of a control, it will show all controls where the name (label) starts with the letters typed. Also typing in a textbox will do the job.. Is there an easy way to do this?

You can search controls within parent control collection:
foreach(Control c in ParentControl.Controls)
{
if(c.Name == "label1")
{
//add to your list
}
}
You can also check using StartsWith("stringVal")
if(c.Name.StartsWith("l"))
{
//add to your list
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
foreach (Control control in this.Controls)
{
// Skip, if the control is the used TextBox
if (control == textBox1) { continue; }
// Show all controls where name starts with inputed string
// (use ToLower(), so casing doesnt matter)
if (control.Name.ToLower().StartsWith(textBox1.Text.Trim().ToLower()))
{
control.Visible = true;
}
// Hide objects that doesn't match
else { control.Visible = false; }
}
}
This toggles the controls' visibility, and hide's all items, that doesn't match the given input. Also casing doesn't matter.

Done when adding the text to search in a textbox.
private void textBox1_TextChanged(object sender, EventArgs e)
{
foreach (Control c in fl_panel.Controls)
{
if (c.Name.ToUpper().StartsWith(textBox1.Text.ToUpper().ToString()) && textBox1.Text != "")
{
Control[] ctrls = fl_panel.Controls.Find(textBox1.Text.ToString(), true);
c.Visible = true; // to restore previous matches if I delete some text
}
else if(textBox1.Text == "")
{
c.Visible = true;
}
else
{
c.Visible = false;
}
}
}

you can try this to find the controls that matches a text typed in the textbox, after that you can do whatever you want with it.
private void textBox1_TextChanged(object sender, EventArgs e)
{
var controlMatchesCriteria = from c in this.Controls.OfType<TextBox>()
where c.Name == textBox1.Text
select c;
}

Related

How to set Textbox.Enabled from false to true on TextChange?

I programmatically create a Form with two textboxes. My goal is to disable one textbox if I type something in the second one and contrariwise. I managed to disable second textbox on first textbox textchange,but can't figure out how enable it when the first textbox.Text is empty.
Here is the code :
private void metaName_TextChanged(object sender,EventArgs e)
{
var ctrl = (Control)sender;
var frm = ctrl.FindForm();
TextBox metaTxt = null;
foreach (var ctr in frm.Controls)
{
if (ctr is TextBox)
{
metaTxt = (TextBox)ctr;
if (metaTxt.Name == "metaHTTPEquiv")
{
metaTxt.Enabled = false;
}
else
if (?)
{
}
}
}
}
I want to make something like this :
if(textBox3.Text == String.Empty)
{
textBox4.Enabled = true;
}
else
if(textBox3.Text != String.Empty)
{
textBox4.Enabled = false;
}
You can check only the textchanged event for each one like the following:
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox2.Enabled = !(textBox1.Text.Length >= 1);
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
textBox1.Enabled = !(textBox2.Text.Length >= 1);
}
The self textbox has some values, then the enabled will be false for the other one
First set a flag to enable or disable the second control based on the content of the metaName textbox that raises the event, then search for the second textbox using a bit of Linq.
private void metaName_TextChanged(object sender,EventArgs e)
{
TextBox ctrl = sender as TextBox;
if(ctrl != null)
{
bool enable = !string.IsNullOrEmpty(ctrl.Text);
TextBox secondOne = this.Controls
.OfType<TextBox>()
.FirstOrDefault(x => x.Name == "metaHTTPEquiv");
if(secondOne != null)
secondOne.Enabled = enable;
}
}
The same code, reversing the textboxes roles, could be used as the event handler of the second textbox.
Forget about control events and use data binding.
Take the following helper method
static void Bind(Control target, string targetProperty, object source, string sourceProperty, Func<object, object> expression)
{
var binding = new Binding(targetProperty, source, sourceProperty, true, DataSourceUpdateMode.Never);
binding.Format += (sender, e) => e.Value = expression(e.Value);
target.DataBindings.Add(binding);
}
and just add something like this in your form load event
Bind(textBox2, "Enabled", textBox1, "Text", value => string.IsNullOrEmpty((string)value));

Radio Button Check Control With Tab Pages

I have a number of different tabs and within the tabs i have some radio buttons. I only want one radio button at a time within the tab pages to be selected. I have the following code
private void RadioButtonCheckedChanged(object sender, EventArgs e)
{
TabControl.TabPageCollection pages = tabControl1.TabPages;
var rdoButtonName = sender as RadioButton;
foreach (TabPage page in pages)
{
foreach (Control item in page.Controls)
{
if (item is RadioButton)
{
if (rdoButtonName.Name == item.Name)
{
rdoButtonName.Checked = true;
}
else
{
rdoButtonName.Checked = false;
}
}
}
}
}
When i go to click on the radio buttons on the first tab page it does not allow me to change their checked status but it does on the other pages. Can anyone see anything wrong with the above code?
I see that you set Cheked value to the sender and not to other radio buttons...
private void RadioButtonCheckedChanged(object sender, EventArgs e)
{
TabControl.TabPageCollection pages = tabControl1.TabPages;
var rdoButtonName = sender as RadioButton;
foreach (TabPage page in pages)
{
foreach (Control item in page.Controls)
{
if (item is RadioButton)
{
if (item.Name != rdoButtonName.Name)
{
item.Checked = false;
}
}
}
}
}
I think (better debug and check) that your problem is that each time you change one of your RadioButton state it will call this function over again and will make the unexpected results.
To fix that I would detach and reattach your event handler before changing the Checked state, like this:
private void RadioButtonCheckedChanged(object sender, EventArgs e)
{
TabControl.TabPageCollection pages = tabControl1.TabPages;
var rdoButtonName = sender as RadioButton;
foreach (TabPage page in pages)
{
foreach (Control item in page.Controls)
{
if (item is RadioButton)
{
rdoButtonName.CheckedChanged -= new System.EventHandler(this.RadioButtonCheckedChanged);
if (rdoButtonName.Name == item.Name)
{
rdoButtonName.Checked = true;
}
else
{
rdoButtonName.Checked = false;
}
rdoButtonName.CheckedChanged += new System.EventHandler(this.RadioButtonCheckedChanged);
}
}
}
}
The problem is, that "CheckedChanged"-event can't be used in this kind of situation, and that is where the problem lies. The key is to use another event - "Click":
private void radioButton_Click(object sender, EventArgs e)
{
foreach (TabPage page in tabControl1.TabPages)
{
foreach (RadioButton radioButton in page.Controls)
{
if (radioButton != (RadioButton)sender) { radioButton.Checked = false; }
}
}
}
Change your RadioButtons to use this method in the "Click"-event and it'll work. I tested it myself.

Reset all the items in a form

I was wondering, is there a way I can reset all the checkboxes, textboxes, numerics and other controls back to the default values without writing code for every control individually? This is the code I've tried, but doesn't seem to work:
for (int i = 0; i < this.Controls.Count; i++)
{
this.Controls[i].ResetText();
}
EDIT:
I've fixed it by manually setting the control values, sorry for all the trouble >.<.
Do as below create class and call it like this
Check : Reset all Controls (Textbox, ComboBox, CheckBox, ListBox) in a Windows Form using C#
private void button1_Click(object sender, EventArgs e)
{
Utilities.ResetAllControls(this);
}
public class Utilities
{
public static void ResetAllControls(Control form)
{
foreach (Control control in form.Controls)
{
if (control is TextBox)
{
TextBox textBox = (TextBox)control;
textBox.Text = null;
}
if (control is ComboBox)
{
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
}
if (control is CheckBox)
{
CheckBox checkBox = (CheckBox)control;
checkBox.Checked = false;
}
if (control is ListBox)
{
ListBox listBox = (ListBox)control;
listBox.ClearSelected();
}
}
}
}
You can create the form again and dispose the old one.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnReset_Click(object sender, EventArgs e)
{
Form1 NewForm = new Form1();
NewForm.Show();
this.Dispose(false);
}
}
foreach (Control field in container.Controls)
{
if (field is TextBox)
((TextBox)field).Clear();
else if (field is ComboBox)
((ComboBox)field).SelectedIndex=0;
else
dgView.DataSource = null;
ClearAllText(field);
}
Additional-> To clear the Child Controls
The below function would clear the nested(Child) controls also, wrap up in a class.
public static void ClearControl(Control control)
{
if (control is TextBox)
{
TextBox txtbox = (TextBox)control;
txtbox.Text = string.Empty;
}
else if (control is CheckBox)
{
CheckBox chkbox = (CheckBox)control;
chkbox.Checked = false;
}
else if (control is RadioButton)
{
RadioButton rdbtn = (RadioButton)control;
rdbtn.Checked = false;
}
else if (control is DateTimePicker)
{
DateTimePicker dtp = (DateTimePicker)control;
dtp.Value = DateTime.Now;
}
else if (control is ComboBox)
{
ComboBox cmb = (ComboBox)control;
if (cmb.DataSource != null)
{
cmb.SelectedItem = string.Empty;
cmb.SelectedValue = 0;
}
}
ClearErrors(control);
// repeat for combobox, listbox, checkbox and any other controls you want to clear
if (control.HasChildren)
{
foreach (Control child in control.Controls)
{
ClearControl(child);
}
}
}
If you have some panels or groupboxes reset fields should be recursive.
public class Utilities
{
public static void ResetAllControls(Control form)
{
foreach (Control control in form.Controls)
{
RecursiveResetForm(control);
}
}
private void RecursiveResetForm(Control control)
{
if (control.HasChildren)
{
foreach (Control subControl in control.Controls)
{
RecursiveResetForm(subControl);
}
}
switch (control.GetType().Name)
{
case "TextBox":
TextBox textBox = (TextBox)control;
textBox.Text = null;
break;
case "ComboBox":
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
break;
case "CheckBox":
CheckBox checkBox = (CheckBox)control;
checkBox.Checked = false;
break;
case "ListBox":
ListBox listBox = (ListBox)control;
listBox.ClearSelected();
break;
case "NumericUpDown":
NumericUpDown numericUpDown = (NumericUpDown)control;
numericUpDown.Value = 0;
break;
}
}
}
You can reset all controls of a certain type. Something like
foreach(TextBox tb in this.Controls.OfType<TextBox>().ToArray())
{
tb.Clear();
}
But you can't reset all controls at once
Quick answer, maybe it'll help:
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.ShowDialog();
while (f2.DialogResult == DialogResult.Retry)
{
f2 = new Form2();
f2.ShowDialog();
}
}
and in Form2 (The 'settings' Form):
private void button1_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
Close();
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Retry;
Close();
}
I recently had to do this for Textboxes and Checkboxes but using JavaScript ...
How to reset textbox and checkbox controls in an ASP.net document
Here is the code ...
<script src="http://code.jquery.com/jquery-1.7.1.js" type="text/javascript"></script>
<script type="text/javascript">
function ResetForm() {
//get the all the Input type elements in the document
var AllInputsElements = document.getElementsByTagName('input');
var TotalInputs = AllInputsElements.length;
//we have to find the checkboxes and uncheck them
//note: <asp:checkbox renders to <input type="checkbox" after compiling, which is why we use 'input' above
for(var i=0;i< TotalInputs ; i++ )
{
if(AllInputsElements[i].type =='checkbox')
{
AllInputsElements[i].checked = false;
}
}
//reset all textbox controls
$('input[type=text], textarea').val('');
Page_ClientValidateReset();
return false;
}
//This function resets all the validation controls so that they don't "fire" up
//during a post-back.
function Page_ClientValidateReset() {
if (typeof (Page_Validators) != "undefined") {
for (var i = 0; i < Page_Validators.length; i++) {
var validator = Page_Validators[i];
validator.isvalid = true;
ValidatorUpdateDisplay(validator);
}
}
}
</script>
And call it with a button or any other method ...
<asp:button id="btnRESET" runat="server" onclientclick="return ResetForm();" text="RESET" width="100px"></asp:button>
If you don't use ValidationControls on your website, just remove all the code refering to it above and the call Page_ClientValidateReset();
I am sure you can expand it for any other control using the DOM. And since there is no post to the server, it's faster and no "flashing" either.
function setToggleInputsinPnl(pnlName) {
var domCount = pnlName.length;
for (var i = 0; i < domCount; i++) {
if (pnlName[i].type == 'text') {
pnlName[i].value = '';
} else if (pnlName[i].type == 'select-one') {
pnlName[i].value = '';
}
}
}
There is a very effective way to use to clear or reset Windows Form C# controls like TextBox, ComboBox, RadioButton, CheckBox, DateTimePicker etc.
private void btnClear_Click(object sender, EventArgs e)
{
Utilities.ClearAllControls(this);
}
internal class Utilities
{
internal static void ClearAllControls(Control control)
{
foreach (Control c in control.Controls)
{
if (c is TextBox)
{
((TextBox)c).Clear();
}
else if (c is ComboBox)
{
((ComboBox)c).SelectedIndex = -1;
}
else if (c is RadioButton)
{
((RadioButton)c).Checked = false;
}
else if (c is CheckBox)
{
((CheckBox)c).Checked = false;
}
else if (c is DateTimePicker)
{
((DateTimePicker)c).Value = DateTime.Now; // or null
}
}
}
}
To accomplish this with overall user experience in c# we can use one statement to clear them. Pretty straight forward so far, above is the code.

Dynamically filtering a menu (ContextMenuStrip) in C# without recreating the menu?

Is this possible?
I plan to have 10 menu items where these are going to have sub-menu items (1 level deep only). I want to be able to filter them when the user types into my TextBox control. I know I can filter items upon opening the menu for the first time, but I want to be able to continually filter it as the user types and hide categories on the fly when the category menu item has no subitems applicable for the current filter (by name filtering).
Any ideas?
I added a context menu strip (menuStrip1). To this I added the following:
File
Exit
Edit
Copy
Paste
Further Down
Help
Arghhhh!
I then added a text box (FilterMenuText), and, on the OnTextChanged event, do the following:
private void FilterMenuText_TextChanged(object sender, EventArgs e)
{
foreach (ToolStripMenuItem menuItem in menuStrip1.Items)
{
if (menuItem.DropDownItems.Count > 0)
{
bool matchFound = false;
foreach (ToolStripMenuItem childMenuItem in menuItem.DropDownItems)
{
if (childMenuItem.Text.ToUpper().Contains(FilterMenuText.Text.ToUpper()))
{
matchFound = true;
break;
}
}
menuItem.Visible = matchFound;
}
}
}
This will hide and show the top level MenuItems as appropriate based on the content of the child menu items. If your menu has more than one level of drop down, put the foreach into a recursive function, like:
private void FilterMenuText_TextChanged(object sender, EventArgs e)
{
foreach (ToolStripMenuItem menuItem in menuStrip1.Items)
{
menuItem.Visible = MenuItemHasChildWithName(menuItem, FilterMenuText.Text);
}
}
private bool MenuItemHasChildWithName(ToolStripMenuItem menuItem, string name)
{
if (!menuItem.HasDropDownItems)
{
return false;
}
bool matchFound = false;
foreach (ToolStripMenuItem childMenuItem in menuItem.DropDownItems)
{
if (childMenuItem.Text.ToUpper().Contains(name.ToUpper()))
{
matchFound = true;
break;
}
if (childMenuItem.HasDropDownItems)
{
matchFound = MenuItemHasChildWithName(childMenuItem, name);
if(matchFound) { break; }
}
}
return matchFound;
}
This is what I used for conditionaly showing menu items on a context menu. If you use the same menu and don't want to show it, you merely set each item in the same loop to true;
private void dgViewData_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dgViewData.HitTest(e.X, e.Y).Type != DataGridViewHitTestType.ColumnHeader)
{
foreach (ToolStripMenuItem menuItem in conMicImport.Items)
{
menuItem.Visible = menuItem.Text.ToString().Contains("Add") == true ? false : true;
}
conMicImport.Show(dgViewData, e.Location);
ctxtDG = dgViewData;
}
}
}
Set the toolstrip object's Visible property to false when you don't want it to appear.
for example purposes I have done this using a web forms application
foreach (Control c in Page.Form.Controls)
{
//Response.Write("WORD2" + c.GetType());
if (c is Panel)
{
foreach (Control p in c.Controls)
{
if (p is CheckBoxList)
{
foreach (ListItem li in ((CheckBoxList)p).Items)
{
li.Selected = false;
}
}
}
}
}

Adding different controls having same names in C# Windows Form

I am working in C# windows forms application in which I am adding 3 different controls having same name (a button, a textBox & a Label) to my form.
Why there is error in button4_Click?
CODE:
private void button1_Click(object sender, EventArgs e)
{
TextBox myControl = new TextBox();
myControl.Name = "myControl";
this.Controls.Add(myControl);
}
private void button2_Click(object sender, EventArgs e)
{
Button myControl = new Button();
myControl.Name = "myControl";
this.Controls.Add(myControl);
}
private void button3_Click(object sender, EventArgs e)
{
Label myControl = new Label();
myControl.Name = "myControl";
this.Controls.Add(myControl);
}
private void button4_Click(object sender, EventArgs e)
{
((ComboBox)this.Controls["myControl"]).Text = "myCombo"; // works
((TextBox)this.Controls["myControl"]).Text = "myText"; // error
((Label)this.Controls["myControl"]).Text = "myLabel"; // error
}
The Controls[string] indexer returns the first control whose name matches the string. It will be hit and miss with your code but you probably have a ComboBox already added to the form with that same name. The next statements go kaboom because you cannot cast a ComboBox to a TextBox.
Of course, do try to do the sane thing, give these controls different names.
this.Controls["myControl"] returns the first control named myControl.
This is a TextBox, not a Label.
Instead of accessing them through the Controls collection, you should store your controls in fields in the form class (perhaps using List<T>s).
Here is one idea that might help you:
void SetControlText(Type controlType, string controlName, string text) {
foreach (var ctl in this.Controls.OfType<Control>()) {
if (ctl.GetType() == controlType && ctl.Name == controlName) {
ctl.Text = text;
break;
}
}
}
Or with LINQ only:
var item = this.Controls.OfType<Control>().Where(j => j.GetType() == controlType && j.Name == controlName).FirstOrDefault();
if (item != null)
item.Text = text;
Simply call the above function like so:
SetControlText(typeof(Button), "myButton", "Text was set!");
This function will iterate through all of the controls on the form, and when it finds the control type you specify with the name you specify, it will update the controls .Text field.

Categories