How to find a control in a repeater with IndexOf C# - c#

I want to know if it's possible to find a control in a repeater but by approximation. I mean, I have some controls with end "....EditMode" and I want to catch them all and modify some attribute
Something like this
foreach(RepeaterItem item in repeater1.Items)
{
HtmlGenericControl divEditMode = item.FindControl("....IndexOf ("EditMode")");
if(divEditMode != null)
{
divEditMode.Visible = false;
}
}

foreach(RepeaterItem item in repeater1.Items)
{
foreach (var control in item.Controls)
{
if(control.ID.EndsWith("EditMode"))
{
control.Visible = false;
}
}
}
If I understand your wishes.

The way to accomplish this is to loop through the controls "by hand" instead of using FindControl. You can use the Controls collection of the RepeaterItem to list all controls and analyze their ids.
As controls are organized as a tree, you should recursively inspect also the Controls collections of the controls on the top level.
private IEnumerable<Control> GetEditControls(ControlCollection controls)
{
var lst = new List<Control>();
if (controls == null)
return lst;
foreach(var ctrl in controls)
{
if (ctrl.Id.EndsWith("EditMode"))
lst.Add(ctrl);
lst.AddRange(GetControls(ctrl.Controls);
}
return lst;
}
// ...
foreach(RepeaterItem item in repeater1.Items)
{
var divsEditMode = GetEditControls(item.Controls);
foreach(var divEditMode in divsEditMode)
{
divEditMode.Visible = false;
}
}

Related

Check which Controls have Borders c#

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.

Readonly properties

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.

Iterating Through All DropDownList In an ASP.NET WebForm C#

What is the object that I would have to reference in order to iterate through all the DropDownList on a web page. I have a web page with several drop down list on it. I want a piece of code that will do the following:
foreach (DropDownList d in xxx)
{
someFunction(d, d.ID);
}
Thanks.
If you don't need to worry about nested controls in which case you would need recursion, something like below should work.
foreach(DropDownList list in Controls.OfType<DropDownList>())
{
//TODO: Something with list
}
If recursion is required you could make a method like below..
public static IEnumerable<Control> GetAllControls(Control parent)
{
if(null == parent) return null;
return new Control[] { parent }.Union(parent.Controls.OfType<Control>().SelectMany(child => GetAllControls(child));
}
And then modify your loop...
foreach(DropDownList list in GetAllControls(this).OfType<DropDownList>())
{
//TODO: Something with list
}
foreach (var dropDownList in Page.Controls.OfType<DropDownList>())
{
}
There is no magical all control container. You're going to have to recursively traverse your control tree and find all the drop downs.
public void DoSomethingForAllControlsOf<T>(Control thisControl, Action<T> method)
where T: class
{
if(thisControl.Controls == null)
return;
foreach(var control in thisControl.Controls)
{
if(control is T)
method(control as T);
DoSomethingForAllControlsOf<T>(control, method);
}
}
That should recursively walk down the control tree and invoke the method on all elements of type T. Example:
DoSomethingForAllControlsOf<DropDownList>(this, someFunction);
You can't run a foreach loop on that because although you have numerous DropDownLists, they are not part of an iterable collection. You could, however, store each DropDownList into an array, and iterate through that array.
To get all of the dropdown controls, you'll probably need to loop through recursively. You can use this function to do it:
public Control DisableDropDowns(Control root)
{
foreach (Control ctrl in root.Controls)
{
if (ctrl is DropDownList)
((DropDownList)ctrl).Enabled = false;
DisableDropDowns(ctrl);
}
}
The LINQ way:
First you need an extension method to grab all the controls of the type you're interested in:
//Recursively get all the formControls
public static IEnumerable<Control> GetAllControls(this Control parent)
{
foreach (Control control in parent.Controls)
{
yield return control;
foreach (Control descendant in control.GetAllControls())
{
yield return descendant;
}
}
}`
Then you can iterate as you wanted:
var formCtls = this.GetAllControls().OfType<DropDownList>();`
foreach(DropDownList ddl in formCtls){
//do what you gotta do ;)
}
while(dropdownlist1.SelectedIndex++ < dropdownlist1.Items.Count)
{
if (dropdownlist1.SelectedValue == textBox1.text)
{
// do stuff here.
}
}
//resetting to 0th index(optional)
dropdownlist1.SelectedIndex = 0;

Iterating through TextBoxes in asp.net - why is this not working?

I have 2 methods I tried to iterate through all my textboxes in an asp.net page. The first is working, but the second one is not returning anything. Could someone please explain to me why the second one is not working?
This works ok:
List<string> list = new List<string>();
foreach (Control c in Page.Controls)
{
foreach (Control childc in c.Controls)
{
if (childc is TextBox)
{
list.Add(((TextBox)childc).Text);
}
}
}
and the "not working" code:
List<string> list = new List<string>();
foreach (Control control in Controls)
{
TextBox textBox = control as TextBox;
if (textBox != null)
{
list.Add(textBox.Text);
}
}
Your first example is doing one level of recursion, so you're getting TextBoxes that are more than one control deep in the control tree. The second example only gets top-level TextBoxes (which you likely have few or none).
The key here is that the Controls collection is not every control on the page - rather, it is only the immediate child controls of the current control (and a Page is a type of Control). Those controls may in turn have child controls of their own. To learn more about this, read about the ASP.NET Control Tree here and about NamingContainers here. To truly get every TextBox anywhere on the page, you need a recursive method, like this:
public static IEnumerable<T> FindControls<T>(this Control control, bool recurse) where T : Control
{
List<T> found = new List<T>();
Action<Control> search = null;
search = ctrl =>
{
foreach (Control child in ctrl.Controls)
{
if (typeof(T).IsAssignableFrom(child.GetType()))
{
found.Add((T)child);
}
if (recurse)
{
search(child);
}
}
};
search(control);
return found;
}
Which is used as an extension method, like so:
var allTextBoxes = this.Page.FindControls<TextBox>(true);
You need to recurse. The controls are in a tree structure - Page.Controls is not a flattened list of all controls on the page. You'd need to do something like the following to get all values of TextBoxes:
void GetTextBoxValues(Control c, List<string> strings)
{
TextBox t = c as TextBox;
if (t != null)
strings.Add(t.Text);
foreach(Control child in c.Controls)
GetTextBoxValues(child, strings);
}
...
List<string> strings = new List<string>();
GetTextBoxValues(Page, strings);
you can try this piece of code to get list of all TextBoxes
public partial class _Default : System.Web.UI.Page
{
public List<TextBox> ListOfTextBoxes = new List<TextBox>();
protected void Page_Load(object sender, EventArgs e)
{
// after execution this line
FindTextBoxes(Page, ListOfTextBoxes);
//ListOfTextBoxes will be populated with all text boxes with in the page.
}
private void FindTextBoxes(Control Parent, List<TextBox> ListOfTextBoxes)
{
foreach (Control c in Parent.Controls) {
// if c is a parent control like panel
if (c.HasControls())
{
// search all control inside the panel
FindTextBoxes(c, ListOfTextBoxes);
}
else {
if (c is TextBox)
{
// if c is type of textbox then put it into the list
ListOfTextBoxes.Add(c as TextBox);
}
}
}
}
}

How do I get all controls of a form in Windows Forms?

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.

Categories