Pro ASP.NET 2.0 In CSharp 2005 (2005) [eng]
.pdf
1008 C H A P T E R 2 9 ■ J AVA S C R I P T
protected void Button1_Click(object sender, System.EventArgs e)
{
string url = "http://www.google.com";
string frameScript = "<script language='javascript'>" + "window.parent.content.location='" + url + "';</script>";
Page.ClientScript.RegisterStartupScript("FrameScript", frameScript);
}
Figure 29-17. Using server-side code to control frame navigation
■Tip Oddly enough, in this example the RegisterClientScriptBlock() method probably works slightly better than the RegisterStartupScript() block method. No matter how you implement this approach, you will get a slight delay before the new frame is refreshed. Because the script block doesn’t depend on any of the controls on the page, you can render it immediately after the opening <form> tag using RegisterClientScriptBlock(), rather than at the end. This ensures that the JavaScript code that triggers the navigation is executed immediately, rather than after all the other content in the page has been downloaded.
Inline Frames
One solution that combines server-side programming with framelike functionality is the <iframe> tag (which is defined as part of the HTML 4.0 standard). The <iframe> in an inline, or embedded, frame that you can position anywhere inside an HTML document. Both the main document and the embedded page are treated as complete, separate documents.
1010 C H A P T E R 2 9 ■ J AVA S C R I P T
Summary
In this chapter, you saw how a bit of carefully chosen JavaScript code can extend your ASP.NET web pages with more responsive interfaces and more dynamic effects. Along the way, you saw how to develop .NET solutions for some traditional HTML and JavaScript techniques, such as page processors, pop-up windows, rollover buttons, and frames. You also explored the new client callback feature that helps you implement seamless page updates. You can do a lot more by creatively applying a little JavaScript. For more ideas, check out some of the custom controls available at Microsoft’s http://www.asp.net community website.
C H A P T E R 3 0 ■ DY N A M I C G R A P H I C S A N D G D I + |
1013 |
■Tip It’s acceptable to have overlapping hotspots, but the hotspot that is defined first will handle the click. In the example shown in Figure 30-1, this means it makes sense to define the hotspots in this order: DVDs, Media, CDs.
Once you’ve tweaked the hotspots to perfection, you can look at the source code to find the coordinates. In the case of a circle, three details are important: the X coordinate, Y coordinate, and radius. They appear in that order in the <area> tag:
<area shape="circle" coords="272, 83, 83" ...>
This tag defines the hotspot around the DVD region. The circle’s center is at (272, 83), and the radius is 83 pixels.
When defining a rectangle, you define the top-left and bottom-right corners. The order of coordinates is left X, top Y, right X, and bottom Y. When defining a polygon, you can have as many points as you like. The browser draws a line from one point to another to create the shape. You list the X and Y coordinates for your points in pairs like this: X1, Y1, X2, Y2, X3, Y3, and so on. It’s recommended (according to the HTML standard) that you end with the same point with which you started.
Once you’ve determined your hotspots, you can add the corresponding HotSpot objects. Here’s the ImageMap for Figure 30-1, with three hotspots:
<asp:ImageMap ID="ImageMap1" runat="server" ImageUrl="~/cds.jpg"> <asp:CircleHotSpot AlternateText="DVDs"
Radius="83" X="272" Y="83" /> <asp:CircleHotSpot AlternateText="Media" Radius="83" X="217" Y="221" /> <asp:CircleHotSpot AlternateText="CDs" Radius="83" X="92" Y="173" />
</asp:ImageMap>
Rather than coding this by hand, you can select your ImageMap and click the ellipsis next to the HotSpots property in the Properties window. This opens a collection editor where you can add and modify each hotspot.
Once you’ve defined the hotspots, you can test them in a browser. When you move the mouse pointer over a hotspot, it changes into a hand. You’ll also see that the alternate text you’ve defined for the hotspot appears in a tooltip.
Handling Hotspot Clicks
The next step is to make the hotspots clickable. A hotspot can trigger one of two actions—it can navigate to a new page, or it can post back your page (and fire the ImageMap.Click event). To choose which option you prefer, simply set the ImageMap.HotSpotMode property.
■Tip When you set the ImageMap.HotSpotMode property, it applies to all hotspots. You can also override this setting for individual hotspots by setting the HotSpot.HotSpotMode property. This allows you to have some hotspots that post back the page and others that trigger page navigation.
To disable hotspots completely, use HotSpotMode.Inactive. If you use HotSpotMode.Navigate, you need to set the URL for each hotspot using the HotSpot.NavigateUrl property. If you use HotSpotMode.PostBack, you should give each hotspot a unique HotSpot.PostBackValue. This allows you to identify which hotspot triggered the postback in the Click event.
1014 C H A P T E R 3 0 ■ DY N A M I C G R A P H I C S A N D G D I +
Here’s the revised ImageMap control declaration that adds these details:
<asp:ImageMap ID="ImageMap1" runat="server" ImageUrl="~/cds.jpg" HotSpotMode="PostBack" OnClick="ImageMap1_Click"> <asp:CircleHotSpot AlternateText="DVDs" PostBackValue="DVDs"
Radius="83" X="272" Y="83" />
<asp:CircleHotSpot AlternateText="Media" PostBackValue="Media" Radius="83" X="217" Y="221" />
<asp:CircleHotSpot AlternateText="CDs" PostBackValue="CDs" Radius="83" X="92" Y="173" />
</asp:ImageMap>
Here’s the Click event handler, which simply displays the name of the clicked hotspot:
protected void ImageMap1_Click(object sender, ImageMapEventArgs e)
{
lblInfo.Text = "You clicked " + e.PostBackValue;
}
Figure 30-2 shows the resulting page.
Figure 30-2. Handling a hotspot click
A Custom Hotspot
The ImageMap control supports any HotSpot-derived hotspot class. ASP.NET includes exactly three, which correspond to the three basic types of <area> shapes defined in the HTML standard. However, you can create your own hotspots by deriving your own custom class from HotSpot.
Obviously, a custom hotspot class can’t do anything that falls outside the HTML standard. For example, it would be nice to have an ellipse and other curved shapes, but that just isn’t available.
C H A P T E R 3 0 ■ DY N A M I C G R A P H I C S A N D G D I + |
1015 |
However, you can create a variety of complex multisided shapes, such as triangles, octagons, diamonds, and so on, using the polygon type. By deriving a custom HotSpot, you can create a higher-level model that generates the appropriate polygon based on a few basic pieces of information (such as the center coordinate and the radius).
For example, the following class presents a simple custom triangle. This triangle is created based on a center point, width, and height.
public class TriangleHotSpot : HotSpot
{
public TriangleHotSpot()
{
Width = 0;
Height = 0; X = 0;
Y = 0;
}
public int Width
{
get { return (int)ViewState["Width"]; } set { ViewState["Width"] = value; }
}
public int Height
{
get { return (int)ViewState["Height"]; } set { ViewState["Height"] = value; }
}
// X and Y are the coordinates of the center point. public int X
{
get { return (int)ViewState["X"]; } set { ViewState["X"] = value; }
}
public int Y
{
get { return (int)ViewState["Y"]; } set { ViewState["Y"] = value; }
}
...
When creating a custom HotSpot, you must override the MarkupName property to return the type of shape you are creating. Remember, the only valid choices are circle, rectangle, and polygon. This information is placed into the shape attribute of the <area> tag.
...
protected override string MarkupName
{
get { return "polygon"; }
}
...
Finally, you need to override the GetCoordinates() method to return the string for the cords attribute. For a polygon, this must be a comma-separated series of points in X, Y pairs. Here’s the code that creates a simple triangle, with a bottom edge and a single point in the top center:
1016 C H A P T E R 3 0 ■ DY N A M I C G R A P H I C S A N D G D I +
...
public override string GetCoordinates()
{
//Top coordinate. int topX = X;
int topY = Y - Height / 2;
//Bottom-left coordinate. int btmLeftX = X - Width / 2; int btmLeftY = Y + Height / 2;
//Bottom-right coordinate. int btmRightX = X + Width / 2; int btmRightY = Y + Height / 2;
return topX.ToString() + "," + topY.ToString() + "," + btmLeftX.ToString() + "," + btmLeftY.ToString() + "," + btmRightX.ToString() + "," + btmRightY.ToString();
}
}
Now you can use your custom hotspot much as you use a custom control. The first step is to register a tag prefix for your namespace, as shown here:
<%@ Register TagPrefix="chs" Namespace="CustomHotSpots" %>
And here’s an ImageMap that uses the TriangleHotSpot:
<asp:ImageMap ID="ImageMap1" runat="server" ImageUrl="~/triangle.gif"> <chs:TriangleHotSpot AlternateText="Triangle"
X="140" Y="50" Height="75" Width="85" /> </asp:ImageMap>
Drawing with GDI+
GDI+ is an all-purpose drawing model for .NET applications. GDI+ has a number of uses in .NET, including writing documents to the printer, displaying graphics in a Windows application, and rendering graphics in a web page.
Using GDI+ code to draw a graphic is slower than using a static image file. However, it gives you much more freedom and enables several possibilities that weren’t possible (or were prohibitively difficult) in earlier web development platforms, such as classic ASP. For example, you can create rich graphics that incorporate user-specific information, and you can render charts and graphs on the fly based on the records in a database.
The heart of GDI+ programming is the System.Drawing.Graphics class. The Graphics class encapsulates a GDI+ drawing surface, whether it is a window, a print document, or an in-memory bitmap. ASP.NET developers rarely have the need to paint windows or print documents, so it’s the last option that is the most practical.
To use GDI+ in ASP.NET, you need to follow a sequence of four steps:
1.Create the in-memory bitmap where you’ll perform all your drawing.
2.Create a GDI+ graphics context for the image. This gives you the System.Drawing.Graphics object you need.
C H A P T E R 3 0 ■ DY N A M I C G R A P H I C S A N D G D I + |
1017 |
3.Perform the drawing using the methods of the Graphics object. You can draw and fill lines and shapes, and you can even copy bitmap content from existing files.
4.Write the binary data for the image to the browser, using the Response.OutputStream property.
In the following sections, you’ll see several examples of web pages that use GDI+. Before continuing, you may want to ensure that the following namespaces are imported:
using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Imaging;
The System.Drawing namespace defines many of the fundamental ingredients for drawing, including pens, brushes, and bitmaps. By default, Visual Studio adds using statements that import these namespaces to all your web pages. The System.Drawing.Drawing2D namespace adds other useful details such as the flexible GraphicsPath class, while System.Drawing.Imaging includes the ImageFormat namespace that lets you choose the graphics format in which your bitmap will be rendered when it’s sent to the client.
Simple Drawing
The following example demonstrates the simplest possible GDI+ page. All the work is performed in the event handler for the Page.Load event.
The first step is to create the in-memory bitmap by creating an instance of the System.Drawing.Bitmap class. When you create this object, you need to specify the height and width of the image in pixels as constructor arguments. You should make the size as small as possible. Not only will a larger bitmap consume additional server memory while your code is executing, but the size of the rendered content you send to the client will also increase, slowing down the transmission time.
//Create the in-memory bitmap where you will draw the image.
//This bitmap is 300 pixels wide and 50 pixels high.
Bitmap image = new Bitmap(300, 50);
The next step is to create a GDI+ graphics context for the image, which is represented by the System.Drawing.Graphics object. This object provides the methods that allow you to draw content on the in-memory bitmap. To create a Graphics object from an existing Bitmap object, you just use the static Graphics.FromImage() method, as shown here:
Graphics g = Graphics.FromImage(image);
Now comes the interesting part. Using the methods of the Graphics class, you can draw text, shapes, and image on the bitmap. In this example, the drawing code is exceedingly simple. It fills the graphic with a solid white background using the FillRectangle() method of the Graphics object.
//Draw a solid white rectangle.
//Start from point (1, 1).
//Make it 298 pixels wide and 48 pixels high. g.FillRectangle(Brushes.White, 1, 1, 298, 48);
The FillRectangle() method requires several arguments. The first argument sets the color, the next two parameters set the starting point, and the final two parameters set the width and height. When measuring pixels, the point (0, 0) is the top-left corner of your image in (X, Y) coordinates.
The X coordinate increases as you go farther to the right, and the Y coordinate increases as you go farther down. In the current example, the image is 300 pixels wide and 50 pixels high, which means the point (300, 50) is the bottom-right corner.
