How to find HtmlForm element? - c#

I am trying to find HtmlForm element using code below and add several new controls. Unfortunately this is not working, the HtmlForm element is never found.
foreach (Control c in Controls)
{
if (c is HtmlForm)
{
c.Controls.AddAt(0, manager);
c.Controls.AddAt(1, updatePanel);
}
}

How about using Page.Form to get the HtmlForm?

Do you have runat="server" specified in the form control? Otherwise; your code behind won't be aware of it.
Also, you might need some recursion here if the Control has nested controls; so something like this:
public static Control FindControlRecursive(Control containerCtl, string controlIdToFind)
{
var foundCtl = containerCtl.FindControl(controlIdToFind);
if (foundCtl != null && controlIdToFind == foundCtl.ID)
{
return foundCtl;
}
foreach (Control ctl in containerCtl.Controls)
{
foundCtl = FindControlRecursive(ctl, controlIdToFind);
if (foundCtl != null && controlIdToFind == foundCtl.ID)
{
return foundCtl;
}
}
return null;
}

Related

Get the list of Child controls inside a groupbox

I have a groupbox in my application which contains child controls.(As seen in the attchached pic). I want to enumerate through all the textboxes for performing some validation using a simple foreach loop.
This document outline would give a fair idea of the housing of the controls
foreach (Control control in grpBxTargetSensitivity.Controls)
{
if (control is FlowLayoutPanel && control.HasChildren)
{
foreach (Control ctrl in control.Controls)
{
if (ctrl is Panel && ctrl.HasChildren)
{
foreach (Control tbox in ctrl.Controls)
{
if (tbox is TextBox)
{
TextBox textbox = tbox as TextBox;
validData &= !string.IsNullOrWhiteSpace(textbox.Text);
}
}
}
}
}
}
My question is, Is there a better way (possibly through LINQ) to get all the controls including the textboxes housed inside the panels than the above method.?
I don't know that this is any better.. whether it's easier to read is a matter of opinion:
var validData
= grpBxTargetSensitivity.Controls.OfType<FlowLayoutPanel>()
.SelectMany(c => c.Controls.OfType<Panel>())
.SelectMany(c => c.Controls.OfType<TextBox>())
.All(textbox => !string.IsNullOrWhiteSpace(textbox.Text));
This'll grab all TextBoxes inside of all Panels in all FlowLayoutPanels in your GroupBox, and return true if all of those TextBoxes have a value in them.
A one liner slution,
IEnumerable<TextBox> collection = grpBxTargetSensitivity.Children.OfType<TextBox>(); //assuming you are looking for TextBox
or
You can try following generic method,
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
then enumerate over the controls as follows,
foreach (TextBox tb in FindVisualChildren<TextBox>(grpBxTargetSensitivity)) //assuming you are looking for TextBox
{
// do something
}
I create one method by the ability to find any controls (or T type) and any inherited object from Control (or T type) for you:
public static List<T> GetSubControlsOf<T>(Control parent) where T : Control
{
var myCtrls = new List<T>();
foreach (Control ctrl in parent.Controls)
{
// if ctrl is type of T
if (ctrl.GetType() == typeof(T) ||
ctrl.GetType().IsInstanceOfType(typeof(T)))
{
myCtrls.Add(ctrl as T);
}
else if (ctrl.HasChildren)
{
var childs = GetSubControlsOf<T>(ctrl);
if (childs.Any())
myCtrls.AddRange(childs);
}
}
return myCtrls;
}
and use that this form for e.g:
foreach (var textbox in GetSubControlsOf<TextBox>(this))
{
validData &= !string.IsNullOrWhiteSpace(textbox.Text);
}
I found following links on StackOverflow itself:
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
Loop through all the user controls on a page
Give them try. Should work in your case.

Equivalent to jQuery closest() in ASP.NET Web Forms

Im trying to figure out a way to build a somewhat clever version of the jQuery closest method in C#. Im using a generic method to find the desired control and then index the control chain
public static T FindControlRecursive<T>(Control control, string controlID, out List<Control> controlChain) where T : Control
{
controlChain = new List<Control>();
// Find the control.
if (control != null)
{
Control foundControl = control.FindControl(controlID);
if (foundControl != null)
{
// Add the control to the list
controlChain.Add(foundControl);
// Return the Control
return foundControl as T;
}
// Continue the search
foreach (Control c in control.Controls)
{
foundControl = FindControlRecursive<T>(c, controlID);
// Add the control to the list
controlChain.Add(foundControl);
if (foundControl != null)
{
// Return the Control
return foundControl as T;
}
}
}
return null;
}
To Call it
List<Control> controlChain;
var myControl = FindControls.FindControlRecursive<TextBox>(form, "theTextboxId"), out controlChain);
To find the closest element of id or type
// Reverse the list so we search from the "myControl" and "up"
controlChain.Reverse();
// To find by id
var closestById = controlChain.Where(x => x.ID.Equals("desiredControlId")).FirstOrDefault();
// To find by type
var closestByType = controlChain.Where(x => x.GetType().Equals(typeof(RadioButton))).FirstOrDefault();
Would this be a good approach or are there any other cool solutions out there creating this?
Whats your consideration?
Thanks!
Maybe something like this
public static IEnumerable<Control> GetControlHierarchy(Control parent, string controlID)
{
foreach (Control ctrl in parent.Controls)
{
if (ctrl.ID == controlID)
yield return ctrl;
else
{
var result = GetControlHierarchy(ctrl, controlID);
if (result != null)
yield return ctrl;
}
yield return null;
}
}

jscript document.getElementsByName in C#

