User control's property loses value after a postback - asp.net

This is the HTML. I have a repeater that contains a user control.
<asp:Repeater ID="rpNewHire" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<user:CKListByDeprtment ID = "ucCheckList"
DepartmentID= '<%# Eval("DepID")%>'
BlockTitle = '<%# Eval("DepName")%>'
runat = "server"></user:CKListByDeprtment>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
DepartmentID is a property that I defined inside the user control.
int departmentID;
public int DepartmentID
{
get { return departmentID; }
set { departmentID = value; }
}
And this is how I am trying to access it
protected void Page_Load(object sender, EventArgs e)
{
int test = departmentID;
}
When the page loads for the first time, departmentID has a value. However, when the page Posts back, that value is always 0.

All variables (and controls) are disposed at the end of the page's lifecycle. So you need a way to persist your variable, e.g. in the ViewState.
public int DepartmentID
{
get {
if (ViewState["departmentID"] == null)
return int.MinValue;
else
return (int)ViewState["departmentID"];
}
set { ViewState["departmentID"] = value; }
}
The MSDN Magazine article "Nine Options for Managing Persistent User State in Your ASP.NET Application" is useful, but it's no longer viewable on the MSDN website. It's in the April 2003 edition, which you can download as a Windows Help file (.chm). (Don't forget to bring up the properties and unblock the "this was downloaded from the internet" thing, otherwise you can't view the articles.)

Change your property to use viewstate
int departmentID = 0;
public int DepartmentID
{
get {
if(ViewState["departmentID"]!=null)
{ departmentID = Int32.Parse(ViewState["departmentID"]); };
return departmentID;
}
set { ViewState["departmentID"] = value; }
}

Related

Clone reference type properties with CustomButtonCallback

