GridView rows jumping around while editing data - asp.net

I've got a simple intranet form (ASP.NET 2.0) with a GridView bound to data from Active Directory. It does this with an SqlDataSource that selects from a view that pulls the data from AD. This works better than doing LDAP queries directly from ASP.NET, since I can do table joins, etc. without much fuss. The GridView has a CommandField column with an edit button, and a few EditItemTemplates with DropDownLists for selecting valid values.
Updates, on the other hand, are done by connecting directly to AD. To allow for this, I have to handle the OnRowUpdating event of the GridView, and set Cancel in the GridViewUpdateEventArgs to true, since the SqlDataSource has no update command defined. Then it just creates a DirectorySearcher, looks up the user based on distinguishedName (the data key of the GridView), calls GetDirectoryEntry() on the result, sets a couple properties, and finally calls CommitChanges() on the DirectoryEntry. No problems there - it's updating the data just fine.
It is, however, behaving a little confusingly. It seems there's a bit of a propagation delay when updating the data. It takes roughly ten seconds after updating before the view used for the SqlDataSource reflects the change. I'm not sure if this is typical AD behavior, or if the view is connecting to a different DC than the one the update is being issued against. This behavior isn't a problem in and of itself, and I can live with it if necessary.
But while that isn't a big problem, it's causing another issue - the GridView is sorted by default on the "company" column, which is one of the properties the user is allowed to edit. If the user changes the company on a row, waits a little while (or continues making multiple edits), then goes to edit another row, they could potentially end up editing a row adjacent to the one they wanted. This is because the GridView rebinds, and suddenly the row that had its company changed is sorted elsewhere in the list. The GridView is evidently triggering the edit based on the index of the row, and suddenly there's a different row at that index because the view used for the data source suddenly just caught up to reality.
What's sort of perplexing is that the GridView is trying to data bind on every post-back. In the past, I've had to make sure to call DataBind() after making data edits to ensure the data is up-to-date, but now it's happily hitting the data source every time. And yet the page ViewState is coming in around 66 KB, so I know the GridView is putting its data there.
So, off the top of my head, these would be a couple of fixes (that I haven't implemented successfully yet).
Stop the GridView from data binding with every page load, and stick with what it's got cached in ViewState. There's no "Cancel" property on the GridView's OnDataBinding event args, and setting Cancel during the data source's OnSelecting event just leaves me with an empty GridView.
Fix the propagation delay. Again, I don't have my heart set on that, but if it's a means of fixing the rows jumping around unexpectedly, then that's fine with me. Would I just have to make sure I'm explicitly connecting to the same DC both in the database view and when updating AD from ASP.NET? Or is there something more going on?
Trigger the row edit based on the primary key of the row rather than the index. I'm guessing I'd have to create a CommandButton in the row, set the CommandArgument to the primary key of the row, then walk through all the rows in the GridView on post-back and manually set EditIndex accordingly.
I'm open to other ideas too. If the ViewState ends up being a couple hundred KB, that's workable. This site is accessed over a pretty speedy LAN, and is strictly for internal use.

Updating Active Directory from ASP.NET tends to be a little slow no matter how you access it.
Not knowing what your code looks like, I would suggest the UpdatePanel and UpdateProgess tools if you are using the default ASP.NET tool set.
This will prevent any additional calls to the server until the update is complete. Something like this
<asp:UpdateProgress ID="updateMyGridViewProgress" runat="server">
<ProgressTemplate>
<img src="images/loading.gif" alt="Updating the information" />
</ProgressTemplate>
</asp:UpdateProgress>
<asp:UpdatePanel ID="updateMyGridView" runat="server">
<ContentTemplate>
<asp:GridView
ID="myGridView"
OnRowUpdating="UpdateAdInfo"
runat="server" >
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
I've had to use something similar to this to help users understand when the update had completed in the past.
However, the default ASP.NET AJAX UpdatePanel tends to be verbose in the information that it posts back to the server for even simple operations.
Personally, I would try to avoid using GridView and use something a little more AJAX friendly (ie jqGrid http://www.trirand.com/blog/)

Related

ASP.NET how to pass a reference to a particular control

I'm generally an ASP.NET MVC guy, so the "standard" ASP.NET stuff is a little difficult for me to wrap my brain around. I've tried looking for the answer, but the keywords I'm using seem to be too generic... I get a lot of close answers, but not what I'm actually looking for.
I have a grid that is populated from a data set. One of the fields is a dropdown with 4 possible statuses. When the user selects a status, an event is fired in the codebehind to make the change in the db immediately.
There is a particular status that I need to confirm, because once it's selected, it's irreversible. Figuring out how to have the back end pop up a confirmation box was annoying, but I think I have that part done now.
The problem is, if the user confirms that the status they selected for the dropdown was intended, I need to disable any further changes to that dropdown, either by disabling the control or by removing the row altogether. With this requirement, I imagine I need to pass a reference to the specific control that fired the event back to the script, so that it can pass it through the postback, where I would need to consume it.
I have no idea how to pass a reference to the control (what can be used as a reference?) and I have no idea how to use that reference in the postback.
Any help would be greatly appreciated.
;p i was waiting for you to find my post on the issue lol.
but to put it simply, you postback to the page, all members are still available to you if you instantiated something in codebehind. if not, then use FindControl to pull them from DOM. here's the passing values stuff.
as long as you don't kill the lifecycle, you're fine: Passing dropdownlist selected value to another page's dropdown list
and here is the linkspam (full docs): How do I keep TCP/IP socket open in IIS?
probably the articles on session-state and page lifecycle will be of most use.
To prompt the user for confirm add this attribute to dropdownlist.
onchange="return confirm('Confirmation Message');"

Repeater Control asp.net

I have a repeater control that displays a playlist for my users, this control can sometimes hold say 1000 or more songs. This is a great feature, I was previously using jQuery to do client side sorting, but that has limitations. So I implemented server side sorting which works great, the only issue i am seeing is that when playlist are this long it takes a second or 2 before the postback and sorting is actually started.
I have watched the actions in firebug and done some research and understand that the databound values are not preserved, which makes sence. My question is, When watching in Firebug, it looks like the repeater control removes all the items in the collection before it starts the postback? is this true have others experienced this?
The repeater control ceases to exist entirely between postbacks. The repeater control is called into existance when you make a page request. It is populated, etc. then rendered to the browser. Once done, ASP.NET will delete all the objects on the page (or rather the garbage collector will get them when required. Either way, you can't get them any more).
When the postback happens it has to re-create the entire repeater all over again. There are some mechanisms, such as viewstate, that try to make this as seamless as possible (i.e. recreating controls just as you left them in the previous request) but they sometimes don't work the way you might expect.

Reasons why viewstate validation fails (but only sometimes)

The following message appears in our log:
The control tree into which viewstate
is being loaded must match the control
tree that was used to save viewstate
during the previous request. For
example, when adding controls
dynamically, the controls added during
a post-back must match the type and
position of the controls added during
the initial request.
Well, that's pretty clear, and alot has been written about this subject. However, I cannot reproduce this behavior, and I only find a couple thousand errors per day in the logs; so it's probably isn't that obvious.
The page in question has an UpdatePanel and loads one of three usercontrols depending on the querystring.
Is there any known issue with some clients, or any other possible explanation?
One possible Issue could be, that
you load Controls dynamically
you do not give them explicit an ID
the order in recreation of these control is different (GET vs. POST)
I had such an issue once. Also Repeater are good candidates for such a behaviour because each Item is an INamingContainer. If the content of the Repeater changes during Postback you could get that error.
I've seen this behaviour in cases where update panels are on the page and a value somewhere outside of this is changed but never propagated to the client.
The solution is to make sure that any value that gets changed gets updated client side. Thus when the postback occurs all the data matches what is supposed to be there server side.
If you have such data you can put it into an update panel as well.
Set UpdateMode="Conditional" on it and in your codebehind you can just call the update panels .update method when you need to update it.

Do I have to use Viewstate in ASP.NET

I am moving from classic ASP to ASP.NET and have encountered what many of you already know as "viewstate". I might be jumping the gun with my assumption, but it looks highly cumbersome. I have developed many ASP forms in the past and never had issues with keeping state. Is there another way OR am I going to have to learn this Viewstate thing in ASP.NET? I am using Visual Studio 2008, VB.NET as the code behind language and Framework v3.5 with SQL Server 2005.
You don't have to. Check out MVC framework. It eliminates ViewState and works as old ASP (at least from this point of view).
This series of posts is must reading for understanding ViewState
I disable it and do most of my work in Page_Init instead of Load (values are still maintained because of ControlState). This setup has worked out well for me.
ViewState is optional, but helpful. What ViewState is, is all the changes which occur on a control on the SERVER SIDE. So, if you're assigning text to a label, and you want that text to persist without the need to reassign it on every postback, then you'll want to maintain that. Another example where I always leave ViewState on is anything databound.
That said, there are times when it's helpful to turn ViewState off for that same reason. For example, the one place where I always turn ViewState off is a MESSAGE label. That way, when I have to print out a message to the user (one which should only appear once and then go away) I just add the text to the label and then forget about it. During the next PostBack, the label will automatically revert to the text which is found in the ASPX declaration for that control (in this case an empty string).
Now, note that this has nothing to do with the form collection, which are the values posted to IIS during the PostBack. The form collection sends the values that the user enters into form elements (textboxes, checkboxes, droplists,etc). These .NET will populate into the appropriate place--and this occurs AFTER ViewState has been processed.
This way, if you send a textbox with the phrase "hi there" to the client, the user changes it to "See ya" and then submits the form, what the textbox will have by the time the Page_Load event fires is a textbox with "See ya" in the TEXT attribute.
In classic ASP we always just used a HIDDEN field to do the job. Viewstate is just a way of doing that for you automatically. Trust me the learning curve is not as high as you might think.
Some controls are deeply crippled when you turn ViewState off, so be prepared to address these concerns. It's easiest to just be lazy and leave it on, but left unchecked, ViewState can easily account for 30% of the size of your HTML.
For example, say you have a DropDown, and you bind it to a list of Fruits. You bind it in the if(! IsPostBack) { } block in the page load. If you turn off ViewState, you'll lose the items when you click a button. They need to be bound every page load. You'll also lose your selected index, so you'd need to pull that off of the Request.Form[] variables.
Viewstate is part of the package when you are working with ASP.NET. For a basic page/website you shouldn't have to 'know' how to use Viewstate. It just gets used as you put controls on pages.
It's pretty hard to avoid Viewstate with ASP.NET because even if you turn it off at the project level, some individual controls still use Viewstate to persist their information.
If you don't want to deal with Viewstate, consider using the ASP.NET MVC framework. You will likely be more comfortable with the MVC framework coming from Classic ASP.
ViewState is completely optional in almost all if not all cases. ASP.NET re-populates fields automatically even if ViewStateEnabled=false. I've been using ASP.NET for 5 or 6 years and have never had to depend on ViewState. I even disable it when I can.
ViewState works automatically for the most part. It's just how ASP.NET keeps track of the current state of all it's controls.
You can manually use viewstate too, if you want to store some extra data. That is as simple as:
Viewstate["Key"] = value;
The only caveat with that is that any object you store in viewstate must be serializable.
I can definitely recommend avoiding ViewState in DataGrids and DropDownLists because I just recently started doing it myself. I didn't do this for fun, I had to fix a page that had grown so large that it was causing other problems. But this turned out to be easy, and the results were so dramatic that I am very pleased. Of course for a small simple app or for small amounts of data this will not be necessary, but on the other hand it's good to be consistent (always go from known to known so you can continually improve your process...), and why carry around extra baggage, ever?
This will require a little manual intervention on your part. For example, if you turn off viewstate for drop down lists, you'll need to rebind them on each postback, and then restore the SelectedValue from the Request object. You'll need to read up on this, but google has lots of readily available information.
Viewstate is kept automatically for asp.net controls "rooted" to the page. There is little you have to do, the values and some other information is passed in a hidden input B64 encoded. You can look at it if you want, but it doesn't matter, it's all handled automagically for you.
If you're writing code for your own consumption, you can just turn it off and not worry.
Presumably you're going to maintain Web Forms code written by other people, so you should know what the config options and pain points are. Top few I can think of
how to disable it at site, page and control level
why MachineKey is relevant in web farms
why your event log is full of ViewStateAuthentication errors
what ViewStateUserKey is
In terms of actual learning curve this is probably a thorough read of a couple of MSDN articles.
ViewState is a necessary evil inherent to the web forms metaphor. I personally find this methodology obsolete, bloated and generally not web-friendly. Better check out MVC framework as suggested above.
I suggest you avoid the temptation to use ViewState as a "cache" to pass data back and forth (I've seen websites doing this because of clustered setup and no SQL-backed session state). The data is serialized and added to the page and must do roundtrips every request, adding to the total size of the page and making your site slower to load.
'<%# Control Language="C#" AutoEventWireup="true" CodeFile="HomePage.ascx.cs" Inherits="HomePage" %>
<script runat="server">
void testHF_ValueChanged(object sender, EventArgs e)
{
this.HFvalue.Text = this.testHF.Value ;
}
</script>
<asp:Label ID="UserNamelbl" runat="server" Text="User Name : " Visible="false"></asp:Label>
<asp:TextBox ID="UserNametxt" runat="server" Visible="false" ></asp:TextBox>
<asp:Label ID="HFvalue" Text="......" runat="server"></asp:Label>
<asp:HiddenField ID="testHF"
OnValueChanged="testHF_ValueChanged"
value=""
runat="server" ></asp:HiddenField>
<input type="submit" name="SubmitButton" value="Submit" onclick="CL()" />
<script type="text/javascript">
function CL()
{
this.testHF.Value = this.UserNametxt.Text;
}
</script>
'

Double postback issue

I have a ASP.NET 1.1 application, and I'm trying to find out why when I change a ComboBox which value is used to fill another one (parent-child relation), two postbacks are produced.
I have checked and checked the code, and I can't find the cause.
Here are both call stacks which end in a page_load
First postback (generated by teh ComboBox's autopostback)
Postback call stack (broken)
Second postback (this is what I want to find why it's happening)
alt text (broken)
Any suggestion? What can I check?
It's a very specific problem with this code, I doubt it will be useful for someone else, but here it goes:
A check was added to the combo's onchange with an if, if the condition was met, an explicit call to the postback function was made.
If the combo was set to AutoPostback, asp.net added the postback call again, producing the two postbacks...
The generated html was like this:
[select onchange="javascript: if (CustomFunction()){__doPostBack('name','')}; __doPostBack('name','')"]
First thing I would look for is that you don't have the second ComboBox's AutoPostBack property set to true. If you change the value in the second combo with that property set true, I believe it will generate a postback on that control.
Do you have any code you could share? Double post backs plagued me so much in classic ASP back in the day that it was what finally prompted me to switch to .NET once and for all. Whenever I have problems like these for .NET, I go to every CONTROL and every PAGE element like load, init, prerender, click, SelectedIndexChanged, and the like and put a breakpoint.
Even if I don't have code there, I'll insert something like:
Dim i As Integer
i = 0
I am usually able to pinpoint some action that I wasn't expecting and fix as needed. I would suggest you do that here.
Good luck.
Check Request.Form["__EVENTTARGET"] to find the control initiating the postback - that may help you narrow it down.
Looking at the callstacks, and some Reflectoring (into ASP.NET 2 - I don't have 1.1 handy) - it looks like SessionStateModule.PollLockedSessionCallback is part of the HttpApplication startup routines. It may be possible that your app is being recycled - I'm pretty sure an event gets written into the Event log for that.
My only other suggestion would be Fiddler or something on the client to capture HTTP traffic.
This is very old post, but people still looking at this for solution exactly same as I did last week.
Like Grengby said Double events are primary reasons - but removing one of them is not allways an option. Atleast on my case and I had to resolve this on 3rd party's application.
I added following script and amended ASP form on masterpage:
<script>var Q = 0;</script>
<form id="Form1" runat="server" onsubmit="Q++; if(Q==1){return true;} else { return false;}">
This seems to be working and please forward your comments.
Arun
http://www.velocityreviews.com/forums/t117900-asp-net-multiple-postback-issue.html

Resources