|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThe ASP.NET 2.0 framework comes with the To achieve that, I developed an ASP.NET 2.0 AJAX Extensions Extender Control for use with ASP.NET 2.0 What You Can Do with the Extender and How to Use ItYou can use this extender control in existing ASP.NET 2.0 AJAX Extension application web pages which contain the ASP.NET 2.0 In the current version, the extender control must be placed at the same level in the control tree as the In the current release, the extender provides the following navigation and editing features, and the following default keyboard shortcut scheme:
You don't need to display the corresponding link buttons in order to select, delete, and edit a data row by keyboard shortcuts. This default keyboard scheme can easily be changed by changing the default key values in the extender class. To configure the keyboard scheme for a For paging, the extender works with both the numeric and the next/previous pager scheme. It works for all four existing BackgroundThe solution is based on an ASP.NET 2.0 AJAX Extender WebControl. This makes it easy to change the keyboard scheme on server-side and minimize work in the client-side JavaScript. The extender control works by simulating the corresponding postback commands of the The article will not cover the general steps in developing Extenders and Behaviour controls, but will describe the solution specific details. For a comprehensive documentation on how to develop an ASP.NET 2.0 AJAX Extensions Extender Control, read the documentation on AJAX.ASP.NET, and particulary the article about developing an Extender control. In a few words, to develop an Extender control which extends the client behavior of an ASP.NET server control on the client side, you must create an ASP.NET 2.0 AJAX Extender Control for the server side, and a corresponding JavaScript class, derived from the " Server-side CodeIn the following section, I will describe the important server side steps to build up the Extender control. In the following snippet, you see the definition of the Extender class on the server-side. [assembly: System.Web.UI.WebResource("AjaxSamples.GridViewKeyBoardPagerBehavior.js",
"application/x-javascript")]
namespace AjaxSamples
{
[TargetControlType(typeof(System.Web.UI.WebControls.GridView))]
public class GridViewKeyBoardPagerExtender : System.Web.UI.ExtenderControl
{
...
The extender makes only sense in conjunction with a As stated before, the extender works by triggering the postbacks of the The following code snippet shows the server side properties for handling the delete event. All other events have analogous properties. private string _delCmdArgument = string.Empty;
[Browsable(false)]
protected string DeleteCmdArgument
{
get { return _delCmdArgument; }
set { _delCmdArgument = value; }
}
private Keys _delKey = Keys.Delete;
[Browsable(false)]
protected string DeleteKeyCode
{
get { return Convert.ToInt32(_delKey).ToString(); }
}
[Browsable(true), DefaultValue(Keys.Delete)]
public Keys DeleteKey
{
get { return _delKey; }
set { _delKey = value; }
}
...
The property The public property The key values are defined an an enumeration found in the file KeyCodeEnums.cs. We need the unique id of the [Browsable(false)]
protected string PostBackCtrlID
{
get { return Grid.UniqueID; }
}
The private GridView _grid;
[Browsable(false)]
protected GridView Grid
{
get
{
if (_grid == null)
{
_grid = Parent.FindControl(
TargetControlID) as System.Web.UI.WebControls.GridView;
if (_grid == null)
{
throw new NullReferenceException(string.Format(
"{0} is not of type GridView or the GridView is no initialized.",
TargetControlID));
}
}
return _grid;
}
}
In the protected override void OnPreRender(EventArgs e)
{
// Grid is in edit mode, so we set corresponding command arguments.
// canceling or updating editing are the only allowed actions in this state.
// Grid is in edit mode so we set corresponding command values.
if (Grid.EditIndex > -1)
{
_editCancelCmdArgument = "Cancel$" + Grid.EditIndex.ToString();
_editUpdateCmdArgument = "Update$" + Grid.EditIndex.ToString();
}
else
{
// Is a row selected
if (Grid.SelectedIndex > -1)
{
// Deleting this row is possible
_delCmdArgument = "Delete$" + Grid.SelectedIndex.ToString();
// Editing// switch row to Editing mode is possible
_editBeginCmdArgument = "Edit$" + Grid.SelectedIndex.ToString();
// Selecting is possible if selecting is enabled
if (Grid.SelectedIndex == 0)
{
_prevSelectCmdArgument = String.Empty;
}
else
{
_prevSelectCmdArgument = "Select$" + Convert.ToString(Grid.SelectedIndex - 1);
}
if ((Grid.SelectedIndex == Grid.PageSize - 1) || (
Grid.SelectedIndex == Grid.Rows.Count - 1))
{
_nextSelectCmdArgument = String.Empty;
}
else
{
_nextSelectCmdArgument = "Select$" + Convert.ToString(Grid.SelectedIndex + 1);
}
}
#region Paging
// depending of the PagerSettings.Mode value the CommandArgument value of
// the Pager LinkButtons differ.
switch (Grid.PagerSettings.Mode)
{
case PagerButtons.Numeric:
case PagerButtons.NumericFirstLast:
#region Prev/Next Paging Arguments
// claculate Next/Previous Pager Arguments
// there is no previous page, the grid shows the first page
if (Grid.PageIndex == 0)
{
_prevPageCmdArgument = string.Empty;
}
else
{
_prevPageCmdArgument = "Page$" + Convert.ToString(Grid.PageIndex);
}
// there is no next page. The grid shows the last page
if (Grid.PageIndex + 2 > Grid.PageCount)
{
_nextPageCmdArgument = string.Empty;
}
else
{
_nextPageCmdArgument = "Page$" + Convert.ToString(Grid.PageIndex + 2);
}
#endregion
break;
case PagerButtons.NextPrevious:
case PagerButtons.NextPreviousFirstLast:
#region Prev/Next Paging
// there is no previous page, the grid shows the first page
if (Grid.PageIndex == 0) {
_prevPageCmdArgument = String.Empty;
}
else
{
_prevPageCmdArgument = "Page$Prev";
}
// there is no next page. The grid shows the last page
if (Grid.PageIndex == Grid.PageCount - 1)
{
_nextPageCmdArgument = String.Empty;
}
else
{
_nextPageCmdArgument = "Page$Next";
}
#endregion
break;
}
#region First/Last Paging Settings
if (Grid.PageIndex == 0)
{
_firstPageCmdArgument = String.Empty;
}
else
{
_firstPageCmdArgument = "Page$First";
}
if (Grid.PageIndex == Grid.PageCount - 1)
{
_lastPageCmdArgument = String.Empty;
}
else
{
_lastPageCmdArgument = "Page$Last";
}
#endregion
#endregion
}
base.OnPreRender(e);
}
During postback, for security purposes, the ASP.NET runtime checks whether the control ID and the command argument is a valid combination that is allowed to fire postback events. For that, we need to register the protected override void Render(HtmlTextWriter writer)
{
ClientScriptManager csm = Page.ClientScript;
for (int i = 0; i < Grid.PageSize; i++)
{
csm.RegisterForEventValidation(Grid.UniqueID, "Select$" + i.ToString());
csm.RegisterForEventValidation(Grid.UniqueID, "Edit$" + i.ToString());
csm.RegisterForEventValidation(Grid.UniqueID, "Cancel$" + i.ToString());
csm.RegisterForEventValidation(Grid.UniqueID, "Delete$" + i.ToString());
...
To bridge the server side part of the extender with the client side part, you have to override the method protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(
Control targetControl)
{
ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor(
"AjaxSamples.GridViewKeyBoardPagerBehavior", targetControl.ClientID);
descriptor.AddProperty("_firstCmdArgument", this.FirstPageCmdArgument);
descriptor.AddProperty("_lastCmdArgument", this.LastPageCmdArgument);
...
return new ScriptDescriptor[] { descriptor };
}
In the method protected override IEnumerable<ScriptReference> GetScriptReferences()
{
ScriptReference reference = new ScriptReference();
reference.Name = "AjaxSamples.GridViewKeyBoardPagerBehavior.js";
reference.Assembly = "AjaxSamples";
return new ScriptReference[] { reference };
}
Now, we have finished the server side part of the extender control. The following part describes the important details on the client-side. Client-side CodeAs the first important step, we register a AjaxSamples.GridViewKeyBoardPagerBehavior.prototype = {
initialize : function() {
AjaxSamples.GridViewKeyBoardPagerBehavior.callBaseMethod(this, 'initialize');
// we catch the keydown event at the document level of the HTML DOM tree
$addHandler(document, 'keydown', Function.createDelegate(this, this._onKeyDown));
window.onkeydown = function(e)
{
if (keyEvent.ctrlKey == true) {
if (e.keyCode == "68") {
return false;
}
}
}
},
dispose : function() {
AjaxSamples.GridViewKeyBoardPagerBehavior.callBaseMethod(this, 'dispose');
$clearHandlers(document);
},
Another thing we do here is deactivate any keyboard shortcuts of the browser that conflicts with one of our keyboard shortcuts. In this case, we deactivate the "Add to Favorites" (CTRL+D) of the Firefox browser that conflicts with our Save Changes shortcut when editing a row in the The next interesting thing is the handler itself. // Event Handler that catches the keyboard event
_onKeyDown : function(keyEvent) {
var cmdArgument = "";
if (keyEvent.ctrlKey == true) {
if (keyEvent.keyCode == this._firstKeyCode) {
cmdArgument = this._firstCmdArgument;
}
if (keyEvent.keyCode == this._lastKeyCode) {
cmdArgument = this._lastCmdArgument;
}
...
if (keyEvent.keyCode == this._editUpdateKeyCode) {
window.onkeypress = function(keyEvent){return false;}
if (this._editUpdateCmdArgument != "") {
feedBack = confirm("Save Changes?");
if (feedBack) {
cmdArgument = this._editUpdateCmdArgument;
}
}
}
if (cmdArgument != "") {
__doPostBack(this._postBackCtrlID, cmdArgument);
return;
}
}
...
In the handler, you can edit the code to adapt the behavior of the extender when pressing a key (combination) to your needs. In the Using the codeTo use the extender in your project, unzip the code and add it to your solution. Now, your are ready to use the extender in your existing or upcoming projects. You can add it in the ASP.NET Toolbox if you use it regularly. The following ASP.NET markup shows how the <%@ Register Assembly="AjaxSamples" Namespace="AjaxSamples" TagPrefix="cc1" %>
...
<asp:ScriptManager runat="server" ID="ScripManager1">
</asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="UpdatePanel1" ChildrenAsTriggers="true"
UpdateMode="Conditional">
<ContentTemplate>
<div>
<asp:AccessDataSource ID="Northwind" runat="server"
DataFile="~/App_Data/Nwind.mdb"
SelectCommand="SELECT [CustomerID], [CompanyName], [ContactName],
[Address], [City], [Country] FROM [Customers]">
</asp:AccessDataSource>
<asp:GridView ID="GridView1"
runat="server"
DataSourceID="Northwind"
DataKeyNames="CustomerID"
AutoGenerateColumns="true" AllowPaging="True" >
</asp:GridView>
<cc1:GridViewKeyBoardPagerExtender NextKey="Up" PreviousKey="Down"
ID="GridViewKeyBoardPagerExtender1" runat="server" TargetControlID="GridView1" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||