I'm trying to follow the DevExpress documentation example on cloning rows. The basics are easy to get right, but things get tricky when you try to clone properties other than value types.
First attempt / setting up a repro:
I've narrowed my real scenario to a small(ish) repro of the problem. The following is all part of a freshly created ASP.NET 2.0 webforms application. First, suppose these domain objects (that'll double as DTO's here too):
public class Qualification
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public Qualification Qualification { get; set; }
}
Then there are two quick 'n dirty data source classes like so:
public class QualificationOds
{
public static List<Qualification> Qualificiations = new List<Qualification>
{
new Qualification { Id = 1, Title = "Doctore" }
};
public List<Qualification> GetRecords()
{
return Qualificiations;
}
}
public class PeopleOds
{
public List<Person> GetRecords()
{
return new List<Person>
{
new Person
{
Id = 1,
Name = "John Doe",
Qualification = QualificationOds.Qualificiations[0]
}
};
}
}
The default.aspx page will first register dx to DevExpress namespaces:
<%# Register Assembly="DevExpress.Web.ASPxGridView.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dx" %>
<%# Register Assembly="DevExpress.Web.ASPxEditors.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxEditors" TagPrefix="dx" %>
And have a single form with this code in it:
<asp:ObjectDataSource runat="server" ID="peopleDataSource" TypeName="DevxTest.PeopleOds" SelectMethod="GetRecords" />
<asp:ObjectDataSource runat="server" ID="qualificationsDataSource" TypeName="DevxTest.QualificationOds" SelectMethod="GetRecords" />
<dx:ASPxGridView
runat="server"
id="grvPeople"
KeyFieldName="Id"
DataSourceID="peopleDataSource"
OnCustomButtonCallback="grid_CustomButtonCallback"
OnInitNewRow="grid_InitNewRow">
<Columns>
<dx:GridViewCommandColumn>
<EditButton Visible="true" />
<CustomButtons>
<dx:GridViewCommandColumnCustomButton ID="Clone" Text="Clone" />
</CustomButtons>
</dx:GridViewCommandColumn>
<dx:GridViewDataTextColumn FieldName="Name" />
<dx:GridViewDataComboBoxColumn FieldName="Qualification.Id" >
<PropertiesComboBox
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</dx:GridViewDataComboBoxColumn>
</Columns>
</dx:ASPxGridView>
The code behind contains the code to clone a row into a fresh edit form, based on aforementioned DevExpress example, like so:
private string[] fieldsToCopy = { "Name", "Id" };
private Hashtable valuesToClone;
protected void grid_CustomButtonCallback(object sender, ASPxGridViewCustomButtonCallbackEventArgs e)
{
if (e.ButtonID != "Clone") return;
valuesToClone = new Hashtable();
foreach (var fieldName in fieldsToCopy)
{
valuesToClone[fieldName] = grvPeople.GetRowValues(e.VisibleIndex, fieldName);
}
grvPeople.AddNewRow();
}
protected void grid_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
if (valuesToClone == null) return;
foreach (string fieldName in fieldsToCopy)
{
e.NewValues[fieldName] = valuesToClone[fieldName];
}
}
This works for the Name property, but not so much for the Qualification property. It shows like this on the page:
I've also tried "Qualification.Id" and "Qualification" as field names to copy, but no dice. At any rate, I'm pretty sure it should be "Id" as in my example though, because the debugger shows the correct GetRowValues return value only for that case.
Second attempt / custom code to handle the dropdown:
So I'm thinking I need to have some custom code to set the NewValue for a dropdown. First I create an EditItemTemplate for the Qualification column like so:
<EditItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="qualificationCombo"
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</EditItemTemplate>
And then I add this code to grid_InitNewRow:
// Attempt to set the combo box to a value:
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
And it works! However, now the Name is no longer cloned. It looks like this:
I have no clue why, but the added code has a side-effect causing the NewValues setter approach to fail.
Bottom Line:
The bottom line is rather simple: how do I change the DevExpress example into one that can also clone reference type properties?
PS. I've also cross-posted my question on the DevExpress support forum.
You mention that "Qualification.Id" doesn't work, but you most likely tried that while the EditItemTemplate was there. If there is no such template then that code actually works.
To be complete, change the fieldsToCopy line of code to:
private string[] fieldsToCopy = { "Name", "Qualification.Id" };
And make sure there's no EditItemTemplate, then it'll work.
Alternatively, if you are stuck with a EditItemTemplate for some reason, there's one "solution" to make sure the ComboBox in that template gets bound to the cloned value. Make sure you hook into OnDataBound on the ComboBox with the following code:
protected void qualificationCombo_DataBound(object sender, EventArgs e)
{
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
}
This will properly set the ComboBox to the cloned value, while also leaving the e.NewValues approach for plain fields intact.

How to get property in code behind in ASP.NET?

I am working on ASP.NET. I am new to it. I need to set a table property (iscollect="true"). I need to get this property in my code behind. How to get it as true. Please help. Thanks in advance
or if i am doing anything wrong plz suggest me
here is my example goes
<table width="100%" border="0" align="center" runat="server" id="Personal" iscollect="true">
<tr>
<td><btn:collection ID="collect" runat="server"/></td>
</tr>
</table>
Code behind
public bool iscollect { get; set; }
protected void btnContinue_Click(object sender, EventArgs e)
{
bool var = iscollect;
if (iscollect==true)
{
Personalcollect.Visible = true;
SavecollectDetails();
}
}
How to get this property as true as i set in code behind. Please help.
Thanks!
The iscollect wont be persisted between requests. Try storing it in the viewstate like this:
public bool iscollect {
get {return (bool)(ViewState["iscollect"] ?? false)}
set { ViewState["iscollect"] = value; }
}
And then add the attribute in the ASPX file:
iscollect="<%= iscollect %>"
try this:
In ASPX:
... runat="server" id="Personal"iscollect='<%=iscollect%>'>
You can get the attributes of table using Attributes property like this
string value = Personal.Attributes["iscollect"].ToString();
As you have declare a Property named iscollect on the page, you can assign it to the value specified in the table markup.
private bool _isCollect = false;
public bool IsCollect
{
get
{
Boolean.TryParse(Personal.Attributes["iscollect"], out _isCollect);
return _isCollect;
}
}
I don't know how did you manage to compile your code, but this should work:
public bool iscollect {
get {return (bool)(ViewState["iscollect"] ?? false)}
set { ViewState["iscollect"] = value; }
}
protected void btnContinue_Click(object sender, EventArgs e)
{
iscollect = Convert.ToBoolean(Personal.Attributes["iscollect"]);
if (iscollect)
{
Personalcollect.Visible = true;
SavecollectDetails();
}
}
<table width="100%" border="0" align="center" runat="server" id="Personal" iscollect="<%=iscollect%>">
<tr><td><btn:collection ID="collect" runat="server" /></td></tr>
</table>

