Programatic Access to DragHandleTemplate in ASP.NET AJAX ReorderList - asp.net

Is there a way to programatically access the DragHandleTemplate of a ReorderList (ASP.NET AJAX Control Toolkit) ... Specifically during ItemDataBound for the ReorderList, in order to change its appearance at the per item level?

You can also express FindControlRecursive in LINQ:
private Control FindControlRecursive(Control root, string id)
{
return root.ID == id
? root
: (root.Controls.Cast<Control>().Select(c => FindControlRecursive(c, id)))
.FirstOrDefault(t => t != null);
}

Unfortunately there is no way of getting drag holder from ReorderListItem. Instead, you can create a server control inside DragHandleTemplate (e.g. PlaceHolder) and then find it in your ItemDataBound event handler:
In aspx file:
<DragHandleTemplate>
<div class="dragHandle">
<asp:Label ID="lblDragHandle" runat="server" />
</div>
</DragHandleTemplate>
In aspx.cs file:
protected void ReorderList1_ItemDataBound(object sender, AjaxControlToolkit.ReorderListItemEventArgs e)
{
Label lblDragHandle = (Label)FindControlRecursive(e.Item, "lblDragHandle");
lblDragHandle.Text = e.Item.ItemIndex.ToString();
}
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
I copied FindControlRecursive method from Jeff's blog.

You can not access DragHandleTemplate programatically on the server, but if you create the surrounding elements with unique ID's (per row) you should be able the use CSS-selectors or Javascript to only change some of the items.

Related

How to find GridView on Page

I have nested GridViews on my page (Default) and I need to get the ID of the GridView inside but it's returning null. I have an UpdatePanel outside the nested GridViews. It's using a masterpage.
GridView gv = (GridView)UpdatePanel1.FindControl("GridViewSchedule");
Here is the helper method to find a control recursively.
public static Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
return root;
return root.Controls.Cast<Control>()
.Select(c => FindControlRecursive(c, id))
.FirstOrDefault(c => c != null);
}
// Usage
var gridView = FindControlRecursive(UpdatePanel1, "GridViewSchedule");

How to find control image button inside repeater, which is already inside a datalist

How to find control (i.e image button) inside repeater, that repeater is already in a datalist? because I have to perform delete operation on that image button.
Here is my code, here I'm getting repeater but not image button:
foreach (DataListItem item in Dlist_SearchResult.Controls)
{
rptrResult = (Repeater)item.FindControl("Rptr_result");
imgbtnDelete = (ImageButton)item.FindControl("imgbtnDelete");
}
You can use Recursion in your FindControl. FindControl by default is not recursive.
Try this:
private static Control FindControlRecursive(Control rootCtrl, string ID)
{
if (rootCtrl.ID == ID)
return rootCtrl;
foreach (Control ctr in rootCtrl.Controls)
{
Control foundCtl = FindControlRecursive(ctr, ID);
if (foundCtl != null)
return foundCtl;
}
return null;
}
you can call it
Button btn = FindControlRecursive((Control)Page,"imgbtnDelete");

Get reference of image button click event in gridview in http module

