I'm trying to get all controls in a winform disabled at the Load event.
I have a form (MDI) which loads a Login Form. I want to disable the controls behind the Login Form to only let the user enter his username and password, and then if the user is valid re-enable the controls again.
Just show the login form as a modal dialog, i.e., frm.ShowDialog( ).
Or, if you really want to disable each control, use the Form's Controls collection:
void ChangeEnabled( bool enabled )
{
foreach ( Control c in this.Controls )
{
c.Enabled = enabled;
}
}
I suggest doing it this way instead of simply setting the Form's Enabled propery because if you disable the form itself you also disable the tool bar buttons. If that is ok with you then just set the form to disabled:
this.Enabled = false;
However, if you are going to do this you may as well just show the login prompt as a modal dialog :)
Simple Lambda Solution
form.Controls.Cast<Control>()
.ToList()
.ForEach(x=>x.Enabled = false);
Container like Panel control that contains other controls
then I used queue and recursive function get all controls.
for (Control control in GetAllControls(this.Controls))
{
control.Enabled = false;
}
public List<Control> GetAllControls(Control.ControlCollection containerControls, params Control[] excludeControlList)
{
List<Control> controlList = new List<Control>();
Queue<Control.ControlCollection> queue = new Queue<Control.ControlCollection>();
queue.Enqueue(containerControls);
while (queue.Count > 0)
{
Control.ControlCollection controls = queue.Dequeue();
if (controls == null || controls.Count == 0)
continue;
foreach (Control control in controls)
{
if (excludeControlList != null)
{
if (excludeControlList.SingleOrDefault(expControl => (control == expControl)) != null)
continue;
}
controlList.Add(control);
queue.Enqueue(control.Controls);
}
}
return controlList;
}
Just for some fun with linq, because you can.....
What you could do is create a "BatchExecute" extension method for IEnumerable and update all your controls in 1 hit.
public static class BatchExecuteExtension
{
public static void BatchExecute<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T obj in list)
{
action(obj);
}
}
}
Then in your code....
this.Controls.Cast<Control>().BatchExecute( c => c.enabled = false);
Cool.
I agree that ShowDialog is the way to go, but to answer the original question, you can do this if you want to disable all controls:
foreach (Control c in this.Controls)
{
c.Enabled = false;
}
As Ed said, showing the form as a modal dialog will do what you want. Be sure to check the dialog result returned from ShowDialog in case they cancel it instead of clicking login.
But if you really want to disable all the controls on the form then you should be able to just disable the form itself, or some other parent control like a panel that has all controls in it. That will disable all child controls. This will also allow the child controls to go back to their previous state when the parent control is enabled again.
Trying the ShowDialog show this exception:
Form that is not a top-level form cannot be displayed as a modal dialog box. Remove the form from any parent form before calling showDialog.
What im doing is this:
private void frmControlPanel_Load(object sender, EventArgs e)
{
WindowState = FormWindowState.Maximized;
ShowLogin();
//User = "GutierrezDev"; // Get user name.
//tssObject02.Text = User;
}
private void ShowLogin()
{
Login = new frmLogin
{
MdiParent = this,
Text = "Login",
MaximizeBox = false,
MinimizeBox = false,
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterScreen
};
Login.ShowDialog();
}
Related
I want to enable all controls on a Panel. I can loop through the Panel like below.
This doesn't touch all the components though, just the top level ones.
How do I do this? (This is not the answer)
private void LoopThroughAllControls(System.Windows.Forms.Panel panel)
{
for (int i = 0; i < panel.Controls.Count; i++)
{
panel.Controls[i].Enabled = true;
}
}
ToolStrip code that adds ToolStripButton items:
this.toolStripContractor.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.tsbContractor_AddFile,
this.tsbContractor_View,
this.tsbContractor_Delete});
All you have to do is set the Panel's Enabled property to true or false.
From MSDN's page on the Enabled property:
When a container control has its enabled property set to false, all its contained controls are disabled, as well. For example, if the user clicks on any of the controls contained in a disabled GroupBox control, no events are raised.
If, however, you choose to go with a recursive method, here is how to write it:
void SetEnabledAllChildrenOf(Control control, bool enabled)
{
control.Enabled = enabled;
foreach(Control c in control.Controls)
{
SetEnabledAllChildrenOf(c, enabled);
}
}
I know about the FindControl BUT my button is inside a Login control which is inside a LoginView control,below is my code but its not working!!
Login log = LoginView1.FindControl("Login1") as Login;
Button logButton = log.FindControl("LoginButton") as Button;
this.Form.DefaultButton = logButton.UniqueID;
Th error I get is
Object reference not set to an instance of an object.
FindControl only looks at the immediate children. You'd need to recursively navigate all the children, the children's children, etc., to find the control you're looking for.
public Control MyFindControl(Control parent, string controlIdToFind)
{
foreach(Control c in parent.Controls)
{
Control found = MyFindControl(c, controlIdToFind);
if (found != null)
{
return found;
}
}
// control not found.
return null;
}
Then change your code to:
Button logButton = (Button) MyFindControl(LoginView1, "LoginButton");
if (logButton != null)
{
this.Form.DefaultButton = logButton.UniqueID;
}
I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.
I have a form in which there are some buttons. I'd like put their references in an array.Is it possible with a foreach ?
I want to do this:
public Form1()
{
InitializeComponent();
Button[] all = new Button[5];
all[0] = button1;
all[1] = button2;
all[3] = button3;
all[4] = button4;
}
I've already tried
int i=0;
foreach (Button p in Form1)
{
all[i]= p;
i++;
}
But I can't use a foreach on a Form.
The same thing if the buttons are in a panel.
What can I do to collect all buttons quickly?
Thanks :)
You're looking for the Controls collection of your form or container, which contains every control directly in it.
Beware that this will also include non-Buttons; call .OfType<Button>() to filter.
So instead of the foreach you can initialize an array like this:
Button[] all = this.Controls.OfType<Button>().ToArray();
Every Control has a Controls property which is a ControlCollection. You can get all Buttons on a Control (as a Form or a Panel) like this:
foreach(var button in control.Controls.OfType<Button>())
{ ... }
But this will only give you the Buttons that are contained directly by this control. If you want to get all Buttons in your Form on all Panels, GroupBoxs etc, you need to recurse through the Controlslike in this example:
public class Form1 : Form
{
// ...
private static IEnumerable<Button> GetAllButtons(Control control)
{
return control.Controls.OfType<Button>().Concat(control.Controls.OfType<Control>().SelectMany(GetAllButtons));
}
private void DoSomethingWithAllButtons()
{
foreach(var button in GetAllButtons(this))
{ // do something with button }
}
}
in my application im submitting a data to the db on a tabControls page(page:tabPage2) and i want when hitting the submit button first saving data to db(im achieving this) the a question will ask anything will be done? if the user hit the no button all fields on tabpage2 will reset. so i wrote a script like below but it is not clearing fields.
if (dr == DialogResult.Yes)
{
for (int i = 0; i < this.tabControl1.Controls.Count; i++)
{
if (this.tabControl1.SelectedTab == tabPage2)
{
if (tabPage2.Controls[i] is TextBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is ComboBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is PictureBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is RadioButton)
{
tabPage2.Controls[i].Text = "";
}
}
}
}
If you control the class for the page layout within the specific tab page you want to clear, it's probably best to create a public or internal method in that class (such as Clear()) which can access each of its member controls and clear them directly. That's the easiest approach, and it should usually apply.
If you instead need it to handle a page with an unknown structure, you might need an approach like:
private void ClearControls(Control parentControl)
{
foreach (Control ctrl in parentControl.Controls)
{
TextBox ctrlText;
ComboBox ctrlCombo;
PictureBox ctrlPicture;
RadioButton ctrlRadio;
// Pay careful attention to the parentheses...
if ((ctrlText = ctrl as TextBox) != null)
{
ctrlText.Text = string.Empty;
}
else if ((ctrlCombo = ctrl as ComboBox) != null)
{
ctrlCombo.SelectedIndex = -1;
}
else if ((ctrlPicture = ctrl as PictureBox) != null)
{
// Logic to clear a PictureBox called ctrlPicture
}
else if ((ctrlRadio = ctrl as RadioBox) != null)
{
// Logic to clear a RadioButton called ctrlRadio
}
else if (ctrl.Controls.Count > 0)
{
ClearControls(ctrl); // Recursively clear contained controls.
}
}
}
With a call to start it off from the original handler:
if (dr == DialogResult.Yes)
ClearControls(this.tabControl1);
You are itering over the collection of TabControl child controls, not actual TabPage's.
Change your code to this instead:
if (dr == DialogResult.Yes && this.tabControl1.SelectedTab == tabPage2)
{
foreach (var ctrl in tabPage2.Controls)
{
if (ctrl is TextBox || ctrl is ComboBox || ctrl is PictureBox || ctrl is RadioButton)
{
ctrl.Text = "";
}
}
}
I should say though than setting the Text property to "" for controls other than TextBox feels rather wrong to me. As you'll find out, this won't work for combos, images and radio buttons.
Also if you have controls nested into panels or the like they won't be cleared. Containers have their own nested collection of controls, which in turn can also be containers, and so on and on.
IMHO it would be far better for you to explicitely reset form controls one by one rather than trying to find them dynamically on your form. This way you'll be free to move your controls around at design time without ever worrying about breaking the resetting logic.
Additional suggestion: you can also attach your controls at design time to an instance of your own IExtenderProvider component which will take care of resetting controls appropriately based on their type.