Consuming RSS feeds in ASP and C#

I'm working on making a modification to a site built with ASP/C#, and one of the tasks was to add in the display of 2 RSS feeds - one from the site's internal blog, and the other from the site's Twitter account. However, I seem to continually get empty feeds from both, even though I've confirmed that I'm pointing to the correct URL of the feeds. My code is shown below.
private void GetTwitterRSS()
{
IEnumerable items = Cache["TwitterFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://twitter.com/statuses/user_timeline/84668697.rss"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("TwitterFeed", items, null, DateTime.Now.AddMinutes(5.0),TimeSpan.Zero);
twitterrssRepeater.DataSource = items;
twitterrssRepeater.DataBind();
}
}
private void GetBlogRSS()
{
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://www.rentseeker.ca/blog/?feed=rss2"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("BlogFeed", items, null, DateTime.Now.AddHours(1.0),TimeSpan.Zero);
blogrssRepeater.DataSource = items;
blogrssRepeater.DataBind();
}
}
protected string DisplayBlogFeedItem(SyndicationItem item)
{
return string.Format(#"<p>{1}</p><p><strong>{2}</strong></p><p>{3}</p>",
FormatPublishDate(item.PublishDate.DateTime),
item.Title.Text,
item.Summary.Text);
}
protected string DisplayTwitterFeedItem(SyndicationItem item)
{
return string.Format(#"<li>{1}</li>",
item.Title.Text);
}
The code on the page is:
<ul>
<asp:ListView ID="twitterrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayTwitterFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
</ul>
and
<asp:ListView ID="blogrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayBlogFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
Clearly, I'm missing something. From what I've read, I understand that I'm supposed to authenticate myself in order to view a Twitter feed - I have the credentials, but am not sure how to pass them into SyndicationFeed when I load it.
Any tips, suggestions, or direction for further information is greatly appreciated.
Here's a simple example I would use to receive my Twitter feed (I'm only getting name, update title & id)
public class TwitterFeed
{
public string Name { get; set; }
public string Title { get; set; }
public string Id { get; set; }
}
Then the method to get the feed
public List<TwitterFeed> GetTwitterFeed(string name)
{
List<TwitterFeed> list = new List<TwitterFeed>();
XmlReader reader = XmlReader.Create(string.Format("http://search.twitter.com/search.atom?q=to:{0}", name));
SyndicationFeed feed = SyndicationFeed.Load(reader);
var tweetItems = from item in feed.Items
select new TwitterFeed()
{
Name = item.Authors.First().Name,
Title = item.Title.Text,
Id = item.Id
};
return tweetItems.ToList();
}
Hope that helps
SyndicationFeed.Items is not a List, but implements IEnumerable interface, so instead of
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
use the following line:
IEnumerable items = Cache["BlogFeed"] as IEnumerable<SyndicationItem>;

Is there a workaround for IE 6/7 "Unspecified Error" bug when accessing offsetParent

