rexlin:
Thanks rexlin, but that article misses the point entirely. That kind of "baked-in" concurrency only works if you have viewstate enabled for the GridView. If you happen to have the code for that tutorial, fire it up, load the concurrency page, and take a look at your page source - look at that big, bloated ViewState! Now disable ViewState for that page and try the following:
1. Bring up two browsers, both showing that page.
2. Delete an item in Browser #1 - it should refresh showing that item gone.
3. Go to Browser #2, you should still see the original item there since you didn't refresh the page. Without refreshing the page first, try to delete it. You'll notice it happily deletes whatever record happened to come AFTER the one you intended to delete since the GridView is tracking that even by row #.
My issue is that when ViewState is disabled for a GridView (which it almost always should be when you're dealing with a significant amount of data) the GridView loses it's mind when it comes to knowing which actual data item it's working with. The argument that gets passed for ItemCommand events is a row number. If the actual items (number or order) in the list have changed, it just acts on whatever item happens to be at that row at the time it gets loaded - which presents a problem in multi-user environments as well as if the user performs an action then immediately does a browser refresh.
I've got an idea for a workaround though that lets have the GridView events use the data key instead of row number, which is the way it should have worked to begin with in my opinion... Not to mention it'll let me handle concurrency based on a timestamp field in the database instead of having to track the pre and post values of every field in the record. I'll post an example once I have it worked out.