Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro ASP.NET 2.0 In CSharp 2005 (2005) [eng]

.pdf
Скачиваний:
106
Добавлен:
16.08.2013
Размер:
29.8 Mб
Скачать

968 C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

Figure 28-11. The improved design-time representation

Smart Tags

Visual Studio 2005 includes a new feature for creating a rich design-time experience—smart tags. These are the pop-up windows that appear next to a control when you click the tiny arrow in the corner.

Smart tags are similar to menus in that they have a list of items. However, these items can be commands (which are rendered like hyperlinks) or other controls such as check boxes, drop-down lists, and more. They can also include static descriptive text. In this way, a smart tag can act like a mini Properties window.

Figure 28-12 shows an example of the custom smart tag that’s created in the next example. It allows the developer to set a combination of TitledTextBox properties. It includes two text boxes that let you set the text, a See Website Information link that launches a browser for a specific URL, and some static information that indicates the control’s name.

To create this smart tag, you need the following ingredients:

A collection of DesignerActionItem objects: Each DesignerActionItem represents a single item in the smart tag.

An action list class: This class has two roles—it configures the collection of DesignerActionItem instances for the smart tag, and, when a command or change is made, it performs the corresponding operation on the linked control.

A control designer: This hooks your action list up to the control so the smart tag appears at design time.

In the following sections, you’ll build this solution piece by piece.

C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

969

Figure 28-12. A custom smart tag

The Action List

Smart tags allow a number of options. To keep it all well organized, it’s a good idea to separate your code by creating a custom class that encapsulates your action list. This custom class should derive from DesignerActionList (in the System.ComponentModel.Design namespace).

Here’s an example that creates an action list that’s intended for use with the TitledTextBox:

public class TitledTextBoxActionList : DesignerActionList { ... }

You should add a single constructor to the action list that requires the matching control type. You can then store the reference to the control in a member variable. This isn’t required, because the base ActionList class does have a Component property that provides access to your control. However, by using this approach, you gain the convenience of strongly typed access to your control.

private TitledTextBox linkedControl;

public TitledTextBoxActionList(TitledTextBox ctrl) : base(ctrl)

{

linkedControl = ctrl;

}

Before you can build the smart tag, you need to equip your action list class with the required members. For every link you want to add to the tag (via a DesignerActionMethodItem), you need to create a method. For every property you want to add (via the DesignerActionPropertyItem), you need to create a property procedure.

The smart tag in Figure 28-4 includes eight custom items: two category headers, three properties, one action link, and one piece of static text (at the bottom of the tag).

The first step is to add the properties. The get property procedure needs to retrieve the value of the property from the linked control. The set property procedure needs to apply the new value to the linked control. However, this has a catch—you can’t set the new value directly. If you do, other parts of the designer infrastructure won’t be notified about the change. Instead, you need to work through the PropertyDescriptor.SetValue() method. To make this easier, you can define a private helper method in your action list class that retrieves the PropertyDescriptor for a given property by name:

970 C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

private PropertyDescriptor GetPropertyByName(string propName)

{

PropertyDescriptor prop;

prop = TypeDescriptor.GetProperties(linkedControl)[propName];

if (null == prop)

{

throw new ArgumentException("Matching property not found.", propName);

}

else

{

return prop;

}

}

Now you can create the three properties that wrap the properties in the TitledTextBox control:

public string Text

{

get { return linkedControl.Text; }

set { GetPropertyByName("Text").SetValue(linkedControl, value); }

}

public string Title

{

get { return linkedControl.Title; }

set { GetPropertyByName("Title").SetValue(linkedControl, value); }

}

public Color BackColor