I'm using jQuery UI's draggable and droppable libraries in a simple ASP.NET proof of concept application. This page uses the ASP.NET AJAX UpdatePanel to do partial page updates. The page allows a user to drop an item into a trashcan div, which will invoke a postback that deletes a record from the database, then rebinds the list (and other controls) that the item was drug from. All of these elements (the draggable items and the trashcan div) are inside an ASP.NET UpdatePanel.
Here is the dragging and dropping initialization script:
function initDragging()
{
$(".person").draggable({helper:'clone'});
$("#trashcan").droppable({
accept: '.person',
tolerance: 'pointer',
hoverClass: 'trashcan-hover',
activeClass: 'trashcan-active',
drop: onTrashCanned
});
}
$(document).ready(function(){
initDragging();
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function()
{
initDragging();
});
});
function onTrashCanned(e,ui)
{
var id = $('input[id$=hidID]', ui.draggable).val();
if (id != undefined)
{
$('#hidTrashcanID').val(id);
__doPostBack('btnTrashcan','');
}
}
When the page posts back, partially updating the UpdatePanel's content, I rebind the draggables and droppables. When I then grab a draggable with my cursor, I get an "htmlfile: Unspecified error." exception. I can resolve this problem in the jQuery library by replacing elem.offsetParent with calls to this function that I wrote:
function IESafeOffsetParent(elem)
{
try
{
return elem.offsetParent;
}
catch(e)
{
return document.body;
}
}
I also have to avoid calls to elem.getBoundingClientRect() as it throws the same error. For those interested, I only had to make these changes in the jQuery.fn.offset function in the Dimensions Plugin.
My questions are:
Although this works, are there better ways (cleaner; better performance; without having to modify the jQuery library) to solve this problem?
If not, what's the best way to manage keeping my changes in sync when I update the jQuery libraries in the future? For, example can I extend the library somewhere other than just inline in the files that I download from the jQuery website.
Update:
#some It's not publicly accessible, but I will see if SO will let me post the relevant code into this answer. Just create an ASP.NET Web Application (name it DragAndDrop) and create these files. Don't forget to set Complex.aspx as your start page. You'll also need to download the jQuery UI drag and drop plug in as well as jQuery core
Complex.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Complex.aspx.cs" Inherits="DragAndDrop.Complex" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<script src="jquery-1.2.6.min.js" type="text/javascript"></script>
<script src="jquery-ui-personalized-1.5.3.min.js" type="text/javascript"></script>
<script type="text/javascript">
function initDragging()
{
$(".person").draggable({helper:'clone'});
$("#trashcan").droppable({
accept: '.person',
tolerance: 'pointer',
hoverClass: 'trashcan-hover',
activeClass: 'trashcan-active',
drop: onTrashCanned
});
}
$(document).ready(function(){
initDragging();
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function()
{
initDragging();
});
});
function onTrashCanned(e,ui)
{
var id = $('input[id$=hidID]', ui.draggable).val();
if (id != undefined)
{
$('#hidTrashcanID').val(id);
__doPostBack('btnTrashcan','');
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:UpdatePanel ID="updContent" runat="server" UpdateMode="Always">
<ContentTemplate>
<asp:LinkButton ID="btnTrashcan" Text="trashcan" runat="server" CommandName="trashcan"
onclick="btnTrashcan_Click" style="display:none;"></asp:LinkButton>
<input type="hidden" id="hidTrashcanID" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Save" onclick="Button1_Click" />
<table>
<tr>
<td style="width: 300px;">
<asp:DataList ID="lstAllPeople" runat="server" DataSourceID="odsAllPeople"
DataKeyField="ID">
<ItemTemplate>
<div class="person">
<asp:HiddenField ID="hidID" runat="server" Value='<%# Eval("ID") %>' />
Name:
<asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>' />
<br />
<br />
</div>
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="odsAllPeople" runat="server" SelectMethod="SelectAllPeople"
TypeName="DragAndDrop.Complex+DataAccess"
onselecting="odsAllPeople_Selecting">
<SelectParameters>
<asp:Parameter Name="filter" Type="Object" />
</SelectParameters>
</asp:ObjectDataSource>
</td>
<td style="width: 300px;vertical-align:top;">
<div id="trashcan">
drop here to delete
</div>
<asp:DataList ID="lstPeopleToDelete" runat="server"
DataSourceID="odsPeopleToDelete">
<ItemTemplate>
ID:
<asp:Label ID="IDLabel" runat="server" Text='<%# Eval("ID") %>' />
<br />
Name:
<asp:Label ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' />
<br />
<br />
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="odsPeopleToDelete" runat="server"
onselecting="odsPeopleToDelete_Selecting" SelectMethod="GetDeleteList"
TypeName="DragAndDrop.Complex+DataAccess">
<SelectParameters>
<asp:Parameter Name="list" Type="Object" />
</SelectParameters>
</asp:ObjectDataSource>
</td>
</tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Complex.aspx.cs
namespace DragAndDrop
{
public partial class Complex : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected List<int> DeleteList
{
get
{
if (ViewState["dl"] == null)
{
List<int> dl = new List<int>();
ViewState["dl"] = dl;
return dl;
}
else
{
return (List<int>)ViewState["dl"];
}
}
}
public class DataAccess
{
public IEnumerable<Person> SelectAllPeople(IEnumerable<int> filter)
{
return Database.SelectAll().Where(p => !filter.Contains(p.ID));
}
public IEnumerable<Person> GetDeleteList(IEnumerable<int> list)
{
return Database.SelectAll().Where(p => list.Contains(p.ID));
}
}
protected void odsAllPeople_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
e.InputParameters["filter"] = this.DeleteList;
}
protected void odsPeopleToDelete_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
e.InputParameters["list"] = this.DeleteList;
}
protected void Button1_Click(object sender, EventArgs e)
{
foreach (int id in DeleteList)
{
Database.DeletePerson(id);
}
DeleteList.Clear();
lstAllPeople.DataBind();
lstPeopleToDelete.DataBind();
}
protected void btnTrashcan_Click(object sender, EventArgs e)
{
int id = int.Parse(hidTrashcanID.Value);
DeleteList.Add(id);
lstAllPeople.DataBind();
lstPeopleToDelete.DataBind();
}
}
}
Database.cs
namespace DragAndDrop
{
public static class Database
{
private static Dictionary<int, Person> _people = new Dictionary<int,Person>();
static Database()
{
Person[] people = new Person[]
{
new Person("Chad")
, new Person("Carrie")
, new Person("Richard")
, new Person("Ron")
};
foreach (Person p in people)
{
_people.Add(p.ID, p);
}
}
public static IEnumerable<Person> SelectAll()
{
return _people.Values;
}
public static void DeletePerson(int id)
{
if (_people.ContainsKey(id))
{
_people.Remove(id);
}
}
public static Person CreatePerson(string name)
{
Person p = new Person(name);
_people.Add(p.ID, p);
return p;
}
}
public class Person
{
private static int _curID = 1;
public int ID { get; set; }
public string Name { get; set; }
public Person()
{
ID = _curID++;
}
public Person(string name)
: this()
{
Name = name;
}
}
}
#arilanto - I include this script after my jquery scripts. Performance wise, it's not the best solution, but it is a quick easy work around.
function IESafeOffsetParent(elem)
{
try
{
return elem.offsetParent;
}
catch(e)
{
return document.body;
}
}
// The Offset Method
// Originally By Brandon Aaron, part of the Dimension Plugin
// http://jquery.com/plugins/project/dimensions
jQuery.fn.offset = function() {
/// <summary>
/// Gets the current offset of the first matched element relative to the viewport.
/// </summary>
/// <returns type="Object">An object with two Integer properties, 'top' and 'left'.</returns>
var left = 0, top = 0, elem = this[0], results;
if ( elem ) with ( jQuery.browser ) {
var parent = elem.parentNode,
offsetChild = elem,
offsetParent = IESafeOffsetParent(elem),
doc = elem.ownerDocument,
safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
css = jQuery.curCSS,
fixed = css(elem, "position") == "fixed";
// Use getBoundingClientRect if available
if (false && elem.getBoundingClientRect) {
var box = elem.getBoundingClientRect();
// Add the document scroll offsets
add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
// IE adds the HTML element's border, by default it is medium which is 2px
// IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
// IE 7 standards mode, the border is always 2px
// This border/offset is typically represented by the clientLeft and clientTop properties
// However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
// Therefore this method will be off by 2px in IE while in quirksmode
add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
// Otherwise loop through the offsetParents and parentNodes
} else {
// Initial element offsets
add( elem.offsetLeft, elem.offsetTop );
// Get parent offsets
while ( offsetParent ) {
// Add offsetParent offsets
add( offsetParent.offsetLeft, offsetParent.offsetTop );
// Mozilla and Safari > 2 does not include the border on offset parents
// However Mozilla adds the border for table or table cells
if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
border( offsetParent );
// Add the document scroll offsets if position is fixed on any offsetParent
if ( !fixed && css(offsetParent, "position") == "fixed" )
fixed = true;
// Set offsetChild to previous offsetParent unless it is the body element
offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
// Get next offsetParent
offsetParent = offsetParent.offsetParent;
}
// Get parent scroll offsets
while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
// Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
if ( !/^inline|table.*$/i.test(css(parent, "display")) )
// Subtract parent scroll offsets
add( -parent.scrollLeft, -parent.scrollTop );
// Mozilla does not add the border for a parent that has overflow != visible
if ( mozilla && css(parent, "overflow") != "visible" )
border( parent );
// Get next parent
parent = parent.parentNode;
}
// Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
// Mozilla doubles body offsets with a non-absolutely positioned offsetChild
if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
(mozilla && css(offsetChild, "position") != "absolute") )
add( -doc.body.offsetLeft, -doc.body.offsetTop );
// Add the document scroll offsets if position is fixed
if ( fixed )
add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
}
// Return an object with top and left properties
results = { top: top, left: left };
}
function border(elem) {
/// <summary>
/// This method is internal.
/// </summary>
/// <private />
add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
}
function add(l, t) {
/// <summary>
/// This method is internal.
/// </summary>
/// <private />
left += parseInt(l, 10) || 0;
top += parseInt(t, 10) || 0;
}
return results;
};
If you would like to fix the minified/compressed .js file for jQuery version 1.4.2, replace:
var d=b.getBoundingClientRect(),
with
var d = null;
try { d = b.getBoundingClientRect(); }
catch(e) { d = { top : b.offsetTop, left : b.offsetLeft } ; }
(note that there is no comma after the closing brace now)
i tried the following workaround for the getBoundingClientRect() unspecified error whilst drag n drop, and it works fine.
in the jquery.1.4.2.js (i.e base jquery file, where the error is thrown exactly)
replace the elem.getBoundingClientRect() function call in js file
//the line which throws the unspecified error
var box = elem.getBoundingClientRect(),
with this..
var box = null;
try
{
box = elem.getBoundingClientRect();
}
catch(e)
{
box = { top : elem.offsetTop, left : elem.offsetLeft } ;
}
This solves the issue and drag n drop will work quitely even after post back through update panel
Regards
Raghu
My version is:
Add function:
function getOffsetSum(elem) {
var top = 0, left = 0
while (elem) {
top = top + parseInt(elem.offsetTop)
left = left + parseInt(elem.offsetLeft)
try {
elem = elem.offsetParent
}
catch (e) {
return { top: top, left: left }
}
}
return { top: top, left: left }
};
replace
var box = this[0].getBoundingClientRect()
with
var box = getOffsetSum(this[0])
PS: jquery-1.3.2.
#Raghu
Thanks for this bit of code! I was having the same problem in IE and this fixed it.
var box = null;
try {
box = elem.getBoundingClientRect();
} catch(e) {
box = {
top : elem.offsetTop,
left : elem.offsetLeft
};
}
This isn't just a jQuery error. I encountered it using ExtJS 4.0.2a on IE8. It seems that IE will almost always stumble on element.getBoundingClientRect() if the element has been replaced in the DOM. Your try/catch hack is pretty much the only way to get around this. I guess the actual solution would be to eventually drop IE < 9 support.
Relevent ExtJS v4.0.2a Source Code (lines 11861-11869):
...
if(el != bd){
hasAbsolute = fly(el).isStyle("position", "absolute");
if (el.getBoundingClientRect) {
b = el.getBoundingClientRect();
scroll = fly(document).getScroll();
ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
} else {
...
With a try/catch fix:
...
if(el != bd){
hasAbsolute = fly(el).isStyle("position", "absolute");
if (el.getBoundingClientRect) {
try {
b = el.getBoundingClientRect();
scroll = fly(document).getScroll();
ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
} catch(e) {
ret = [0,0];
}
} else {
...

Programatic Access to DragHandleTemplate in ASP.NET AJAX ReorderList

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.

Resources