How do we pass the Click event of ImageButton inside a GridView to httpmodule
for linkbutton's i am doing this way:
if (request.Form.GetValues("__EVENTTARGET") != null)
{
//If it's a link button execute we can directley check for the params
if (request.Params.Get("__EVENTTARGET").Contains("xyz"))
{
//some Code
}
This is not working for ImageButton.
If you're trying to attach an event to a button within a gridview might I suggest in your base page on the prerender event parse through all gridviews on the page (use a recursive findcontrol algorithm) and look for any imagebuttons, if you find one you should then be able to attach an event to it.
EDIT:
I use something similar in the following:
public abstract class AmendmentPopUpWindow : BaseMasterPlanPage
{
// override this method if the correct save controls arent being hidden in the popups
public virtual IEnumerable<WebControl> SaveControls
{
get { return Controls.All().OfType<WebControl>().Where(c => c.ID.ToLower().Contains("save")); }
}
protected override void OnPreRender(EventArgs e)
{
if (WebConfiguration.Global_EnableAmendments && SystemVersion.HasValue)
{
foreach (var control in Controls.All())
{
if (control is RadioButton || control is TextBox || control is DropDownList || control is RadComboBox || control is CheckBox || control is CheckBoxList ||
control is RadEditor || control is RadTextBox || control is RadNumericTextBox)
{
var webControl = control as WebControl;
webControl.Enabled = false;
webControl.ForeColor = Color.Gray;
}
}
foreach (var saveControl in SaveControls)
saveControl.Visible = false;
}
base.OnPreRender(e);
}
EDIT: The .All() is an extension method defined as follows (stolen from here)
public static IEnumerable<Control> All(this ControlCollection controls)
{
foreach (Control control in controls)
{
foreach (Control grandChild in control.Controls.All())
yield return grandChild;
yield return control;
}
}
ImageButtons have an additional quasi-property in their names which identifies the mouse-coordinates (X and Y).
So to find the ImageButton's name your should iterate through posted parameters and found those which end with .x or .y:
foreach (string item in request.Form)
{
if (item.EndsWith(".x") || item.EndsWith(".y"))
{
var controlName = item.Substring(0, item.Length - 2);
// some code here
}
}
You could also cound this answer useful. It contains a more generic method to determine which control caused a postback.

Access nested web user control elements

I have a nested web user control. Main web user control I have used on a page but now I want to access the control inside the inner web user control and its events.
Can any body help me in this issue.
In the parent user control, expose a reference to your child control, or it's properties through a property. For example
public partial class ParentControl : UserControl
{
...
// Expose the whole child control
public ChildControl MyChild
{
get { return this.theIdOfTheChildControl; }
}
...
// or expose specific properties
public string MyChildText
{
get { return this.theIdOfTheChildControl.Text; }
set { this.theIdOfTheChildControl.Text = value; }
}
}
try this method
private List<Control> GetAllNestedUserControl(Control ph)
{
List<Control> Get = new List<Control>();
foreach (var control in ph.Controls)
{
if (control is UserControl)
{
UserControl uc = control as UserControl;
if (uc.HasControls())
{
Get = GetAllNestedUserControl(uc);
}
}
else
{
Control c = (Control)control;
if (!(control is LiteralControl))
{
Get.Add(c);
}
}
}
return Get;
}
this method will return the list of all controls then do the following to get the control u want
List<Control> Get = GetAllNestedUserControl(ph);
Label l = (Label)Get.Find(o => o.ID == "lblusername");
l.Text = "changed from master";

ASP:TextBox Value disappears in postback only when password

I have an asp.net textbox like this:
<asp:TextBox ID="PINPad" runat="server" Columns="6" MaxLength="4"
CssClass="PINTextClass"></asp:TextBox>
It is, as you might have guessed, the text box from an on screen PIN pad. Javascript fills in the values. The page is posted back every five seconds (using an update panel if that matters) to update various other unrelated items on the screen. This works just fine.
However, when I convert it to a password text box, like this:
<asp:TextBox ID="PINPad" runat="server" Columns="6" MaxLength="4"
CssClass="PINTextClass" TextMode="Password"></asp:TextBox>
Then whenever the page posts back, the text box is cleared out on the screen and the textbox is empty (though during the timer event, the value does make it back to the server.)
Any suggestions how to fix this, so that it retains its value during postback?
As a security feature, ASP.NET tries to disallow you from sending the password value back to the client. If you're okay with the security issues (i.e. it's either not really secure information or you're sure that the connection is secure), you can manually set the "value" attribute of the control, rather than using its Text property. It might look something like this:
this.PINPad.Attributes.Add("value", this.PINPad.Text);
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
if (!(String.IsNullOrEmpty(txtPwd.Text.Trim())))
{
txtPwd.Attributes["value"]= txtPwd.Text;
}
if (!(String.IsNullOrEmpty(txtConfirmPwd.Text.Trim())))
{
txtConfirmPwd.Attributes["value"] = txtConfirmPwd.Text;
}
}
}
here is another way to do it:-
using System;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControlLibrary
{
public class PWDTextBox : TextBox
{
public PWDTextBox()
{
this.TextMode = TextBoxMode.Password;
}
public string Password
{
get
{
string val = (string)ViewState["pwd"];
if (string.IsNullOrEmpty(val))
{
return "";
}
else
{
return val;
}
}
set
{
ViewState["pwd"] = value;
}
}
public override string Text
{
get
{
return Password;
}
set
{
Password = value;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.Text = Password;
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Value, this.Password);
}
}
}
The problem of losing the password in the postback can be avoid making use of Asynchronous JavaScript calls, lets describe a typical scenario for a Login page:
Lets say we have a Login page which allows the user to change the language of its labels when the user choose a language with a dropdownlist
a solution would be to invoke selectedIndexChanged event of the dropdownlist, make a postback which goes to the server and picks up the labels in the chosen language.
in this scenario the field password will be lost due to the security feature of ASP.NET which makes passwords fields not persisted between a postbacks.
This scenario can be solved if the postback is avoided making use of Asynchronous JavaScript Technology and XML (Ajax) calls.
Add a javascript function which will be invoked from the dropdownlist control, in this case this function is assigned to the Command property of the dropdownlist in code behind:
function ValueChanged(div)
{
var table = div.getElementsByTagName("table");
if (table && table.length > 0)
{
var t = table[0].getAttribute('type');
if (t != null && (t == "DropDown"))
{
var inputs = div.getElementsByTagName("input");
if (inputs && inputs.length == 2)
{
{
Translate(inputs[1].value);
}
}
}
}
}
The Translate function takes as parameter the selected option language in the dropdown control and performs the asynchronous call as shown bellow.
function Translate(lang)
{
var request = null;
if (window.XMLHttpRequest)
{
request = new XMLHttpRequest();
if (request.overrideMimeType)
{
request.overrideMimeType('text/xml');
}
}
else if (window.ActiveXObject)
{
request = new ActiveXObject("Msxml2.XMLHTTP");
}
if (request == null)
{
return;
}
var url = "GetLoginTranslations.aspx";
request.open('GET', url +'?lang=' + lang, true);
request.setRequestHeader("Cache-Control", "no-cache");
request.setRequestHeader("Pragma", "no-cache");
request.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
request.onreadystatechange = function () { TranslateLabels(request); };
request.send(null);
}
the function Translate shown above performs the call and get the results in the specified .aspx page (in this case "GetLoginTranslations.aspx")
when the request is completed and the request.onreadystatechange is set to the function TranslateLabels this function will be executed.
on this way the postback is not executed as before in the event onSelectedIndexChanged of the dropdownlist control.
the TranslateLabels function would look something like :
function TranslateLabels(request)
{
if (request.readyState == 4)
{
if (request.status == 200)
{
if (request.responseXML)
{
var objRoot = request.responseXML.documentElement;
if (objRoot)
{
if (objRoot.nodeName == "strings")
{
for (var i = 0; i < objRoot.childNodes.length; i++)
{
var node = objRoot.childNodes[i];
var elem;
switch (node.getAttribute("id"))
{
case "lbl_login":
elem = document.getElementById("lbl_login");
if (elem)
elem.innerHTML = node.firstChild.nodeValue;
break;
}
///....
}
}
}
}
}
}
the request.responseXML contains the XML built in the page GetLoginTranslations.aspx and the structure of this XML is defined there.
the Page_Load() event in the GetLoginTranslations.aspx should look like:
protected void Page_Load(object sender, EventArgs e)
{
if (Request["lang"] != null)
strLang = Request["lang"];
//init response
Response.Clear();
Response.Cache.SetExpires(DateTime.Now);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetValidUntilExpires(true);
Response.ContentType = "application/xml";
Response.Charset = "utf-8";
XmlTextWriter xml = new XmlTextWriter(Response.OutputStream, System.Text.Encoding.UTF8)
{
Formatting = Formatting.None
};
xml.WriteStartDocument();
xml.WriteStartElement("strings");
xml.WriteStartElement("string");
xml.WriteAttributeString("id", "lbl_login");
xml.WriteString(GetTranslation("label_login", strLang));
xml.WriteEndElement();
// ... the other labels
xml.WriteEndElement(); //</strings>
xml.Close();
}
Some other considerations:
set the the property AutoPostback of the dropdownlist to false.
Happens both for view-model properties named 'Password' and 'PIN'. You can bypass the behavior by defining those as:
string Password ;
... rather than:
string Password { get; set; }
If you do so, features such the 'LabelFor' macro displaying 'DisplayAttribute.Name' no longer works, so you'd have to define those directly in the HTML.
Or you can simply name the fields something other than 'Password' or 'PIN'.

Resources