For additional examples of ASP.NET AJAX server controls and extenders, we recommend downloading and reviewing the ASP.NET AJAX Control Toolkit available at http://asp.net/ajax/ajaxcontro
Trang 1properties: [ {name: 'highlightCssClass', type: String},
{name: 'nohighlightCssClass', type: String} ]
}
// Register the class as a type that inherits from Sys.UI.Control
ControlsBook2Lib.Ch09.HighlightedHyperlink.registerClass('ControlsBook2Lib.Ch09
HighlightedHyperlink', Sys.UI.Control);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Notice that the HighlightedHyperlink client-side component doesn’t need to know the CSS class names in advance The client-side component also contains an optional descriptor
for JSON serialization support Figure 9-1 shows HighlightedHyperLink ASP.NET AJAX-enabled
server control in action in the HighlightedHyperLink web form
Trang 2Figure 9-1 The rendered HighlightedHyperLink web form in Firefox
The source code for the HighlightedHyperLink web form and code-behind file is shown in Listings 9-13 and 9-14
Listing 9-13 The HighlightedHyperLink Web Form aspx Page File
color: navy;
font-weight: bolder;
} .NoHighlight {
color: Green;
font-weight: lighter;
} </style>
</asp:Content>
Trang 3<asp:Content ID="Content2" ContentPlaceHolderID="ChapterNumAndTitle" runat="server">
<asp:Label ID="ChapterNumberLabel" runat="server
Width="14px">9</asp:Label> <asp:Label
ID="ChapterTitleLabel" runat="server" Width="360px">
ASP.NET AJAX Controls and Extenders</asp:Label>
Trang 4In this chapter, we provided an overview of ASP.NET AJAX, both the server-side and client-side functionality ASP.NET AJAX includes a powerful client-side script library that provides cross-browser compatibility, as well as a powerful client-side programming model that mimics object-oriented behavior in JavaScript
We covered the server-side programming model that requires implementation of the GetScriptDescriptors and GetScriptReferences methods We also explained how the server-side configuration is passed to the client-side component utilizing the ScriptBehaviorDescriptor class Finally, we demonstrated how to implement both an ASP.NET AJAX server control by implementing IScriptControl, as well as how to implement an extender control by inheriting from the ExtenderControl base class
For additional examples of ASP.NET AJAX server controls and extenders, we recommend downloading and reviewing the ASP.NET AJAX Control Toolkit available at http://asp.net/ajax/ajaxcontroltoolkit/samples/
Trang 5■ ■ ■
C H A P T E R 1 0
Other Server Controls
Up to this chapter, we have focused on providing the necessary background to create powerful
ASP.NET server controls that support custom styling, templating, data binding, client-side
script, and ASP.NET AJAX These development techniques and features can be put to work in
many different ways In this part of the book, we begin to move on to advanced topics such web
part development and design-time support
In this chapter, we begin our advanced topic journey by covering web part development and adaptive control programming We will start off with a discussion on building web parts
for both ASP.NET and Microsoft Office SharePoint Server 2007 Next, we will focus on adaptive
control development, including the mobile controls for devices In the next section, we begin
our journey with web parts
■ Note For information on building custom validator controls, the MSDN documentation contains a nice set of
cross-browser validator control samples that also comply with the WWW Consortium DOM Level 1 specification; the
samples are located here: http://msdn2.microsoft.com/en-us/library/aa719624(VS.71).aspx
Web-Part-Based Web Site Development
This chapter won’t attempt to provide a complete overview of the web part infrastructure and
development model available in ASP.NET, because the documentation does a very good job of
explaining what functionality is available What I will do is provide a discussion on various web
part topics encountered while building out the example web parts in this chapter to help you
understand the moving parts available when building web parts If you find that you need
more background information on a particular area, here is the top-level link to the ASP.NET
web parts documentation at MSDN Online:
http://msdn2.microsoft.com/en-us/library/e0s9t4ck(VS.90).aspx
From the preceding link, you can navigate to these sections for more detail on a ular topic:
partic-• ASP.NET Web Parts Overview
• Web Parts Control Set Overview
Trang 6• Web Parts Page Display Modes
• Web Parts Personalization
• Web Parts Connections OverviewFor an idea of what’s possible, look no further than Microsoft Office SharePoint Server (MOSS) 2007, which is built on top of ASP.NET and the web part infrastructure A public-facing Internet site built on top of MOSS with custom web parts is http://www.glu.com Here is a link
to the first of a three-part series on how this site was built by Allin Consulting on MOSS and ASP.NET web parts:
http://blogs.msdn.com/sharepoint/archive/2007/06/14/
moss-has-got-game-glu-mobile-s-website-www-glu-com-how-we-did-it-part-1-of-3.aspxWith that background out of the way, we’ll dive into a discussion on web part development
in the next section
Web Part Development
Web parts have existed in SharePoint for many years Initially, the web part development model was based on VBScript, which is not what most developers would call their favorite development language or environment In SharePoint Server 2003, Microsoft more closely integrated SharePoint with ASP.NET, providing namespaces for supporting web part develop-ment in NET With NET Framework 2.0, the ASP.NET team integrated the web part infrastructure and development model within ASP.NET itself However, the two web part models remained separate Building web parts that targeted both ASP.NET 2.0 and SharePoint Server 2003 required custom compilation, since different namespaces and base classes where required In Microsoft Office SharePoint Server (MOSS) 2007, SharePoint is completely integrated with and built on ASP.NET 2.0 This means that you can build web parts for MOSS using the ASP.NET WebPart base class
■ Note Microsoft recommends inheriting from the ASP.NET WebPart base class whether developing for pure ASP.NET or SharePoint
The next section provides a brief overview of the ASP.NET web part infrastructure to set the state for building web parts that take advantage of this framework
Web Part Infrastructure
One of the features of WebPart-based applications is personalization WebParts can have attributes configured with the PersonalizableAttribute so that a user can create a unique view on the page Personalization for an ASP.NET web site requires that the SQL personalization provider
is configured for the site
Trang 7■ Note Personalization requires that the <trust level="" /> element is configured for Medium in order
to access members in the SqlClient namespace
The SqlPersonalizationProvider class is used to configure the personalization in SQL Server
The ASP.NET SQL Server Registration Tool (Aspnet_regsql.exe) can be used to set up the database location for web part personalization, among other databases such as the ASP.NET
membership database The tool is located at \%windir%\Microsoft.NET\Framework\v2.0.50727,
or at the same location for a later version of the framework
There is a section in the web.config file to declaratively configure web part personalization via the WebPartsPersonalization class under <system.web> <WebParts> <personalization > that
can be used to configure the web part environment Refer to the MSDN documentation for
more information on the WebPartsPersonalization class
Web parts are hosted within the rich web part infrastructure, so as you would expect, there are additional customizations available for web part developers Table 10-1 provides a list of
the most common overrides when creating a WebPart server control
With that background out of the way, let’s move on to creating web parts in the next section
Creating Web Parts
In this section, we create two server controls and demonstrate them in a basic ASPX page Next,
we convert the server controls to web parts and then demonstrate them in a web part portal page
Table 10-1 WebPart Common Overrides
WebPart Member Overview
"Allow" properties These are behavior-focused properties that control developers
may want to manage for the logic of their custom WebPart control
Examples are AllowClose, AllowConnect, and AllowEdit
CreateChildControls It is quite common to build web parts based on composite server
controls to encapsulate chunks of functionality as a WebPart control
CreateEditorParts Web parts can have custom editor web parts based on EditorPart
to enable users to edit custom web part properties Override CreateEditorParts to incorporate the custom EditorPart control
PersonalizableAttribute This attribute is applied to properties of the custom web part that
the user may want to save unique settings to
Rendering methods As with custom server controls, sometimes you may need to
override Render or RenderContents to completely change the outputted HTML or to simply customize it by also calling the base method
Verbs Add custom WebPartVerb objects to the Verbs collection to allow
custom menu actions to appear along with the standard verbs such as close or minimize
Trang 8This may seem like the long road to building web parts, but we believe it is more realistic
In many situations, developers will create server controls and statically code the page layout and what server controls appear on a page as part of an application Initially, there are perhaps just a couple of server controls, but after a couple of cycles where users ask for additional func-tionality or views on data, developers may find themselves with a library of server controls with different users requesting multiple combinations of server controls, resulting in multiple, hand-coded, statically linked and created web forms At this point, the developer may ask, “Why not create a web part portal page where users can pick which controls display on the page, how the controls are laid out, and which controls are linked?”
Regarding what type of scenario may fit this model, a reporting web portal or business intelligence application comes to mind, so our focus for this demonstration is providing a reporting page focused on the famous Northwind database with NorthWind customers as the theme for the site
In the next section, we build the server controls web form with two server controls reporting NorthWind customer data
The Server Controls
As mentioned in the previous section, we start out by creating server control versions of the web parts and then show how to turn them into web parts in the next section The two server controls retrieve data from the NorthWind database The first server control displays a list of customers and allows editing of existing customers but not insertion or deletion The second server control takes a customer ID and displays invoice highlights for the customer based on the provided customer ID Both server controls allow sorting and paging, as well as provide a simple style to show row highlighting
If you have read this book straight through, you can probably guess that each of the two server controls detailed here is a composite control containing a GridView and a DataSource control and inheriting from CompositeControl All of those guesses would be correct Listing 10-1 contains the CustomerList custom server control
Listing 10-1 The CustomerList Server Control
[ToolboxData("<{0}:CustomerList runat=server></{0}:CustomerList>")]
public class CustomerList : CompositeControl {
private const string strSelectCmd = @"Select * from [Customers]";
private const string strUpdateCmd = @"UPDATE [Customers] SET " + @"[CompanyName] = @CompanyName, [ContactName] = @ContactName, " + @"[Phone] = @Phone WHERE [CustomerID] = @CustomerID";
Trang 9// Allow page developers to set the connection string.
public String ConnectionString
Trang 10set { ViewState["AllowCustomerEditing"] = value;
} } protected override void CreateChildControls() {
Controls.Add(ds);
Label title = new Label();
title.Text = "Customer list";
CommandField controlButton = new CommandField();
//Only show Edit button if control configured to allow it
if (AllowCustomerEditing) controlButton.ShowEditButton = true;
Trang 11grid.SelectedIndexChanged += new EventHandler(SelectedIndexChanged);
grid.PageIndexChanged += new EventHandler(PageIndexChanged);
Trang 12field.SortExpression = fieldName;
field.DataField = fieldName;
return field;
} private Parameter _createParameter(String paramName, TypeCode dataTypeCode) {
Parameter theParm = new Parameter(paramName, dataTypeCode);
return theParm;
} }}The CustomerID property is used to store the selected row’s CustomerID value from the customer list The ConnectionString is a public property for the SqlDataSource control that is part of the server control hierarchy to use to connect to the database The CustomerList server control allows editing of the customer list The AllowCustomerEditing property is used to control whether the editing is permitted for a particular instance of the control on a web form
As with all composite server controls, CreateChildControls does all of the heavy lifting to build out the server control hierarchy The controls include a Label for the title, a LiteralControl to contain a br tag, a SqlDataSource, and, of course, the GridView control
The CreateChildControls override attaches two events to the GridView control, one for the SelectedIndexChanged event and the other for the PageIndexChanged event The SelectedIndexChanged event sets the CustomerID property to the CustomerID value from the GridView The PageIndexChanged event resets the SelectedIndex to –1 so that a row is not selected after the page is changed The CustomerInvoices server control is similar to the CustomerList server control, except that it is based on a database view instead of a table and so does not allow editing Listing 10-2 shows the source code for the CustomerInvoices server control
Listing 10-2 The CustomerInvoices Server Control
Trang 13// Allow page developers to set the connection string.
public String ConnectionString
Trang 14Label title = new Label();
title.Text = "Customer Invoices - "+ CustomerID;
GridViewRow row = ((GridView)(sender)).SelectedRow;
}
Trang 15protected void PageIndexChanged(object sender, EventArgs e)
parameters for the GridView control The demonstration web form for the two server controls
is CustomerInfo.aspx The source code is shown in Listings 10-3 and 10-4
Trang 16Listing 10-3 The Customer Information Web Form aspx Page File
<%@ Page Language="C#"
MasterPageFile="~/MasterPage/ControlsBook2MasterPage.Master"
AutoEventWireup="true" CodeBehind="CustomerInfo.aspx.cs"
Inherits="ControlsBook2Web.Ch10.CustomerInfo"
Title="Customer Info Demo Web Form" %>
<%@ Register assembly="ControlsBook2Lib" namespace="ControlsBook2Lib.Ch10"
public partial class CustomerInfo : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
} }}Figure 10-1 shows how the customer information web form application appears in the browser
We could wire up these controls by bubbling up the SelectedIndexChanged event for the GridView to the CustomerList parent control as shown in Chapter 5, so that we can get the customer ID and then pass it to the CustomerInvoices control, but we want to link the controls using the web part, which we cover in the next section when we convert the server controls into web parts
Trang 17Figure 10-1 The Customer Info web form in the browser
Converting to WebPart Controls
To start the conversion, we copied the CustomerList and CustomerInvoices server control to
new class files with the same names but with the term “WebPart” appended To start, System.Web
UI.WebControls.WebParts was added to the class files, and the base control changed from
CompositeControl to WebPart
At this point, the project compiles As a test, we begin by creating the test form to see if the web parts will host in a WebPartZone control We added a page, CustomerInfoWebPart.aspx, to
the web project Next, we added WebPartZone and ZoneTemplate controls to contain the two web
parts A required step is to add a WebPartManager control to the page to enable web part
function-ality Figure 10-2 shows the results of this minimalist effort
Trang 18Figure 10-2 The Customer Info web part basic web form in the browser
The web form renders with the additional chrome of the web parts around the controls, including the basic web part menu containing just the Minimize and Close commands, but this version of the web page is not much different from the server control version We next discuss how to enable different web part modes, such as design
Trang 19The WebPartPageController Server Control
Part of the allure of web forms with web parts is the ability to provide to end users design-time
functionality normally in the hands of developers The WebPartPageController server control
provides a menu to do this by plugging into the web part page functionality One example
behavior is the ability to move the location of web parts by entering design mode for the page
Once finished designing the page, the end user can choose browse mode in the drop-down
menu The WebPartPageController control also allows the user to choose whether to save
personalization data at the User or Shared scope One consideration would be to apply role
checking on this setting if only certain users should be able to select the Shared scope Figure 10-3
shows WebpartPageController in action
Figure 10-3 WebpartPageController in the browser
Figure 10-4 shows the form in design mode with the mouse dragging CustomerInvoicesWebPart to the top of the web part zone within the browser
Trang 20Figure 10-4 The Customer Info web part web form in design mode
What is handy about this server control is that just by dropping it on to the web-part-enabled web form, you get immediate customization functionality Listing 10-5 provides the source code for the WebPartController server control
Listing 10-5 The WebPartPageController Server Control
Trang 21"Sets the text on the caption for the web part state dropdown.")]
public string DisplayModeText
"Configures the text on the link button to reset state.")]
public string ResetStateText
Trang 22else return (string)resetStateText;
} set { ViewState["ResetStateText"] = value;
} } [Bindable(true), Category("Appearance"), Localizable(true), DefaultValue("Reset the current user's personalization data for the page."), Description("Configures the tooltip for the link button to reset state.")] public string ResetStateToolTip
{ get { object resetStateToolTip = ViewState["ResetStateToolTip"];
if (resetStateToolTip == null) return string.Empty;
else return (string)resetStateToolTip;
} set { ViewState["ResetStateToolTip"] = value;
} } #endregion #region Overrides protected override void OnInit(EventArgs e) {
base.OnInit(e);
_currentWebPartManager = WebPartManager.GetCurrentWebPartManager(Page);
} protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
String browseModeName = WebPartManager.BrowseDisplayMode.Name;
Trang 23//Reset items collection on dropdown
displayModeDropDown.Items.Clear();
// Fill the DropDown with the names of supported display modes
foreach (WebPartDisplayMode mode
in _currentWebPartManager.SupportedDisplayModes)
{
String modeName = mode.Name;
// Make sure a mode is enabled before adding it
// If shared scope is allowed for this user, display the scope-switching
// UI and select the appropriate radio button for the current user scope
Trang 24get { return base.Height;
} set { EnsureChildControls();
Unit min = new Unit(87);
if (value.Value > min.Value) base.Height = value;
else base.Height = min;
} } public override Unit Width {
get { return base.Width;
} set { EnsureChildControls();
Unit min = new Unit(167);
if (value.Value >= min.Value) base.Width = value;
else base.Width = min;
} } protected override void CreateChildControls() {
Controls.Clear();
CreateChildControlHierarchy();
} #endregion private void CreateChildControlHierarchy() {
Panel rootPanel = new Panel {
ID = "rootPanel", BorderWidth = 1, BackColor = this.BackColor,
Trang 25resetUserState.Click += new EventHandler(resetUserState_Click);
HtmlGenericControl div2 = new HtmlGenericControl("div");
Trang 26Width = 165 };
};
sharedRB.CheckedChanged += new EventHandler(sharedRB_CheckedChanged); personalizationScopePanel.Controls.Add(sharedRB);
} #region Control Events void sharedRB_CheckedChanged(object sender, EventArgs e) {
if (_currentWebPartManager.Personalization.CanEnterSharedScope && _currentWebPartManager.Personalization.Scope
== PersonalizationScope.User) _currentWebPartManager.Personalization.ToggleScope();
} void userRB_CheckedChanged(object sender, EventArgs e) {
if (_currentWebPartManager.Personalization.Scope == PersonalizationScope.Shared)
_currentWebPartManager.Personalization.ToggleScope();
} void resetUserState_Click(object sender, EventArgs e) {
_currentWebPartManager.Personalization.ResetPersonalizationState(); }
Trang 27void displayModeDropDown_SelectedIndexChanged(object sender, EventArgs e)
Now that we have good control over the web part page functionality, we next take care of
a little bit of code cleanup to make the web parts look better before moving on to discuss how
to enable connections between web parts
Connecting Web Parts
In the previous sections, we created server controls and then converted them to web parts We
also added a handy web page controller web part to expose web part page functionality to end
users In the server control versions of the web parts, we added a border and a label to contain
a title for the control If you view the screen shots in Figures 10-1 to 10-4, you see that the
CustomerListWebPart control has the title set to Customer List, resulting in the phrase “Customer
List” appearing twice The CustomerInvoicesWebPart has a title of Untitled Web parts include
their own border and title functionality, so we first need to remove the blue border
function-ality from the server controls Next, we’ll start the work on connecting the web parts
First, we create an interface for passing the customer ID from the CustomerListWebPart to the CustomerInvoicesWebPart called ICustomerID We add the [Personalizable()] attribute
to the CustomerID property on the CustomerListWebPart control so that the value of CustomerID
is saved as part of the persistence service and will be available the next time the page is loaded
Next, we add a new method to the CustomerListWebPart called ProvideICustomerID that returns an ICustomerID object The new method is decorated with the ConnectionProvider
attribute so that the web part infrastructure is aware of how to connect this web part
For the CustomerInvoicesWebPart, we add a private variable called customerIDProvider
of type ICustomerID to hold a reference We also add a GetICustomerID method that takes a
parameter of type ICustomerID and assigns it to the private variable customerIDProvider Finally,
we override OnPreRender for the CustomerInvoicesWebPart so that the CustomerID can be retrieved
from the provider and set on the CustomerInvoicesWebPart’s CustomerID property
Wiring Up the Page
To allow connections between the web parts, we first add a ConnectionZone web control to the
CustomerInfoWebPart.aspx markup and add verbs such as connect, configure, disconnect, and
so on to the ConnectionZone control We also override OnPreRender in CustomerInfoWebPart
aspx.cs and set properties for the connection verbs and UI to customize the connection
func-tionality This completes the work necessary to wire up our server controls and link them the
web-part way
Trang 28To test this functionality, run the page, and select the new Connect option that appears
as a Display mode This menu item is available because the WebPartPageController server control dynamically reads what modes are supported by the WebPartManager control on the page Figure 10-5 shows the web form in Connect mode
Figure 10-5 The Customer Info Web Part web form in Connect mode
After clicking Connect as shown in Figure 10-5, Figure 10-6 shows a screen shot of the Create and Manage Connections functionality, as well as the Close Zone button to cancel out creating a connection
Trang 29Figure 10-6 The Create and Manage Connections UI without any connections
Figure 10-7 shows the UI after clicking the “Select a consumer” link with the CustomerInvoices web part selected for the To value
Figure 10-7 The Create and Manage Connections UI after connecting the web parts
After clicking the Connect Controls button and selecting Browse mode in WebPartPageController, the controls are now linked Selecting a row in the CustomerList web
part filters the CustomerInvoices web part to invoices for the selected customer based on the
CustomerID passed via the web part connection, as shown in Figure 10-8 where CustomerID
BLAUS is selected and the customer’s invoices display below in the CustomerInvoices web part
Trang 30Figure 10-8 Linked web parts
This concludes our web part walkthrough The final web part source code for the CustomerListWebPart and CustomerInvoicesWebPart web parts as well as the final CustomerInfoWebPart web form are provided in Listings 10-6, 10-7, 10-8, and 10-9 respectively
Listing 10-6 The CustomerListWebPart Server Control
[ToolboxData("<{0}:CustomerListWebPart runat=server></{0}:CustomerListWebPart>")]
Trang 31public class CustomerListWebPart : WebPart, ICustomerID
{
private const string strSelectCmd = @"Select * from [Customers]";
private const string strUpdateCmd = @"UPDATE [Customers] SET " +
@"[CompanyName] = @CompanyName, [ContactName] = @ContactName, " +
@"[Phone] = @Phone WHERE [CustomerID] = @CustomerID";
//This callback method returns the provider
[ConnectionProvider("CustomerID Provider", "CustomerIDProvider")]
public ICustomerID ProvideICustomerID()
{
return this;
}
// Allow page developers to set the connection string
public String ConnectionString
Trang 32set { ViewState["ConnectionString"] = value;
} } public Boolean AllowCustomerEditing {
get { object allowEditing = ViewState["AllowCustomerEditing"];
if (allowEditing == null) return false;
else return (Boolean)allowEditing;
} set { ViewState["AllowCustomerEditing"] = value;
} } protected override void CreateChildControls() {
Trang 33grid.DataSourceID = "dsCustomers";
CommandField controlButton = new CommandField();
//Only show Edit button if control configured to allow it
grid.SelectedIndexChanged += new EventHandler(SelectedIndexChanged);
grid.PageIndexChanged += new EventHandler(PageIndexChanged);
Trang 34case "CustomerID": field.HeaderText = "Customer ID";
break;
default: field.HeaderText = fieldName; break;
} field.SortExpression = fieldName;
field.DataField = fieldName;
return field;
} private Parameter _createParameter(String paramName, TypeCode dataTypeCode) {
Parameter theParm = new Parameter(paramName, dataTypeCode);
return theParm;
} }}
Listing 10-7 The CustomerListWebPart Server Control
[ToolboxData("<{0}:CustomerInvoicesWebPart runat=server></{0}:CustomerInvoicesWebPart>")]
public class CustomerInvoicesWebPart : WebPart {
private const string strSelectCmd = @"Select * from [Invoices] where " + "CustomerID = '{0}'";
private ICustomerID _customerIDProvider;
public CustomerInvoicesWebPart() {
} public String CustomerID {
get { object customerID = ViewState["CustomerID"];
if (customerID == null) return String.Empty;
Trang 35//The ConnectionConsumer attribute identifies
//this method as the mechanism for connecting with
// the provider
[ConnectionConsumer("CustomerID Consumer", "CustomerIDConsumer")]
public void GetICustomerID(ICustomerID Provider)
// Allow page developers to set the connection string
public String ConnectionString
Trang 36protected override void CreateChildControls() {
GridViewRow row = ((GridView)(sender)).SelectedRow;
} protected void PageIndexChanged(object sender, EventArgs e) {
((GridView)(sender)).SelectedIndex = -1;
}
Trang 37private BoundField _createBoundField(String fieldName)
Listing 10-8 The Customer Information Web Part Web Form aspx Page File
<%@ Page Language="C#" MasterPageFile="~/MasterPage/ControlsBook2MasterPage.Master"
AutoEventWireup="true"
CodeBehind="CustomerInfoWebPart.aspx.cs"
Inherits="ControlsBook2Web.Ch10.CustomerInfoWebPart"
Title="Customer Info Web Part Demo Web Form" %>
<%@ Register TagPrefix="apress" Namespace="ControlsBook2Lib.Ch10"
Assembly="ControlsBook2Lib" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadSection" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ChapterNumAndTitle" runat="server">
<asp:Label ID="ChapterNumberLabel" runat="server"
Width="14px">10</asp:Label> <asp:Label
ID="ChapterTitleLabel" runat="server" Width="360px">Other Server Controls
</asp:Label>
Trang 38"Reset the current user's personalization data for the page."
Height="87px" Width="167px" BackColor="Silver" ForeColor="White" /> <asp:webpartzone id="WebPartZone1" runat="server" BorderColor="#CCCCCC"
Font-Names="Verdana" Padding="6" >
<EmptyZoneTextStyle Font-Size="0.8em" />
<PartStyle Font-Size="0.8em" ForeColor="#333333" />
<TitleBarVerbStyle Font-Size="0.6em" Font-Underline="False" ForeColor="White" /> <MenuLabelHoverStyle ForeColor="#E2DED6" />
<MenuPopupStyle BackColor="#5D7B9D" BorderColor="#CCCCCC" BorderWidth="1px" Font-Names="Verdana" Font-Size="0.6em" />
<MenuVerbStyle BorderColor="#5D7B9D" BorderStyle="Solid" BorderWidth="1px" ForeColor="White" />
<PartTitleStyle BackColor="#5D7B9D" Font-Bold="True" Font-Size="0.8em"
ConnectionString = "<%$ ConnectionStrings:NorthWindDB %>"
Title="Customer Invoices"/>
</zonetemplate>
<MenuVerbHoverStyle BackColor="#F7F6F3" BorderColor="#CCCCCC"
BorderStyle="Solid" BorderWidth="1px" ForeColor="#333333" />
<PartChromeStyle BackColor="#F7F6F3" BorderColor="#E2DED6" Font-Names="Verdana" ForeColor="White" />
<HeaderStyle Font-Size="0.7em" ForeColor="#CCCCCC" HorizontalAlign="Center" /> <MenuLabelStyle ForeColor="White" />
<connectverb text="Connect Controls" />
<disconnectverb text="End Connection" />