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;
}
Related
I would like to use the find control method to find a image on the designer and make it visible, but i keep getting a null
This is my Code:
foreach (ImageShow image in imageList)
{
Image Showimage = (Image)FindControl(image.imageName);
Showimage.Visible = true;
}
Any help would be much appreciated,
Thanks in advance
FindControl does not search throughout a hierarchy of controls, I presume that this is a problem.
try using the following method :
public static T FindControlRecursive<T>(Control holder, string controlID) where T : Control
{
Control foundControl = null;
foreach (Control ctrl in holder.Controls)
{
if (ctrl.GetType().Equals(typeof(T)) &&
(string.IsNullOrEmpty(controlID) || (!string.IsNullOrEmpty(controlID) && ctrl.ID.Equals(controlID))))
{
foundControl = ctrl;
}
else if (ctrl.Controls.Count > 0)
{
foundControl = FindControlRecursive<T>(ctrl, controlID);
}
if (foundControl != null)
break;
}
return (T)foundControl;
}
Usage:
Image Showimage = FindControlRecursive<Image>(parent, image.imageName);
In your case parent is this, example :
Image Showimage = FindControlRecursive<Image>(this, image.imageName);
You can use it without ID, then will find first occurrence of T :
Image Showimage = FindControlRecursive<Image>(this, string.Empty);
foreach (ImageShow image in imageList)
{
Image showimage = FindControl(image.imageName) as Image;
if(showimage != null)
{
showimage .Visible = true;
}
}
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;
}
}
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;
}
I have a asp.net page which is inherited from a master page .I want to clear all controls in this page .I tried using the bellow method .This is not working if a master page is there. Otherwise its working fine any ideas?
private void ClearControls()
{
foreach(Control c in Page.Controls)
{
foreach (Control ctrl in c.Controls)
{
if (ctrl is TextBox)
{
((TextBox)ctrl).Text = string.Empty;
}
}
}
}
try this:
public void FindAllTextBox(Control ctrl)
{
if (ctrl != null)
{
foreach (Control c in ctrl.Controls)
{
if (c is TextBox)
((TextBox)c).Text = string.empty;
FindAllTextBox(c);
}
}
}
Ex.:
Control ctrl = this.FindControl("content");
FindAllTextBox(ctrl);
You should be able to do this with Page.Form.FindControl("ContentPlaceHolder1").Controls:
foreach (Control item in Page.Form.FindControl("ContentPlaceHolder1").Controls)
{
if (item is TextBox)
{
((TextBox)item).Text = string.Empty;
}
}
This is probably because of your controls are inside of another container when you add a master page. Have you tried adding another foreach before if?
private void ClearControls()
{
foreach(Control container in Page.Controls)
{
foreach (Control c in container.Controls)
{
foreach (Control ctrl in c.Controls)
{
if (ctrl is TextBox)
{
((TextBox)ctrl).Text = string.Empty;
}
}
}
}
}
I wouldn't do it this way though. Sometimes hardcoding is better. This would use a lot of resource when called on a page that contains lots of controls.
Don't hard code:
//Recursively get all the formControls underneath the current one, be it Page, UserControl or whatever.
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 call it in your webform / control:
var formCtls = this.GetAllControls().OfType<TextBox>();
foreach(TextBox txtbx in formCtls)
{
//do what you gotta do ;)
}
First, use operator as instead of is and cast:
TextBox tb = ctrl as TextBox;
if (tb != null)
{
tb.Text = String.Empty;
}
Second, you can use ITextControl instead of TextBox.
And third, try next extension method:
public static IEnumerable<T> GetChildControls(this Control control) where T : Control
{
var children = (control.Controls != null) ? control.Controls.OfType<T>() : Enumerable.Empty<T>();
return children.SelectMany(c => GetChildControls(c)).Concat(children);
}
Usage:
foreach (var c in this.Page.Controls.GetChildControls<TextBox>())
{
c.Text = String.Empty;
}
I had the same problem but I think I was making it too hard. I'm using an AJAX UpdatePanel control and I just referenced that instead of going all the way up to the MasterPage. This worked for me.
foreach (Control c in UpdatePanel1.Controls)
{
foreach (Control c1 in c.Controls)
{
if (c1 is TextBox)
{
TextBox txtBox = (TextBox)c1;
txtBox.Text = "0";
}
}
}
Just keep the controls in Panel, and try the code below
foreach (Control cntrl in pnl.Controls)//pnl is panel id
{
if (cntrl is TextBox)
{
TextBox txtBox = (TextBox)cntrl;
txtBox.Text = " ";
}
}
Make a method on your .cs like this:
//Where "this" is Page.
ClearInput(this);
private void ClearInput(Control parent)
{
foreach (Control c in parent.Controls)
{
if (c.Controls.Count > 0)
ClearInput(c);
else
{
if (c is TextBox)
(c as TextBox).Text = "";
if (c is CheckBox)
(c as CheckBox).Checked = false;
if (c is DropDownList)
(c as DropDownList).SelectedIndex = 1;
}
}
}
private void EnableControls(Control control)
{
var textbox = control as TextBox;
if (textbox != null)
{
textbox.Enabled = true;
}
var dropDownList = control as DropDownList;
if (dropDownList != null)
{
dropDownList.Enabled = true;
}
var radioButton = control as RadioButton;
if (radioButton != null)
{
radioButton.Enabled = true;
}
var checkBox = control as CheckBox;
if (checkBox != null)
{
checkBox.Enabled = true;
}
foreach (Control childControl in control.Controls)
{
EnableControls(childControl);
}
}
public void getAllCtl(ControlCollection ctls)
{
foreach (Control c in ctls)
{
if (c is System.Web.UI.WebControls.TextBox)
{
//TextBox tt = c as TextBox;
////to do something by using textBox tt.
((TextBox)c).Text = string.Empty;
}
if (c is System.Web.UI.WebControls.CheckBox)
{
((CheckBox)c).Checked = false;
}
if (c is System.Web.UI.WebControls.DropDownList)
{
((DropDownList)c).SelectedIndex = -1;
}
if (c.HasControls())
{
getAllCtl(c.Controls);
}
}
}
calling in aspx.cs file as
getAllCtl(this.Form.Controls);
This is OK and tested work for all Master-child page and where ever multiple controls are contains in the page...
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);
}
}
}