which is similar in c# ?
var e = document.getElementsByName("test")[0];
var HTML = e.innerHTML;
Recursive FindControl method:
private Control RecursiveControlFind(Control parent, string controlID)
{
Control child = parent.FindControl(controlID);
if (child == null)
{
if (parent.Controls.Count > 0)
{
foreach (Control nestedControl in parent.Controls)
{
child = RecursiveControlFind(nestedControl, controlID);
if (child != null)
break;
}
}
}
return child;
}
Control.FindControl Method but it isn't recursive.

A Better way? Finding ASP.NET controls, finding their id

I have a method that finds all the controls, iterates through them, determines if they are a textbox,drop down list, etc.. retrieves their ID name, and depending on the ID name it will set a boolean statement (thus I would know if that section of the form is complete, and will email to a certain group of people) unfortunetly this is done with too many if statements and was wondering if I could get some help making this more manageable
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "")
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
if (control is DropDownList)
{
DropDownList lb = control as DropDownList;
if (lb.SelectedIndex != -1)
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
}
}
}
Why not just use the Control.FindControl(string) method?
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
// Find control on page.
Control myControl1 = FindControl("TextBox2");
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}
from: https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.control.findcontrol
It is hard to understand the logic behind your code, but I'm sure it can be written easier. For example you can do something like this:
DropDownBox box = FlattenHierachy(Page)
.Where(c => c is DropDownList)
.Cast<DropDownList>()
.Where(d => d.SelectedIndex != -1)
.FirstOrDefault();
if (box != null)
{
if (box.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (box.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
Obviously you can make this generic if you extract the lambda expression from the seconde Where call. So you could reuse it for different types. That's the solution which is as close to your code as possible, but I guess it would be a better idea to use a recursive method traversing the page and giving that method your predicates as lambda expressions.
Cleaned up you code a little to only include each check once.
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null &&
((control is TextBox && ((TextBox)control).Text = "" )
|| (control is DropDownList && ((DropDownList)control).SelectedIndex != -1 ))
{
if (control.ID.StartsWith("GenInfo_"))
GenInfo = true;
if (control.ID.StartsWith("EmpInfo_"))
EmpInfo = true;
}
}
}
}
Instead of using the Lambda expression I have created a method that handles the control for me, and depending on the name of the control, it sets that section to be true
public bool setGroup(Control ctrl)
{
isAControl = false;
//set a section to true, so it will pull the html
if (ctrl.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
lstControls.Add(ctrl.ID.Replace("GenInfo_", ""));
isAControl = true;
return isAControl;
}
here is a small snippet of my code I only want to check for certain controls(to speed things up) and I go through each control as each control has a different way to get the value (textbox would use .text where dropdownlist would use .selectedValue)
if(control is TextBox || control is DropDownList || control is RadioButton || control is RadioButtonList
|| control is CheckBox || control is CheckBoxList)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "" && txt.Text != "YYYY/MM/DD")
{
setGroup(control);
if (isAControl)
{
string controlNoGroup = lstControls.Last();
strHtml = strHtml.Replace("#" + (controlNoGroup.ToString()) + "#", txt.Text);
}
}
}

How to Identify Postback event in Page_Load

We have some legacy code that needs to identify in the Page_Load which event caused the postback.
At the moment this is implemented by checking the Request data like this...
if (Request.Form["__EVENTTARGET"] != null
&& (Request.Form["__EVENTTARGET"].IndexOf("BaseGrid") > -1 // BaseGrid event ( e.g. sort)
|| Request.Form["btnSave"] != null // Save button
This is pretty ugly and breaks if someone renames a control. Is there a better way of doing this?
Rewriting each page so that it does not need to check this in Page_Load is not an option at the moment.
This should get you the control that caused the postback:
public static Control GetPostBackControl(Page page)
{
Control control = null;
string ctrlname = page.Request.Params.Get("__EVENTTARGET");
if (ctrlname != null && ctrlname != string.Empty)
{
control = page.FindControl(ctrlname);
}
else
{
foreach (string ctl in page.Request.Form)
{
Control c = page.FindControl(ctl);
if (c is System.Web.UI.WebControls.Button)
{
control = c;
break;
}
}
}
return control;
}
Read more about this on this page:
http://ryanfarley.com/blog/archive/2005/03/11/1886.aspx
In addition to the above code, if control is of type ImageButton then add the below code,
if (control == null)
{ for (int i = 0; i < page.Request.Form.Count; i++)
{
if ((page.Request.Form.Keys[i].EndsWith(".x")) || (page.Request.Form.Keys[i].EndsWith(".y")))
{ control = page.FindControl(page.Request.Form.Keys[i].Substring(0, page.Request.Form.Keys[i].Length - 2)); break;
}
}
}
I am just posting the entire code (which includes the image button / additional control check that causes postback). Thanks Espo.
public Control GetPostBackControl(Page page)
{
Control control = null;
string ctrlname = page.Request.Params.Get("__EVENTTARGET");
if ((ctrlname != null) & ctrlname != string.Empty)
{
control = page.FindControl(ctrlname);
}
else
{
foreach (string ctl in page.Request.Form)
{
Control c = page.FindControl(ctl);
if (c is System.Web.UI.WebControls.Button)
{ control = c; break; }
}
}
// handle the ImageButton postbacks
if (control == null)
{ for (int i = 0; i < page.Request.Form.Count; i++)
{
if ((page.Request.Form.Keys[i].EndsWith(".x")) || (page.Request.Form.Keys[i].EndsWith(".y")))
{ control = page.FindControl(page.Request.Form.Keys[i].Substring(0, page.Request.Form.Keys[i].Length - 2)); break;
}
}
}
return control;
}

Categories

Resources