{

get { return linkedControl.BackColor; }

set { GetPropertyByName("BackColor").SetValue(linkedControl, value);

}

Note Not all properties can be edited natively in a smart tag—it all depends on the data type. If the data type has an associated UITypeEditor (for graphically editing the property) or a TypeConverter (for converting the data type to and from a string representation), editing will work. Most common data types have these ingredients, but your custom objects won’t (and as a result, all you’ll see is a read-only string generated by calling ToString() on the object). For more information, refer to the next chapter, which looks at type conversion in detail.

The next step is to build the functionality for the See Website Information link. To do this, create a method in the action list class. Here’s the code, which uses the Process class to launch the default browser:

public void LaunchSite()

{

try

{

System.Diagnostics.Process.Start("http://www.prosetech.com");

}

catch { }

}

C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

971

The DesignerActionItem Collection

The individual items in a smart tag are represented by the DesignerActionItem class. The .NET Framework provides four basic classes that derive from DesignerActionItem, as described in Table 28-3.

Table 28-3. Classes Derived from DesignerActionItem

Method

Description

DesignerActionMethodItem

This item is rendered as a link. When you click it, it triggers an

 

action by calling a method in your DesignerActionList class.

DesignerActionPropertyItem

This item is rendered as an edit control and uses logic that’s

 

similar to the Properties window. Strings are given edit boxes,

 

enumerated values become drop-down lists, and Boolean values

 

are turned into check boxes. When you change the value, the

 

underlying property is modified.

DesignerActionTextItem

This item is rendered as a static piece of text. Usually, it provides

 

additional information about the control. It’s not clickable.

DesignerActionHeaderItem

This item derives from DesignerActionTextItem. It’s a static piece

 

of text that’s styled as a heading. Using one or more header

 

items, you can divide the smart tag into separate categories and

 

group your other properties accordingly. It’s not clickable.

 

 

To create your smart tag, you need to build a DesignerActionItemCollection that combines your group of DesignerActionItem objects. Order is important in this collection, because Visual Studio will add the DesignerActionItem objects to the smart tag from top to bottom in the order they appear.

To build your action list, you override the DesignerActionList.GetSortedActionItems() method, create the DesignerActionItemCollection, add each DesignerActionItem to it, and then return the collection. Depending on the complexity of your smart tag, this may take several steps.

The first step is to create the headers that divide the smart tag into separate regions. You can then add other items to these categories. This example uses two headers:

public override DesignerActionItemCollection GetSortedActionItems()

{

// Create 8 items.

DesignerActionItemCollection items = new DesignerActionItemCollection();

// Begin by creating the headers.

items.Add(new DesignerActionHeaderItem("Appearance")); items.Add(new DesignerActionHeaderItem("Information"));

...

Next, you can add the properties. You specify the name of the property the class, followed by the name that should appear in the smart tag. The last two items include the category where the item should be placed (corresponding to one of the DesignerActionHeaderItems you just created) and a description (which appears as a tooltip when you hover over that item).

...

// Add items that wrap the properties. items.Add(new DesignerActionPropertyItem("Title",

"TextBox Title", "Appearance", "The heading for this control."));

972 C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

items.Add(new DesignerActionPropertyItem("Text", "TextBox Text", "Appearance",

"The content in the TextBox."));

items.Add(new DesignerActionPropertyItem("BackColor", "Background Color", "Appearance",

"The color shown behind the control as a background."));

...

Visual Studio connects the action item to the property in the action item class by using reflection with the property name you supply. If you add more than one property to the same category, they’re ordered based on the order in which you add them. If you add more than one category header, the categories are also ordered according to their position.

The next step is to create a DesignerActionMethodItem(), which binds a smart tag item to a method. In this case, you specify the object where the callback method is implemented, the name of the method, the name that should appear in the smart tag display, the category where it will appear, and the tooltip description. The last parameter is a Boolean value. If true, the item will be added to the context menu for the control as well as to the smart tag.

...

items.Add(new DesignerActionMethodItem(this, "LaunchSite", "See website information", "Information",

"Opens a web browser with the company site.", true));

...

Finally, you can create new DesignerActionTextItem objects with the static text you want to show and return the complete collection of items, like so:

...

items.Add(new DesignerActionTextItem( "ID: " + linkedControl.ID,

"ID"));

return items;

}

The Control Designer

Once you’ve perfected your smart tag action list, you still need to connect it to your control. You do this by creating a custom designer and overriding the ActionLists property so that it returns an instance of your custom action list class. The following control designer demonstrates this. Notice that the action list isn’t created each time ActionList is called—instead, it’s cached in a private member variable to optimize performance.

public class TitledTextBoxDesigner : ControlDesigner

{

private DesignerActionListCollection actionLists;

public override DesignerActionListCollection ActionLists

{

get

{

if (actionLists == null)

{

actionLists = new DesignerActionListCollection();

C H A P T E R 2 8 D E S I G N - T I M E S U P P O RT

973

actionLists.Add(

new TitledTextBoxActionList((TitledTextBox)Control));

}

return actionLists;

}

}

}

Summary

In this chapter, you took a tour through some of the simple and complex aspects of the .NET design-time architecture. You learned how to configure the way control properties are displayed in the Properties window and how to take charge of control serialization and parsing. For many more advanced topics, such as custom control designers, you can consult the MSDN documentation.

C H A P T E R 2 9

■ ■ ■

JavaScript

ASP.NET provides a rich server-based programming model. The postback architecture allows you to perform all your work with object-oriented programming languages on the server, which ensures that your code is secure and compatible with all browsers. However, the postback architecture has its weaknesses. Because posting back the page always includes some small but noticeable overhead, it’s impossible to react efficiently to mouse movements and key presses. Additionally, certain tasks— such as showing pop-up windows, providing a real-time status message, and communicating between frames—need browser interaction and just aren’t possible with server-side programming.

To compensate for these problems, experienced ASP.NET developers sometimes use clientside programming to supplement their server-side web-page code. This client-side script allows you to make more-responsive pages and accomplish some feats that wouldn’t otherwise be possible. Often, these considerations occur when creating custom controls that render rich user interfaces (such as pop-up menus or rollover buttons). For the greatest browser compatibility, the client-side script language of choice is JavaScript.

