I have a Form that contains a TabControl and an ErrorProvider. One of the tabs has several textboxes and a button. The textboxes use the Validating event to SetError() if contents are not valid. When the button is pressed, this runs:
bool ok = true;
foreach (Control c in errorProviderDv.ContainerControl.Controls)
{
MessageBox.Show(c.Name);
if (errorProviderDv.GetError(c) != "")
{
ok = false;
}
}
The TabControl is the only control in errorProviderDv.ContainerControl.Controls, even though several errors are set and are displaying in the form.
Am I doing something wrong? Does the ErrorProvider need to be a child of the tab instead of the form?
The TabControl itself is a container which contains TabPages. Those TabPages are containers which contain your textboxes.
The following code will get you want you want but you may want to clean it up to make a recursive call passing in a container so it will work for almost any type.
private void button1_Click(object sender, EventArgs e)
{
bool ok = true;
foreach (Control c in errorProviderDv.ContainerControl.Controls)
{
if (c is TabControl)
{
foreach (Control t in (c as TabControl).SelectedTab.Controls)
{
MessageBox.Show(t.Name);
if (errorProviderDv.GetError(t) != "")
{
ok = false;
}
}
}
}
}
Related
For instance, I want all my text boxes to respond to Ctrl-A by selecting all text. I see several options:
Add an event handler to all the text boxes that takes care of the keyboard shortcuts
Subclass TextBox and replace all my text boxes with it
Create a user control that wraps TextBox and replace all my text boxes with it
However all of these involve changing each and every text box in the app. Is there any sort of thing I could do globally to all text boxes via one action to accomplish this? I kind of doubt it but I thought it wouldn't hurt to ask! (I mean, I suppose now that .NET is open source I could build a custom framework, but that's definitely overkill!)
I have a idea about that. The first step is get all controls of a control. Like this method:
public static IEnumerable<Control> GetAllControls(Control container)
{
List<Control> controlList = new List<Control>();
foreach (Control c in container.Controls)
{
controlList.AddRange(GetAllControls(c));
controlList.Add(c);
}
return controlList;
}
You can improve this method to get just the TextBox's.
So, now you have all the TextBoxes that you want. You can add a event for each, something like that:
foreach( var textBox in textBoxList )
{
textBox.KeyPress += MeyKeyPressEvento_KeyPress;
}
Or you can put that event int your form and select all TextBoxes.
I hope you can get a mindset with my answer. Good luck 🖖🏻
Dynamically attach your events when you load your form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// iterate all controls on the form
foreach (Control control in this.Controls)
{
if (control is TextBox textBox)
{
// attach your event's method
textBox.KeyDown += OnKeyDown_SelectAllText;
}
}
}
private void OnKeyDown_SelectAllText(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.A)
{
TextBox textBox = (TextBox) sender;
textBox.SelectAll();
}
}
// be sure to detach all events when done with form
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (Control control in this.Controls)
{
TextBox textBox = control as TextBox;
if (textBox != null)
{
textBox.KeyDown -= OnKeyDown_SelectAllText;
}
}
}
}
I've got these functions:
private void setupFocusControls(Control parent)
{
foreach (Control control in parent.Controls)
{
control.GotFocus += HandleFocus;
}
}
private void HandleFocus(object sender, EventArgs e)
{
Control control = (Control)sender;
thisFormName = this.Name;
thisControlName = control.Name.ToString();
if (bHelpSystemActive)
{
bHelpSystemActive = false;
if ((ModifierKeys & Keys.Control) == Keys.Control)
{
HelpSystem hs = new HelpSystem(thisFormName, thisControlName);
hs.ShowDialog();
}
else
{
showTooltipForControl(control, thisFormName);
}
return;
}
}
And I call this in the Form_Load function:
private void Labeller_Load(object sender, EventArgs e)
{
setupFocusControls(this);
fillListBox();
}
What this does is show a custom help system I've written. If no control key is clicked, then I'll display the info in a tool tip. If the control key is pressed, then I show an editor. Simple really.
Now, this code works perfectly on another form, which uses panels as containers for my form controls. The problem is, I now want to add this functionality to a separate form. I've added all the code, but none of the controls on the form are having the HandleFocus event added to them. The only difference between this form and the working one is that it uses a splitContainer as it's container.
My question is, why is the setupFocusControls function not looping through the splitContainer as it does the panels on my working form? And, how would I go about fixing it? I'd obviously rather not have several functions to perform this (what I thought) simple task...
Cheers.
Assuming that the problem is that you are not assigning the event to every single control on the form (only top-level controls), the fix should be to change your setupFocusControls(Control) method:
private void setupFocusControls(Control parent)
{
foreach (Control control in parent.Controls)
{
control.GotFocus += HandleFocus;
// add the following line to recurse throughout the control tree
setupFocusControls(control);
}
}
This will add the HandleFocus event handler to every single control, by recursing through the children of every control. I hope this works for you!
As a bonus, if you want to add the event handler to all controls, including the parent control, you could write the setupFocusControls method as follows:
private void setupFocusControls(Control parent)
{
parent.GotFocus += HandleFocus;
foreach (Control child in parent.Children)
setupFocusControls(child);
}
I am new to c# programming and u might feel its very simple ...
I am using menu bar(tool strip) with Add, update,delete, cancel and close buttons...
In add button i have....
private void btn_Add_Click(object sender, EventArgs e)
{
NewSavebtn();
}
public void NewSavebtn()
{
if (btn_Add.Text == "&New")
{
btn_Add.Text = "&Save";
btn_Edit.Enabled = false;
btn_Delete.Enabled = false;
txtDetailName.Enabled = true;
TxtHeadName.Enabled = true;
UnLock();
}
else if (btn_Add.Text == "&Save")
{
save_data();
Lock();
btn_Add.Text = "&Add";
btn_Edit.Enabled = true;
btn_Delete.Enabled = true;
ClearAll();
txtDetailName.Enabled = false;
}
else
MessageBox.Show("cant save data");
}
#region Clear Lock Unlock
public void ClearAll()
{
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox || ctl is ComboBox)
{
ctl.Text = "";
}
}
}
public void Lock()
{
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox || ctl is ComboBox)
{
ctl.Enabled=false ;
}
}
}
public void UnLock()
{
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox || ctl is ComboBox)
{
ctl.Enabled=true ;
}
}
}
#endregion
I want to add same code in almost 200+ forms.
can anyone tell me what i suppose to do for it.
Is there any user control or master control like asp.net in c# so that common code can be kept aside and called when its necessary...
because if i put the NewSavebtn() and other methods in different class say class1 and try to call it from form1 like...
class1 c1 =new class1(this);
c1.NewSavebtn(this);
It does not work....
Thnks in advance....
If this is for a Windows forms application then you can Create a User Control, and if you are developing WPF application then you may see the following tutorial: How to Create a WPF User Control & Use It in a WPF Application ( C# )
You can create user control in windows form to use through a hundred forms. However, I think your code is not easy to change in terms of maintenance. You should use delegate to handle the event. For future improvement, you can easily to define your results with the use of delegate Execute a delegate in the ui thread (using message pump).
Im implementing application which has main window and in this second window which has a lot of tabs in tabcontrol.
On each tab I have a lot of control which values may be edited by user, some of them has to be filled, some need to has values between x and y and so on.
Main windows has got save button. Point is that if in any tab control isnt validated then saving shouldnt be possible and appropriate tab should be opened and validation shown. Could you please tell me any advice of how to create such mechanism ? Maybe any generic methods ?
thanks for help
Try this link
WinForms TabControl validation: Switch to a tab where validation failed
Dictionary<TabPage, HashSet<Control>> _tabControls
= new Dictionary<TabPage, HashSet<Control>>();
public OptionsForm()
{
InitializeComponent();
RegisterToValidationEvents();
}
private void RegisterToValidationEvents()
{
foreach (TabPage tab in this.OptionTabs.TabPages)
{
var tabControlList = new HashSet<Control>();
_tabControls[tab] = tabControlList;
foreach (Control control in tab.Controls)
{
var capturedControl = control; //this is necessary
control.Validating += (sender, e) =>
tabControlList.Add(capturedControl);
control.Validated += (sender, e) =>
tabControlList.Remove(capturedControl);
}
}
}
private void Ok_Button_Click(object sender, EventArgs e)
{
if (this.ValidateChildren())
{
_settings.Save();
this.Close();
}
else
{
var unvalidatedTabs = _tabControls.Where(kvp => kvp.Value.Count != 0)
.Select(kvp => kvp.Key);
TabPage firstUnvalidated = unvalidatedTabs.FirstOrDefault();
if (firstUnvalidated != null &&
!unvalidatedTabs.Contains(OptionTabs.SelectedTab))
OptionTabs.SelectedTab = firstUnvalidated;
}
}
I have a winforms app and the main (and only) form has several buttons. When the user clicks a button, I want all other buttons to be disabled.
I know I could do this the long way by setting "Enabled" to false on all buttons but the one which has been clicked in the clicked event handler of that button, but this is a long and tedious approach.
I got the collection of controls on the form, but this does not include the several buttons I have:
System.Windows.Forms.Control.ControlCollection ctrls = this.Controls;
How can I go about implementing this functionality in a mantainable fashion?
Thanks
DisableControls(Control c)
{
c.Enable = false;
foreach(Control child in c.Controls)
DisableControls(child)
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
Button btn = (Button)ctrl;
btn.Click += ButtonClick;
}
}
}
private void ButtonClick(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
Button btn = (Button)ctrl;
if (btn != (Button)sender)
{
btn.Enabled = false;
}
}
}
}
You could use databinding, so you only iterate once on startup:
public partial class Form1 : Form
{
public bool ButtonsEnabled { get; set; }
public Form1()
{
InitializeComponent();
// Enable by default
ButtonsEnabled = true;
// Set the bindings.
FindButtons(this);
}
private void button_Click(object sender, EventArgs e)
{
// Set the bound property
ButtonsEnabled = false;
// Force the buttons to update themselves
this.BindingContext[this].ResumeBinding();
// Renable the clicked button
Button thisButton = sender as Button;
thisButton.Enabled = true;
}
private void FindButtons(Control control)
{
// If the control is a button, bind the Enabled property to ButtonsEnabled
if (control is Button)
{
control.DataBindings.Add("Enabled", this, "ButtonsEnabled");
}
// Check it's children
foreach(Control child in control.Controls)
{
FindButtons(child);
}
}
}
Expanding on Alex Reitbort's answer, here's an example method I just wrote 20 minutes ago for this project I'm doing:
private void Foo(bool enabled)
{
foreach (Control c in this.Controls)
if (c is Button && c.Tag != null)
c.Enabled = enabled;
}
This function is not recursive like his is. However, because I know there are no Buttons within a container other than my form so I don't need to worry about that. If there were child controls (ie controls within a GroupBox for example), I'd probably modify that code to be something like this;
private void ToggleControls()
{
Foo(this.Controls, false) // this being the form, of course.
}
private void Foo(Control.ControlCollection controls, bool enabled)
{
foreach (Control c in controls)
{
if (c is Button && c.Tag != null)
c.Enabled = enabled;
if (c.HasChildren)
Foo(c.Controls, enabled);
}
}
I actually like his method a little more, that style of recursion looks a little cleaner than mine I think. Just showing you an alternate way.
Note; I have 6 buttons on my form and I only want 4 of them to have their Enabled property modified by this method. To accomplish this, I set their Tag property to some random string. That is why I check for c.Tag in my if statements. You can remove that if you know you want to disable every control.