Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 57 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
57
Dung lượng
1,54 MB
Nội dung
Introduction to Ajax-enabled controls 309 An ASP.NET AJAX extender is conceptually similar to an extender provider in Win- dows Forms. It keeps a portion of functionality separated from a server control, and it provides additional properties to the extended control. These properties are used, in turn, to configure the properties of the client component that are associated with the extended control. NOTE To learn more about extender providers in Windows Forms, browse to http://msdn2.microsoft.com/en-us/library/ms171835.aspx. If you decide that both the server and the client capabilities should be specified in the same place, you need a script control. It’s a server control that is created as an Ajax-enabled control and can provide script references and script descriptors with- out the need for an external object. Returning to the example of an auto-complete text box, the AutoCompleteTextBox class that derives from TextBox is a good can- didate for becoming a script control. This model is illustrated in figure 9.7. Deciding whether to build an extender or a script control is a design choice you should make based on the requirements of the web application. Typically, an extender is the right choice when you want to plug client functionality into an existing server control, without the need to create a new control. A script control is the right choice if you want complete control over its capabilities both on the server and on the client side. ClientServer Extended Control Extender Script References Script Descriptors .aspx Figure 9.6 In the extender model, a server control receives the client functionality from the Extender control, which provides the script references and script descriptors needed to wire a client component to the extended control. 310 CHAPTER 9 Building Ajax-enabled controls From a slightly different point of view, the choice between an extender and a script control can be determined by the kind of client component you want to wire to the server control. Creating an extender is typically the right choice if you want to wire a client behavior to a DOM element. Because an element can have multiple behaviors, it makes sense to wire—on the server side—multiple extend- ers to a server control. Each extender contributes to the client capabilities of the extended control by providing a different client behavior. On the other hand, because a DOM element can be associated with one and only one client control, it makes more sense to associate the client control with a script control and have all the properties needed for configuring the client component embedded in the server control. We discussed client components and the client component model in great detail in chapter 8. Figure 9.8 shows the base interfaces and classes you can use to create extenders and script controls. ClientServer Script Control Script References Script Descriptors .aspx Figure 9.7 A script control is a server control that can both render markup code and provide the script references and script descriptors needed to instantiate client components. IExtenderControl ExtenderControl IScriptControl ScriptControl Figure 9.8 Base interface and classes provided by ASP.NET AJAX to create Ajax-enabled controls Extenders 311 There are two base classes: ExtenderControl and ScriptControl . The Extender- Control class creates extenders and implements the IExtenderControl interface. The ScriptControl class creates script controls and implements the IScriptCon- trol interface. The following sections will dive into the details of extenders and script con- trols. You’ll study the base interfaces and classes and learn how to use them to cre- ate Ajax-enabled controls. Let’s start the discussion by introducing extenders. 9.3 Extenders You already know that an extender’s goal is to wire a client component to an exist- ing server control. You need to know how the client functionality is attached to the extended control. The easiest way to build an extender is to declare a class that inherits from the base ExtenderControl class. This class implements an interface called IExtender- Control and takes care of registering the extender with the ScriptManager control. A derived class should override the methods defined in the IExtenderControl interface. Let’s look at this interface before you develop your first extender. 9.3.1 The IExtenderControl interface The IExtenderControl interface defines the contract to which a class adheres to become an extender. Figure 9.9 shows the methods implemented by the inter- face, which have the following responsibilities: ■ GetScriptDescriptors —Returns the list of script descriptors. The method receives a targetControl parameter that contains a reference to the extended control. ■ GetScriptReferences —Returns the list of ScriptReference objects. Each instance represents a script file that will be loaded in the page. > «interface» IExtenderControl +GetScriptDescriptors(in targetControl : Control) : IEnumerable<ScriptDescriptor +GetScriptReferences() : IEnumerable<ScriptReference> Figure 9.9 Methods defined in the IExtenderControl interface 312 CHAPTER 9 Building Ajax-enabled controls Interestingly, both methods defined in the interface return an IEnumerable type. When you implement the method or override it in a derived class, you can return an array or a list or (if you’re using C# 2.0) implement an iterator to return the lists of script descriptors and script references. NOTE Iterators are a feature introduced in C# 2.0 to support foreach iteration in a class or a struct without the need to implement the entire IEnumer- able interface. If you want to know more about C# iterators, browse to http://msdn2.microsoft.com/en-us/library/65zzykke.aspx. Even if your main job is to override the methods defined in the IExtenderCon- trol interface, it’s important to know how the registration procedure is particu- larized for an extender. In the following section, we’ll look at how an extender is registered with the ScriptManager control. 9.3.2 Extender registration The process of registering with the ScriptManager lets the extender be recog- nized as an Ajax-enabled control. It’s a two-step process: 1 During the PreRender stage, you call RegisterExtenderControl method, passing the extender instance and the extended control as arguments. 2 During the Render stage, you call the RegisterScriptDescriptors method to register the script descriptors. As shown in figure 9.10, the first part of the registration procedure involves calling the RegisterExtenderControl method on the ScriptManager control (event 2). This method receives the current extender instance and the extended control as arguments. The registration procedure is completed during the Render phase, where you call the RegisterScriptDescriptors method on the ScriptManager, passing the current extender instance as an argument (event 4). Luckily, the ExtenderControl class takes care of performing the registration procedure automatically on your behalf. Because you always create a new extender by deriving from the ExtenderControl class, you don’t need to worry about the implementation details. However, when we discuss script controls, you’ll discover that in some situations you need to manually register the Ajax- enabled control with the ScriptManager. For this reason, we’ll postpone a deeper examination of the registration procedure until section 9.4. Extenders 313 In general, the design of an extender follows three phases: 1 Build a client component—either a behavior or a control—that encapsu- lates the client functionality you intend to provide to a server control. 2 The real development of the extender starts. Determine which properties of the client component you want to configure on the server side. You can map them to a group of server properties and perform the configuration of the client component through the extender. 3 Build the extender class, which provides the lists of script references and script descriptors to the ScriptManager control. Let’s apply this design strategy to a concrete example. In the following section, you’ll create an extender for the FormattingBehavior behavior you built in chap- ter 8. This will let you wire the behavior to an ASP.NET TextBox and configure it on the server side. 9.3.3 An extender for FormattingBehavior In chapter 8, we demonstrated how to enrich a text box element by simulating in- place edit functionality with the help of a client behavior. Now that you’ve imple- mented this client component, it would be great if you could wire it to TextBox Page ScriptManager Extender 1. PreRender 3. Render 5. Get Script Descriptors 6. Get Script References 7. Render Scripts 2. RegisterExtenderControl(this, targetControl); 4. RegisterScriptDescriptors(this); Figure 9.10 An extender must be registered with the ScriptManager control during the PreRender and Render phases of the server page lifecycle. 314 CHAPTER 9 Building Ajax-enabled controls controls in different web applications. If your intention is to not write one more line of JavaScript code or change any web controls declared in a form, building an extender is the right path. If you have the code for the FormattingBehavior class stored in a JavaScript file you’ve completed the first phase of the design strategy and can move to the second phase. Mapping client properties to server properties Once the client functionality is encapsulated in a client component, you need to filter the client properties you want to configure on the server side. The goal is to create corresponding properties in the extender class and use them to set the value of the client properties. How is this possible? By using a script descriptor. Recall from chapter 8 that the FormattingBehavior class exposes two proper- ties called hoverCssClass and focusCssClass . They hold the names of the CSS classes used by the client behavior. To set their values from the server side, you need to expose corresponding properties in the extender. In preparation, it’s use- ful to draw a table that shows the mapping between properties of the client com- ponent and properties of the extender; see table 9.1. Once you’ve drawn the table, you’re ready to move to the third and final, where you’ll create the extender class and implement the server-side logic. Creating the extender An extender is a class that inherits from the base System.Web.UI.ExtenderCon- trol class. Usually, an extender includes a group of server properties and the over- rides of the methods defined in the IExtenderControl interface. Other than these, an extender shouldn’t perform any tasks. Because the purpose of an extender is to provide script descriptors and script references, all the other logic added to the extender should relate to the configuration of the associated client component. Let’s return to the example. The extender class is called FormattingExtender , and its code is shown in listing 9.3. Table 9.1 Mappings between client properties and extender properties Client property Extender property hoverCssClass HoverCssClass focusCssClass FocusCssClass Extenders 315 using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; [TargetControlType(typeof(TextBox))] public class FormattingExtender : ExtenderControl { public string HoverCssClass { get { return (string)ViewState["HoverCssClass"]; } set { ViewState["HoverCssClass"] = value; } } public string FocusCssClass { get { return (string)ViewState["FocusCssClass"]; } set { ViewState["FocusCssClass"] = value; } } public string ScriptPath { get { return (string)ViewState["ScriptPath"]; } set { ViewState["ScriptPath"] = value; } } protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl) { ScriptBehaviorDescriptor desc = new ScriptBehaviorDescriptor("Samples.FormattingBehavior", targetControl.ClientID); desc.AddProperty("hoverCssClass", this.HoverCssClass); desc.AddProperty("focusCssClass", this.FocusCssClass); yield return desc; } protected override IEnumerable<ScriptReference> GetScriptReferences()| { yield return new ScriptReference(Page.ResolveClientUrl(this.ScriptPath)); } } Listing 9.3 Code for the FormattingExtender class Properties B IExtenderControl methods C 316 CHAPTER 9 Building Ajax-enabled controls Above the class declaration is a TargetControlType attribute. Its goal is to put a constraint on the types of server controls that the extender can extend. Because you pass typeof(TextBox) as an argument to the attribute, only TextBox controls can be extended by the FormattingExtender . Associating the extender with a web control other than a TextBox will cause a server exception to be thrown by ASP.NET. If you pass typeof(Control) , all the controls can be extended, although it doesn’t make much sense given the kind of client functionality that, in this example, you’ll add to the target control. The FormattingExtender class exposes a ScriptPath property B that isn’t listed in table 9.1. This property specifies the location of the JavaScript file that contains the code of the FormattingBehavior behavior. The property isn’t listed in the table because it’s not exposed by the client component. You’ll need it when you create the ScriptReference instance that you return to the ScriptManager , so it makes sense to have it in the extender control. The other two properties are those shown in table 9.1. The HoverCssClass property stores the value assigned to the hoverCssClass property of the client behavior. The same is true for the FocusCssClass property. Note that you store and retrieve all the values from the ViewState of the extender control. For the first time, you can see how the methods C defined in the IEx- tenderControl interface are overridden in the extender control. As expected, the GetScriptDescriptors method returns a script descriptor for the Format- tingBehavior behavior. In the override, the script descriptor uses the values of the server HoverCssClass and FocusCssClass properties to build a $create statement that contains values for the client hoverCssClass and focusCssClass properties. Finally, the GetScriptReferences method returns a ScriptRefer- ence instance with the information needed to load the right JavaScript file in the page. The location of the file is configured through the ScriptPath property. NOTE Listing 9.3 uses the yield return construct in both the GetScriptRef- erences and GetScriptDescriptors methods. You use the yield key- word when implementing a C# iterator, to signal the end of an iteration. Without much effort, you’ve built your first extender. But we’ve left some things unsaid: For example, how do you wire an extender to an ASP.NET control? The next section will teach you how to declare and configure extenders. 9.3.4 Using an extender An extender is nothing more than a custom ASP.NET server control. The Extender- Control class derives from the base Control class; an extender is registered and Extenders 317 declared in an ASP.NET page like any other server control. Figure 9.11 shows how the files are organized in the sample ASP.NET AJAX- enabled website that you can download at http://www.manning.com/gallo. As you can see, the extender class is con- tained in the App_Code directory. The file with the code for the client behavior, Format- tingBehavior.js, is located in the ScriptLi- brary folder. Another possible configuration has both the server class and the JavaScript file stored in a separate assembly; we’ll cover this scenario in section 9.4, but the same rules apply to extenders. To use the extender in an ASP.NET page, all you have to do is register the namespace that contains the FormattingExtender class in the page that will use it: <%@ Register Namespace="Samples" TagPrefix="samples" %> Now, you have to wire the extender to its target control. The code in listing 9.4 shows a simple ASP.NET TextBox with an associated FormattingExtender control. <% Extended Control %> <asp:TextBox ID="txtName" runat="server"></asp:TextBox> <% Extender %> <samples:FormattingExtender ID="FormattingExtender1" runat="server" TargetControlID="txtName" HoverCssClass="hover" FocusCssClass="focus" ScriptPath="~/ScriptLibrary/FormattingBehavior.js" /> All the magic of extenders happens when you set the extender control’s Target- ControlID property to the ID of the target control. In listing 9.4, you extend the TextBox by assigning its ID to the TargetControlID property of the Format- tingExtender control. The remaining properties of the extender are used to con- figure the CSS classes used by the client behavior. The ScriptPath property contains the path to the FormattingBehavior.js file. NOTE The TargetControlID property is the main property exposed by an extender. You always set this property, because it identifies the server control that’s wired to the extender. Listing 9.4 How to extend an ASP.NET web control declaratively Figure 9.11 The extender class and the JavaScript file with the code for the client component can be hosted in an ASP.NET AJAX-enabled website. 318 CHAPTER 9 Building Ajax-enabled controls An extender can also be instantiated programmatically, as shown in listing 9.5. The extender must be always added to the same container as the target control; if the target control is declared in an UpdatePanel, the extender must be declared in the panel. If the target control is declared in the form tag, then the extender must be added to the Page.Form.Controls collection. FormattingExtender ext = new FormattingExtender(); ext.ID = "FormattingExtender1"; ext.TargetControlID = txtName.ID; ext.HoverCssClass = "hover"; ext.FocusCssClass = "focus"; ext.ScriptPath = " ~/ScriptLibrary/FormattingBehavior.js"; Page.Form.Controls.Add(ext); To complete our discussion, let’s run the ASP.NET page and look at the source code sent to the browser. After a bit of scrolling, you can find the script file required by the FormattingExtender control: <script src="FormattingBehavior.js" type="text/javascript"></script> After more scrolling, you see the $create statement generated by the script descriptor that the FormattingExtender returned to the ScriptManager control: Sys.Application.add_init(function() { $create(Samples.FormattingBehavior, {"focusCssClass":"focus","hoverCssClass":"hover"}, null, null, $get("txtLastName")); }); Note how the $create statement is correctly injected into a JavaScript function that handles the init event raised by Sys.Application . So far, so good; every- thing went as expected. Keep in mind that an extender is used to wire a client component to an existing server control. The extender provides the necessary script references and script descriptors to the ScriptManager control. It does so by overriding the methods defined in the IScriptControl interface. An extender control can also expose properties to enable the configuration of the properties exposed by the client com- ponent. Now, we’re ready to explore the second category of Ajax-enabled controls: script controls. Listing 9.5 Extending an ASP.NET web control programmatically [...]... {"LoginButton":$get("AjaxLogin1_LoginButton"), "Password":$get("AjaxLogin1_Password"), "RememberMe":$get("AjaxLogin1_RememberMe"), "UserName":$get("AjaxLogin1_UserName")}, null, null, $get("AjaxLogin1")); }); 330 CHAPTER 9 Building Ajax- enabled controls Figure 9.15 The AjaxLogin control running in the Opera browser As expected, the script tag contains the URL of the AjaxLogin.js file embedded as a web resource in the ScriptControls assembly... be loaded in a web page The AjaxLogin.js file—empty at the moment—will contain the client AjaxLogin control that adds Ajax capabilities to the server Login control To complete the Figure 9.14 Structure of the project layout, add a new class file called ScriptControls project AjaxLogin.cs to obtain the structure shown in figure 9.14 Creating the AjaxLogin client control The client AjaxLogin control... Login control and performs the authentication using an Ajax request Finally, you’ll create a script control that extends the existing Login control and instantiates the client control in the page Let’s start by setting up the project for the new AjaxLogin control Earlier, we explained how to embed the code files in an ASP.NET AJAX- enabled website This time, we’ll explain how to embed the files in a... it to the AjaxLogin.js file created in the project 324 CHAPTER 9 Building Ajax- enabled controls Listing 9.8 Code for the AjaxLogin client class Type.registerNamespace("Samples"); Samples.AjaxLogin = function(element) { Samples.AjaxLogin.initializeBase(this, [element]); this._userName = null; this._password = null; this._rememberMe = null; this._loginButton = null; B Fields } Samples.AjaxLogin.prototype... script control you’ll build derives from the Login class and implements the IScriptControl interface You need to override the methods of the IScriptControl interface as well as implement the registration procedure You do so in the code for the AjaxLogin class, shown in listing 9.9 Listing 9.9 Code for the AjaxLogin server class using using using using using System; System.Collections.Generic; System.Web;... that in order to upgrade the Login control to a script control, you should derive from the Login class and implement the IScriptControl interface That’s what you’ll do in the next section 9.4.4 Adding Ajax to the ASP.NET Login control Trying to put the ASP.NET Login control in an UpdatePanel reveals a sad truth: The control suddenly stops working, and your dreams of performing user authentication in. .. Page.ClientScript.GetWebResourceUrl(typeof(AjaxLogin), "ScriptControls.AjaxLogin.js")); Reference } E } web resource } The WebResource attribute B that decorates the AjaxLogin class is used to register the AjaxLogin.js file as a web resource This is necessary in order to be able to reference the script file in a web page The first method declared in the AjaxLogin class C is a helper method that can find child controls declared in the... methods defined in the IScriptControl interface are embedded in the control rather than in a different object In some situations, you’ll want to turn an existing control into a script control In such a case, you have to derive a class from the existing server control and manually implement the IScriptControl interface The following sections will introduce the IScriptControl interface and provide some insights... without writing a single line of JavaScript code (Behaviors and other kinds of client components were covered in detail in chapter 8.) The following example will guide you in setting up a web page with an autocomplete text box similar to the one shown in figure 10.2 This web page should be part of an ASP.NET AJAX enabled website, which is a website configured for ASP.NET AJAX Appendix A contains a tutorial... provided by ASP.NET AJAX In the next section, we’ll explain how to use the Ajax Control Toolkit as a platform for building extenders and script controls Let’s see what’s under the hood of the Ajax Control Toolkit API The Ajax Control Toolkit API 343 10.2 The Ajax Control Toolkit API As you learned in chapter 9, the ASP.NET AJAX framework provides base classes and interfaces for creating Ajax- enabled . 9.4.4 Adding Ajax to the ASP. NET Login control Trying to put the ASP. NET Login control in an UpdatePanel reveals a sad truth: The control suddenly stops working, and your dreams of performing user. IEnumerable<ScriptReference> Figure 9.9 Methods defined in the IExtenderControl interface 312 CHAPTER 9 Building Ajax- enabled controls Interestingly, both methods defined in the interface return an IEnumerable . setting up the project for the new AjaxLogin control. Earlier, we explained how to embed the code files in an ASP. NET AJAX- enabled website. This time, we’ll explain how to embed the files in