I have a lot of SimpleButton (DevExpress Controls) in my form. I want to set AllowFocus to false for them through code.
foreach (Control x in this.Controls)
{
if (x is SimpleButton)
{
((SimpleButton)x).AllowFocus = false;
}
}
Nothing really happen when I use this code. It still allow focus.
From your comment, it is clear that SImpleButton objects are not directly on the Form, so iterating the Form's Controls collection is not going to return those.
You need to iterate the GroupControl's Controls collection.
Cheers
Solved :
foreach (Control x in groupControl1.Controls)
{
if (x is SimpleButton)
{
((SimpleButton)x).AllowFocus = false;
}
}
Try it this way:
var buttons = this.Controls.OfType<Control>()
.SelectMany(x => x.Controls.OfType<SimpleButton>());
foreach(var button in buttons)
button.AllowFocus = false;
I suggest better to have Re-cursive function, I generally place all controls in main container panel, and you just need pass that container to Function, rest of things function will do for you.
private void FocusControls(Control ctl)
{
if ((ctl.GetType() == typeof(GroupBox)) ||
(ctl.GetType() == typeof(DevExpress.XtraEditors.GroupControl)) ||
(ctl.GetType() == typeof(DevExpress.XtraEditors.PanelControl)) ||
(ctl.GetType() == typeof(DevExpress.XtraTab.XtraTabControl)) ||
(ctl.GetType() == typeof(DevExpress.XtraTab.XtraTabPage))
)
{
foreach (Control obj in ctl.Controls)
FocusControls(obj);
}
if (ctl.GetType() == typeof(SimpleButton))
{
SimpleButton objTemp = (SimpleButton)ctl;
objTemp.AllowFocus = false;
}
}
Might just be a case of checking the types:
if (typeof(x) == typeof(SimpleButton))
Related
I am making a Winforms application. Because I want to redraw some borders I want to loop through the controls and check which controls have a border. Unfortunately I have no idea how to accomplish this.
I know panels and textboxes, etc. have a property BorderStyle but I can not access it while looping through Controls. I use the function from this link : https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.controls?view=netframework-4.8 , to loop through the controls.
If you have a panel you can foreach on the panel. I use form load as an event
private void Form1_Load(object sender, EventArgs e)
{
foreach (var item in this.Controls)
{
switch (item.GetType().Name)
{
case "Label":
if (((Label)item).BorderStyle == BorderStyle.None)
{
//Your commands
}
break;
case "TextBox":
if (((TextBox)item).BorderStyle == BorderStyle.None)
{
//Your commands
}
break;
}
}
}
Or you can check them dynamic
I recommend you to use the dynamic way.
in this way, your app wouldn't encounter exceptions or errors
foreach (var item in this.Controls)
{
//Get item from form
dynamic element = item;
//check if there is any property called Borderstyle exists
var res = item.GetType().GetProperties().Where(p => p.Name.Equals("BorderStyle")).FirstOrDefault();
//if it exists and value is not equal None(Control have border)
if (res !=null && !(res.GetValue(item).Equals("None")))
{
res.SetValue(item, BorderStyle.FixedSingle, null);
//your other commands
}
}
You could use a foreach for every type of control you use (TextBox, Label, etc.)
var controlsWithoutBorders = new List<Control>();
// Check textboxes
foreach (var control in controls.OfType<TextBox>())
{
if (control.BorderStyle != BorderStyle.None)
{
controlsWithoutBorders.Add(control);
}
}
//Check labels
foreach (var control in controls.OfType<Label>())
{
if (control.BorderStyle != BorderStyle.None)
{
controlsWithoutBorders.Add(control);
}
}
Alternatively, you could use a single foreach on all the controls, and try to cast the control to each type. The cast will be successful if the control is actually what you want to cast it to, otherwise it will return null (e.g. trying to cast a Control that is a TextBox to a Label will return null)
var controlsWithoutBorders = new List<Control>();
foreach (var control in controls)
{
var controlAsTextBox = control as TextBox;
var controlAsLabel = control as Label;
if (controlAsTextBox != null && controlAsTextBox.BorderStyle != BorderStyle.None)
{
controlsWithBorders.Add(control);
}
if (controlAsLabel != null && controlAsLabel.BorderStyle != BorderStyle.None)
{
controlsWithBorders.Add(control);
}
}
Though this method is not the fastest at run time, your problem could be cleanly solved with the use of C#'s dynamic typing feature. Consider the below snippet of code.
public void DealWithBorder(List<Control> lsControls) {
foreach(var element in lsControls){
dynamic dynamicElement = element;
try{
BorderStyle style = dynamicElement.BorderStyle;
// Handle if property does exist in the control
}
catch{
// Handle if property doesnt exist in the control
}
}
}
In English, it will try to act as if the property exists in the object but if it does not, an exception will thrown. For more info on dynamic typing, click here.
hi all here i try to make method which can loop on the form and convert any text boxenter image description here from Read only=true to be Read only = false but its not working
public static void unread only(Form frm)
{
foreach (Control item in frm.Controls)
{
if (item is TextBox)
{
// item.ReadOnly = false;
}
}
}
In your code, the compiler thinks that the object you have found is a Control, and does not know what type of control it is. You need to tell it what sort of control it is, and you can do this by casting it to a textbox:
((TextBox)item).ReadOnly = false;
However, there are better ways of doing this. Your code will only look at Top-level controls, and if you have container controls on your form, it will not recursively search those to find other textboxes. A recursive method to do this is as follows:
public static IEnumerable<T> GetControlsOfType<T>(Control root)
where T : Control
{
var t = root as T;
if (t != null)
yield return t;
var container = root as ContainerControl;
if (container != null)
foreach (Control c in container.Controls)
foreach (var i in GetControlsOfType<T>(c))
yield return i;
}
This is some code I got from here. It allows you to do something like this:
foreach (var textBox in GetControlsOfType<TextBox>(theForm))
{
textBox.ReadOnly = false;
}
Primarily your problem is that you are not casting the control to TextBox so that you have access to the property you want to set.
foreach (Control item in frm.Controls) {
if (item is TextBox) {
var textBox = item as TextBox;
textBox.ReadOnly = false;
}
}
That said, controls can contain child control, so you would need to crawl the entire form looking for embedded text boxes.
This will check the form and its controls for text boxes and set them to read only
public static void SetReadOnly(Control frm) {
var controls = new Queue<Control>();
controls.Enqueue(frm);
while (controls.Count > 0) {
var control = controls.Dequeue();
if (control is TextBox) {
var txtBox = control as TextBox;
txtBox.ReadOnly = true;
}
if (control.HasChildren) {
foreach (var child in control.Controls.OfType<Control>()) {
controls.Enqueue(child);
}
}
}
}
The code is pretty self explanatory but you should walk through the flow to understand what it is doing.
You need to be recursive. A Form Control can contain other Controls.
Code to create textboxes...
private void btnAddIncrement_Click(object sender, EventArgs e)
{
SmartTextBox dynamictextbox = new SmartTextBox();
dynamictextbox.BackColor = Color.Bisque;
dynamictextbox.Width = this.tbWidth;
dynamictextbox.Left = (sender as Button).Right + this.lastLeft;
dynamictextbox.K = "Test";
this.lastLeft = this.lastLeft + this.tbWidth;
dynamictextbox.Top = btnAddStart.Top;
this.Controls.Add(dynamictextbox);
}
Code for to remove all text boxes.
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(BnBCalculator.SmartTextBox))
{
count++;
//MessageBox.Show((c as SmartTextBox).K.ToString());
c.Dispose();
}
// else { MessageBox.Show("not txtbox"); }
}
When I click the btnAddIncrement I get the following as expected...
But when I click reset it misses every second textbox. See below...
No idea what's going on here but this is the same no matter how may text boxes I add. It always misses every second box.
You should use a reverse standard for loop to dispose the SmartTextBoxes from its container
for(int x = this.Controls.Count - 1; x >= 0; x--)
{
BnBCalculator.SmartTextBox c = this.Controls[x] as BnBCalculator.SmartTextBox;
if (c != null)
{
count++;
c.Dispose();
}
}
According to this question/answer you don't need to remove them from the container and of course this avoids two loops (explicit or implicit). Also in the accepted answer you could see the reason why your code jumps a control every two.
if (parent != null)
{
parent.Controls.Remove(this);
}
The control that you want to dispose is removed from the collection that you are iterating over. (Not clear why this doesn't throw the standard exception).
Instead looping with a simple for in reverse avoid any problem in the ordered access to the controls to dispose.
When you remove an item form this.Controls the collection is modified and so the next item is not what you expect. Yo should copy the this.Controls to a new list. For example you can use ToArray to make a copy of this.Controls
foreach (Control c in this.Controls.ToArray())
{
...
}
Your removal code is incorrect as you are modifying the Controls collection by calling Dispose() which is why you get the skipping of controls.
Easiest option to remove those of a specific type is to do the following:
var smartTbs = this.Controls.OfType<BnBCalculator.SmartTextBox>().ToList();
smartTbs.ForEach(x => x.Dispose());
You have to remove controls from Form.Controls at first and then dispose it.
var controlsToRemove = new List<Control>();
foreach (Control c in this.Controls)
{
if (c is BnBCalculator.SmartTextBox)
controlsToRemove.Add(c);
}
foreach (Control c in controlsToRemove)
{
Controls.Remove(c);
}
Try to select all the SmartTextBox controls first and dispose them on another loop. Pseudocode:
SmartTextBoxes = Select From this.Controls Where (c.GetType() == typeof(BnBCalculator.SmartTextBox));
foreach(stb in SmartTextBoxes) { stb.Dispose(); }
When I use th below code, it works. All the controls are hidden.
foreach (Control ctr in eItem.Controls)
{
ctr.visible = false;
}
However, I want to hide only labels and dropdownlists. That why I'm trying to use the below code without success
foreach (Control ctr in eItem.Controls)
{
if(ctr is Label | ctr is DropDownList)
{
ctr.visible = false;
}
}
EDIT
Here's the whole method
private void HideLabelAndDDLOnPageLoad()
{
foreach (ListViewItem eItem in lsvTSEntry.Items)
{
foreach (Control ctr in eItem.Controls)
{
if (ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
}
}
When I remove the if, all the controls get hidden. When I put it back, nothing happens.
Thanks for helping
I think what you are after is || change it to ||...that is the logical or operator.
foreach (Control ctr in eItem.Controls)
{
if(ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
| = bitwise operator
|| = logical or operator
Based on your edit
It appears your controls are inside an updatepanel, if that is the case you want to loop for all controls within the updatepanel's content template container.
Here you go:
foreach (Control ctr in UpdatePanel1.ContentTemplateContainer.Controls)
{
// rest of code
if(ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
The | is the bitwise or operator.
You are looking for ||, the logical or operator.
if(ctr is Label || ctr is DropDownList)
Without your exact markup we can only guess the solution here.
You must be using another container to wrap your controls inside your ItemTemplate in the ListView, something like a Panel or other containers. When you get the Controls on the list view item you actually get the warping container and not its children(labels, dropdowns etc.)
One solution to this is something like:
foreach (ListViewItem item in lsvTSEntry.Items)
{
item.FindControl("myLabel").Visible = false;
item.FindControl("myDropdownList").Visible = false;
}
Basically you try to find the controls by id and hide them. Notice there is no error checking there so you could get a NullReferenceException if FindControl returns null.
In case you have nested containers in your ItemTemplate and you want to hide all the labels and dropdowns regardless of where they are you can implement your own recursive FindControl that will look like:
private Control FindControlRecursive(Control rootControl, string controlId)
{
if (rootControl.ID == controlId)
{
return rootControl;
}
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlId);
if (controlToReturn != null)
{
return controlToReturn;
}
}
return null;
}
Not the most elegant but.... You can change this to take an array of Id's of course for speed purposes.
Based on this of course you can implement the search by control type which instead of taking a controlId as a parameter will take the types of controls to find.
I have a Form named A.
A contains lots of different controls, including a main GroupBox. This GroupBox contains lots of tables and others GroupBoxes. I want to find a control which has e.g. tab index 9 in form A, but I don't know which GroupBox contains this control.
How can I do this?
With recursion...
public static IEnumerable<T> Descendants<T>( this Control control ) where T : class
{
foreach (Control child in control.Controls) {
T childOfT = child as T;
if (childOfT != null) {
yield return (T)childOfT;
}
if (child.HasChildren) {
foreach (T descendant in Descendants<T>(child)) {
yield return descendant;
}
}
}
}
You can use the above function like:
var checkBox = (from c in myForm.Descendants<CheckBox>()
where c.TabIndex == 9
select c).FirstOrDefault();
That will get the first CheckBox anywhere within the form that has a TabIndex of 9. You can obviously use whatever criteria you want.
If you aren't a fan of LINQ query syntax, the above could be re-written as:
var checkBox = myForm.Descendants<CheckBox>()
.FirstOrDefault(x=>x.TabIndex==9);
Recursively search through your form's Controls collection.
void FindAndSayHi(Control control)
{
foreach (Control c in control.Controls)
{
Find(c.Controls);
if (c.TabIndex == 9)
{
MessageBox.Show("Hi");
}
}
}
void iterateControls(Control ctrl)
{
foreach(Control c in ctrl.Controls)
{
iterateControls(c);
}
}
You can make a method like this:
public static Control GetControl(Control.ControlCollection controlCollection, Predicate<Control> match)
{
foreach (Control control in controlCollection)
{
if (match(control))
{
return control;
}
if (control.Controls.Count > 0)
{
Control result = GetControl(control.Controls, match);
if (result != null)
{
return result;
}
}
}
return null;
}
...that is used like this:
Control control = GetControl(this.Controls, ctl => ctl.TabIndex == 9);
Note however that TabIndex is a tricky case, since it starts at 0 within each container, so there may be several controls in the same form having the same TabIndex value.
Either way, the method above can be used for checking pretty much any property of the controls:
Control control = GetControl(this.Controls, ctl => ctl.Text == "Some text");
I hate recursion, so I always use a stack for this sort of thing. This assigns a common event handler to the CheckedChanged event of every RadioButton control in the current control hierarchy:
Stack<Control> controlStack = new Stack<Control>();
foreach (Control c in this.Controls)
{
controlStack.Push(c);
}
Control ctl;
while (controlStack.Count > 0 && (ctl = controlStack.Pop()) != null)
{
if (ctl is RadioButton)
{
(ctl as RadioButton).CheckedChanged += new EventHandler(rb_CheckedChanged);
}
foreach (Control child in ctl.Controls)
{
controlStack.Push(child);
}
}
You could easily retrofit Josh Einstein's extension method to work this way.