Creating Custom ASP.NET Server Controls with Embedded JavaScript
2012-02-24 13:37
471 查看
I did some consulting work recently for a company that had a lot of JavaScript embedded in pages that was used used to perform advanced client-side functionality and make AJAX calls back to the server. The company needed additional team members to be able
to contribute to the application without spending a lot of time learning client-side Web technologies. One solution was to provide good documentation of the JavaScript objects and methods that could be called. This still required some fundamental knowledge
of JavaScript though. The focus, however, seemed to be on getting other team members involved with learning C# and server-side technologies so that they could also build back-end code tiers rather than having everyone spend time learning JavaScript and other
related client-side technologies such as CSS and DHTML/DOM.
After seeing the existing application and hearing about the challenges the team was facing, I provided a demo of how custom ASP.NET server controls could have JavaScript embedded in them fairly easily. By going this route the people that knew JavaScript could
still leverage their existing skills, but they could wrap the client-side functionality in a server control that other developers could more easily consume and use without having to be client-side gurus. Going this route also allowed properties that scripts
may utilitize to be exposed along with documentation of what the properties do.
The following steps show how to accomplish this type of JavaScript encapsulation. The steps extend ASP.NET's standard GridView control and customize it by adding additional client-side functionality. I'll admit upfront that this is a fairly simple example
designed only as a starting point. However, the concepts can be applied to more advanced cases. I'm using the exact same principles in version 2.5 of my OrgChart.NET
server control (due out soon).
Step 1: Choose how to create your custom control. You have two main choices when creating custom server controls. You can choose to write a control from scratch, or you can extend an existing control provided by ASP.NET or a 3rd party vendor.
Let's say that you'd like to create a "fancy" grid control that highlights rows as a user mouses over them and allows users to select one or more rows and highlight them. All of this is done on the client-side without any postback operations. While you could
write the grid functionality from scratch, why not leverage what Microsoft has already done if it gets you to the desired end result faster and satisfies project requirements? This is easily done by creating a new Class Library project in VS.NET 2005 and
deriving the custom control class from GridView as shown next:
[ToolboxData(@"<{0}:CustomGridView runat=""server"" \>")]
public class CustomGridView : GridView
{
}
The ToolboxData attribute defines what markup code should be added to an ASP.NET page as a developer drags the control onto a page's design surface.
Step 2. Write the client-side code. This step could certainly be performed later, but I like to write the client-side enhancements upfront. In this case, if we want end users to be able to see highlighted rows as they mouse over them, or
select rows by clicking them, we can use code similar to the following.
function MouseEnter(row,bgColor,textColor)
{
if (row.getAttribute("Selected") == "true") return;
row.style.backgroundColor = bgColor;
row.style.color = textColor;
}
function MouseLeave(row)
{
if (row.getAttribute("Selected") == "true") return;
row.style.backgroundColor = row.getAttribute("OriginalColor");
row.style.color = row.getAttribute("OriginalTextColor");
}
function MouseDown(row,bgColor,textColor)
{
if (row.getAttribute("Selected")=="true")
{
row.style.backgroundColor = row.getAttribute("OriginalColor");
row.style.color = row.getAttribute("OriginalTextColor");
row.setAttribute("Selected","false");
}
else
{
row.style.backgroundColor = bgColor;
row.style.color = textColor
row.setAttribute("Selected","true");
}
}
Since we want to embed the JavaScript code directly into the control, add a new JavaScript file into the Class Library project and set its Build Action to "Embedded Resource". This can be done by right-clicking on the .js file in the Solution Explorer, selecting
Properties, and changing the Build Action property.
Step 3. Define the JavaScript file as a Web Resource. There are two main ways to output JavaScript from a server-side control. First, you can embed JavaScript in the control's code and then output it using the ClientScriptManager class's
RegisterClientScriptBlock() method (or another custom technique). This works, but makes the control's code less maintainable since JavaScript is embedded in VB.NET or C# code. Also, when the JavaScript is output it is embedded in the page's HTML which isn't
a good option when you want to leverage client-side caching of JavaScript files.
The second option (the better option in my opinion) is to use ASP.NET 2.0's WebResource.axd HttpHandler in conjunction with the ClientScriptManager class to dynamically output embedded resources such as JavaScript files. By using WebResource.axd the custom control
can output a <script src="..."></script> tag into the page that dynamically references the JavaScript resource on the server. This allows the client browser to cache the script which should lead to faster page loads especially if the script is large. By
embedding the JavaScript file as a resource rather than putting it in the control's code, the overall code base is also much easier to maintain.
To allow the custom control to write out <script src="..."></script> tags, the target JavaScript file must first be added as a resource into the project as shown in the previous step. After doing that, the following code should be added into the AssemblyInfo.cs
file (this file is added automatically when you create a Class Library project).
[assembly: WebResource("CustomControls.GridViewScript.js", "text/javascript")]
This code uses the WebResourceAttribute class to give the embedded script a name and define the appropriate content type of the resource. The name starts with the namespace of the project and
ends with the name of the script that is embedded in the project as a resource. This technique can also be used to embed images, CSS files or other types of resources.
Step 4: Render the script to the browser. Once the WebResource attribute has been added into AssemblyInfo.cs, the following code can be added into the custom control to cause a <script src="..."></script> tag referencing the embedded script
resource to be output to the page. The call to the ClientScriptManager's RegisterClientScriptResource() method does all the work. It takes the type of control being rendered as well as the resource name defined in AssemblyInfo.cs as parameters.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string resourceName = "CustomControls.GridViewScript.js";
ClientScriptManager cs = this.Page.ClientScript;
cs.RegisterClientScriptResource(typeof(CustomControls.CustomGridView), resourceName);
}
Step 5: Hook the custom control to JavaScript functions. Now that the JavaScript is ready to be output, the custom control needs to be "hooked" to the client-side functions shown earlier in Step 2 in order to perform the desired behaviors.
The following code uses the GridView's RowCreated event to add client-side mouse over, mouse out and mouse down attributes to rows in the grid. Adding these event handlers could also be done entirely on the client-side in cases where the size of the HTML
markup sent from the server to the browser needs to be kept to a minimum.
protected override void OnRowCreated(GridViewRowEventArgs e)
{
base.OnRowCreated(e);
GridViewRow row = e.Row;
Color bgColor = Color.Empty;
Color color = Color.Empty;
if (row.RowIndex % 2 == 0)
{
bgColor = (this.RowStyle.BackColor == Color.Empty) ? Color.White : this.RowStyle.BackColor;
color = (this.RowStyle.ForeColor == Color.Empty) ? Color.Black : this.RowStyle.ForeColor;
}
else
{
bgColor = (this.AlternatingRowStyle.BackColor == Color.Empty) ? Color.White : this.AlternatingRowStyle.BackColor;
color = (this.AlternatingRowStyle.ForeColor == Color.Empty) ? Color.Black : this.AlternatingRowStyle.ForeColor;
}
if (row.RowType == DataControlRowType.DataRow)
{
row.Attributes.Add("onmouseover", String.Format("MouseEnter(this,'{0}','{1}')",
ColorTranslator.ToHtml(this.MouseOverColor),
ColorTranslator.ToHtml(this.TextOverColor)));
row.Attributes.Add("onmouseout", "MouseLeave(this)");
row.Attributes.Add("onmousedown", String.Format("MouseDown(this,'{0}','{1}')",
ColorTranslator.ToHtml(this.SelectedRowColor),
ColorTranslator.ToHtml(this.SelectedRowTextColor)));
row.Attributes.Add("OriginalColor", ColorTranslator.ToHtml(bgColor));
row.Attributes.Add("OriginalTextColor", ColorTranslator.ToHtml(color));
}
}
The end result of following these steps is that JavaScript is dynamically output from the control in an efficient manner. An example of what the ClientScriptManager outputs to reference the JavaScript resource is shown next (some characters were removed for
the sake of brevity):
<script src="/ControlDemo/WebResource.axd?d=3SnAJwuH.......2&t=633134805717880000" type="text/javascript"></script>
The control is now self-contained and does not require any additional files to be deployed before it can be used. It's also easy to maintain since the JavaScript is stored as an external resource rather than being embedded in VB.NET or C# code. While this
is a simple example, more complex scripts and code can be written to handle the needs of any Web application. The complete code for the custom control discussed in this article can be downloaded
here.
to contribute to the application without spending a lot of time learning client-side Web technologies. One solution was to provide good documentation of the JavaScript objects and methods that could be called. This still required some fundamental knowledge
of JavaScript though. The focus, however, seemed to be on getting other team members involved with learning C# and server-side technologies so that they could also build back-end code tiers rather than having everyone spend time learning JavaScript and other
related client-side technologies such as CSS and DHTML/DOM.
After seeing the existing application and hearing about the challenges the team was facing, I provided a demo of how custom ASP.NET server controls could have JavaScript embedded in them fairly easily. By going this route the people that knew JavaScript could
still leverage their existing skills, but they could wrap the client-side functionality in a server control that other developers could more easily consume and use without having to be client-side gurus. Going this route also allowed properties that scripts
may utilitize to be exposed along with documentation of what the properties do.
The following steps show how to accomplish this type of JavaScript encapsulation. The steps extend ASP.NET's standard GridView control and customize it by adding additional client-side functionality. I'll admit upfront that this is a fairly simple example
designed only as a starting point. However, the concepts can be applied to more advanced cases. I'm using the exact same principles in version 2.5 of my OrgChart.NET
server control (due out soon).
Step 1: Choose how to create your custom control. You have two main choices when creating custom server controls. You can choose to write a control from scratch, or you can extend an existing control provided by ASP.NET or a 3rd party vendor.
Let's say that you'd like to create a "fancy" grid control that highlights rows as a user mouses over them and allows users to select one or more rows and highlight them. All of this is done on the client-side without any postback operations. While you could
write the grid functionality from scratch, why not leverage what Microsoft has already done if it gets you to the desired end result faster and satisfies project requirements? This is easily done by creating a new Class Library project in VS.NET 2005 and
deriving the custom control class from GridView as shown next:
[ToolboxData(@"<{0}:CustomGridView runat=""server"" \>")]
public class CustomGridView : GridView
{
}
The ToolboxData attribute defines what markup code should be added to an ASP.NET page as a developer drags the control onto a page's design surface.
Step 2. Write the client-side code. This step could certainly be performed later, but I like to write the client-side enhancements upfront. In this case, if we want end users to be able to see highlighted rows as they mouse over them, or
select rows by clicking them, we can use code similar to the following.
function MouseEnter(row,bgColor,textColor)
{
if (row.getAttribute("Selected") == "true") return;
row.style.backgroundColor = bgColor;
row.style.color = textColor;
}
function MouseLeave(row)
{
if (row.getAttribute("Selected") == "true") return;
row.style.backgroundColor = row.getAttribute("OriginalColor");
row.style.color = row.getAttribute("OriginalTextColor");
}
function MouseDown(row,bgColor,textColor)
{
if (row.getAttribute("Selected")=="true")
{
row.style.backgroundColor = row.getAttribute("OriginalColor");
row.style.color = row.getAttribute("OriginalTextColor");
row.setAttribute("Selected","false");
}
else
{
row.style.backgroundColor = bgColor;
row.style.color = textColor
row.setAttribute("Selected","true");
}
}
Since we want to embed the JavaScript code directly into the control, add a new JavaScript file into the Class Library project and set its Build Action to "Embedded Resource". This can be done by right-clicking on the .js file in the Solution Explorer, selecting
Properties, and changing the Build Action property.
Step 3. Define the JavaScript file as a Web Resource. There are two main ways to output JavaScript from a server-side control. First, you can embed JavaScript in the control's code and then output it using the ClientScriptManager class's
RegisterClientScriptBlock() method (or another custom technique). This works, but makes the control's code less maintainable since JavaScript is embedded in VB.NET or C# code. Also, when the JavaScript is output it is embedded in the page's HTML which isn't
a good option when you want to leverage client-side caching of JavaScript files.
The second option (the better option in my opinion) is to use ASP.NET 2.0's WebResource.axd HttpHandler in conjunction with the ClientScriptManager class to dynamically output embedded resources such as JavaScript files. By using WebResource.axd the custom control
can output a <script src="..."></script> tag into the page that dynamically references the JavaScript resource on the server. This allows the client browser to cache the script which should lead to faster page loads especially if the script is large. By
embedding the JavaScript file as a resource rather than putting it in the control's code, the overall code base is also much easier to maintain.
To allow the custom control to write out <script src="..."></script> tags, the target JavaScript file must first be added as a resource into the project as shown in the previous step. After doing that, the following code should be added into the AssemblyInfo.cs
file (this file is added automatically when you create a Class Library project).
[assembly: WebResource("CustomControls.GridViewScript.js", "text/javascript")]
This code uses the WebResourceAttribute class to give the embedded script a name and define the appropriate content type of the resource. The name starts with the namespace of the project and
ends with the name of the script that is embedded in the project as a resource. This technique can also be used to embed images, CSS files or other types of resources.
Step 4: Render the script to the browser. Once the WebResource attribute has been added into AssemblyInfo.cs, the following code can be added into the custom control to cause a <script src="..."></script> tag referencing the embedded script
resource to be output to the page. The call to the ClientScriptManager's RegisterClientScriptResource() method does all the work. It takes the type of control being rendered as well as the resource name defined in AssemblyInfo.cs as parameters.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string resourceName = "CustomControls.GridViewScript.js";
ClientScriptManager cs = this.Page.ClientScript;
cs.RegisterClientScriptResource(typeof(CustomControls.CustomGridView), resourceName);
}
Step 5: Hook the custom control to JavaScript functions. Now that the JavaScript is ready to be output, the custom control needs to be "hooked" to the client-side functions shown earlier in Step 2 in order to perform the desired behaviors.
The following code uses the GridView's RowCreated event to add client-side mouse over, mouse out and mouse down attributes to rows in the grid. Adding these event handlers could also be done entirely on the client-side in cases where the size of the HTML
markup sent from the server to the browser needs to be kept to a minimum.
protected override void OnRowCreated(GridViewRowEventArgs e)
{
base.OnRowCreated(e);
GridViewRow row = e.Row;
Color bgColor = Color.Empty;
Color color = Color.Empty;
if (row.RowIndex % 2 == 0)
{
bgColor = (this.RowStyle.BackColor == Color.Empty) ? Color.White : this.RowStyle.BackColor;
color = (this.RowStyle.ForeColor == Color.Empty) ? Color.Black : this.RowStyle.ForeColor;
}
else
{
bgColor = (this.AlternatingRowStyle.BackColor == Color.Empty) ? Color.White : this.AlternatingRowStyle.BackColor;
color = (this.AlternatingRowStyle.ForeColor == Color.Empty) ? Color.Black : this.AlternatingRowStyle.ForeColor;
}
if (row.RowType == DataControlRowType.DataRow)
{
row.Attributes.Add("onmouseover", String.Format("MouseEnter(this,'{0}','{1}')",
ColorTranslator.ToHtml(this.MouseOverColor),
ColorTranslator.ToHtml(this.TextOverColor)));
row.Attributes.Add("onmouseout", "MouseLeave(this)");
row.Attributes.Add("onmousedown", String.Format("MouseDown(this,'{0}','{1}')",
ColorTranslator.ToHtml(this.SelectedRowColor),
ColorTranslator.ToHtml(this.SelectedRowTextColor)));
row.Attributes.Add("OriginalColor", ColorTranslator.ToHtml(bgColor));
row.Attributes.Add("OriginalTextColor", ColorTranslator.ToHtml(color));
}
}
The end result of following these steps is that JavaScript is dynamically output from the control in an efficient manner. An example of what the ClientScriptManager outputs to reference the JavaScript resource is shown next (some characters were removed for
the sake of brevity):
<script src="/ControlDemo/WebResource.axd?d=3SnAJwuH.......2&t=633134805717880000" type="text/javascript"></script>
The control is now self-contained and does not require any additional files to be deployed before it can be used. It's also easy to maintain since the JavaScript is stored as an external resource rather than being embedded in VB.NET or C# code. While this
is a simple example, more complex scripts and code can be written to handle the needs of any Web application. The complete code for the custom control discussed in this article can be downloaded
here.
相关文章推荐
- Creating Custom ASP.NET Server Controls with Embedded JavaScript
- Professional Web Parts and Custom Controls with ASP.NET 2.0
- Validation Server Controls->ASP.NET CustomValidator Control
- ASP.NET User Controls and Custom Server Controls
- Building ASP.NET Server Controls-CustomEventTextbox.cs
- ASP.net(1.1)原理学习笔记--第八章 自定义控件Custom Controls
- Exchange Server Mail server with asp.NET 1st step
- Javascript中的函数替代ASP.NET的Server.UrlEncode
- Web Server Controls->ASP.NET Image Control
- ASP.NET SignalR-Server Broadcast with SignalR
- Web server Controls->ASP.NET TextBox Control
- Advanced ASP.NET AJAX Server Controls For .NET Framework 3.5
- Creating ASP.NET Controls Dynamically
- Developing ASP.NET Custom Control With C# Builder
- Creating Custom Helper Methods 创建自定义辅助器方法----辅助器方法 ------ 精通ASP.NET MVC 5
- EF Database First with ASP.NET MVC: Creating the Web Application and Data Models开发遇到问题的解决办法
- [转]jQuery AJAX pagination plugin with ASP.NET Server Side
- Redirecting to custom 401 page when "Access denied" occures within an ASP.NET application with Windows authentication
- 51 Recipes on using jQuery with ASP.NET Controls
- 创建自定义路由处理程序(Creating a Custom Route Handler) | 定制路由系统| 高级路由特性 |精通ASP-NET-MVC-5-弗瑞曼