Note In this chapter, you’ll learn some tried-and-true techniques for integrating JavaScript with ASP.NET. You’ll also learn about a JavaScript-based feature that’s new in ASP.NET 2.0—client callbacks allow you to refresh a portion of data in a web page without triggering a full postback.

JavaScript Essentials

JavaScript is an embedded language. This means that JavaScript code is inserted directly into another document—typically, an HTML web page. The code is downloaded to the client computer and executed by the browser.

You have two ways to embed JavaScript code in a web page:

You can embed the code directly in an event attribute for an HTML element. This is the most straightforward approach for small amounts of code.

You can add a <script> tag that contains the JavaScript code. You can choose to run this code automatically when the page loads, or you can create a JavaScript function that will be called in response to a client-side event.

In many cases, you’ll use both of these techniques at the same time. For example, you might

 

define a function in a <script> block and then wire this function up to a client-side event using

 

an event attribute. ASP.NET follows this pattern when it performs automatic postbacks. The

 

__doPostBack() function defines the code needed to set the appropriate event information for

 

every control, and it’s rendered inside a <script> block. The __doPostBack() function is then

 

connected to different controls using JavaScript event attributes such as onClick.

975

976 C H A P T E R 2 9 J AVA S C R I P T

It’s important to realize that whether you use <script> blocks, event attributes, or both, you have two choices. Your first option is to add static JavaScript code to the .aspx portion of your page. Your second option is to add JavaScript code dynamically by using the methods of the Page class. This gives you the greatest flexibility, including the ability to tweak the JavaScript code on the fly and decide what you want to render at runtime. When you create custom controls, the controls render the JavaScript code they need in this way.

The followings sections explore the basic techniques for using JavaScript. You’ll learn how to use JavaScript event attributes, script blocks, and the methods of the Page class for rendering JavaScript.

Note You can also use VBScript if your web application exists on a company intranet where Internet Explorer is the standard. However, JavaScript is the only standard supported by a wide range of browsers.

JavaScript Events

JavaScript supports a rich set of client-side events, as shown in Table 29-1.

Table 29-1. Commonly Supported JavaScript Events

Event

Description

Applies To

onChange

Occurs when the user changes value in an input

select, text, text area

 

control. In text controls, this event fires after the

 

 

user changes focus to another control.

 

onClick

Occurs when the user clicks a control.

button, check box,

 

 

radio, link, area

onMouseOver

Occurs when the user moves the mouse pointer

link, area

 

over a control.

 

onMouseOut

Occurs when the user moves the mouse pointer

link, area

 

away from a control.

 

onKeyUp

Occurs when the user presses a key.

onKeyDown

Occurs when the user releases a pressed key.

onSelect

Occurs when the user selects a portion of text in

 

an input control.

text, text area text, text area text, text area

onFocus

Occurs when a control receives focus.

onBlur

Occurs when focus leaves a control.

onAbort

Occurs when the user cancels an image download.

onError

Occurs when an image can’t be downloaded

 

(probably because of an incorrect URL).

select, text, text area select, text, text area image

image

onLoad

Occurs when a new page finishes downloading.

window, location

onUnload

Occurs when a page is unloaded. (This typically

window

 

occurs after a new URL has been entered or a link

 

 

has been clicked. It fires just before the new page

 

 

is downloaded.)

 

 

 

 

C H A P T E R 2 9 J AVA S C R I P T

977

The combination of JavaScript and the HTML document model is called DHTML (Dynamic HTML). As is common in the world of the Web, not all browsers support the same level of DHTML. As a result, the events you can use, the elements you can manipulate, and the way events work vary from browser to browser. However, Table 29-1 lists the events that are usually safe to use in any browser that supports JavaScript. As usual, if you are creating a web application for a large number of users, you must perform extensive testing.

Tip You can find event compatibility tables on the Internet (see, for example, www.quirksmode.org/js/ events_compinfo.html). For a comprehensive introduction to DHTML, you can refer to the MSDN website at http://msdn.microsoft.com/workshop/author/dhtml/dhtml.asp. You can find a full JavaScript reference at http://devedge.netscape.com/library/manuals.

You can insert JavaScript code for any of the attributes listed in Table 29-1. For example, the following web page adds the onMouseOver attribute to two TextBox controls:

protected void Page_Load(object sender, System.EventArgs e)

{

TextBox1.Attributes.Add("onMouseOver", "alert('Your mouse is hovering on TextBox1.');");

TextBox2.Attributes.Add("onMouseOver", "alert('Your mouse is hovering on TextBox2.');");

}

When the user moves the mouse over the appropriate text box, the event occurs and the JavaScript alert() function is called, which shows a message box (as shown in Figure 29-1).

Figure 29-1. Responding to a JavaScript event

Note Keep in mind that ASP.NET already uses the onChange event to support the automatic postback feature. If you add the onChange attribute and set the AutoPostBack property to true, ASP.NET is intelligent enough to add both your JavaScript and the __doPostBack() function call to the attribute. Your client-side JavaScript code will be executed first, followed by the __doPostBack() function.