Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
868,39 KB
Nội dung
The problem you have with Mozilla 1.5 and
the
SpinBox
control is also related to the speci-
fications of CSS2 not being totally compre-
hensive. Recall that the structure generated
for the
SpinBox
control (see Figure 8.13) is a
root
<span>
element that is relatively posi-
tioned. The contained
TextBox
control is
not positioned (it simply appears in the flow
of the page within the
<span>
control). However, the two
ImageButton
controls carry the
position:absolute
selectors so that they will be located at the right side of the
TextBox
control.
8
Building Adaptive Controls
338
The Drop-Down Lists in Internet Explorer
Interestingly, in Internet Explorer 5.5, the
drop-down lists open on top of the text boxes,
but not always on top of each other in the
correct order—depending on the order in
which they are opened.
Textbox
ImageButtons
position:absolute
<span> element position:relative
FIGURE 8.13 The structure of the standard
SpinBox control.
What happens is that the
ImageButton
controls (which are rendered as
<input type=”image”>
elements in the page) are removed from the flow of the page by the
position:absolute
selectors.
This means that the
<span>
element is only sized to contain the
TextBox
control, so the two
ImageButton
controls lie outside the
<span>
element in terms of location—even though they are
still child controls.
Internet Explorer and Opera take into account the control hierarchy, and the buttons work fine.
However, Mozilla does not consider the buttons to be part of the rendered page as far as the
mouse pointer is concerned, and it ignores mouse clicks on them. But if you place the cursor on
the text box and press the Tab key, you do in fact move the focus to them and can click them
by pressing the Spacebar.
Creating an Alternative Structure for the SpinBox Control
One solution for the various problems with the
SpinBox
control is to offer an alternative struc-
ture for the controls that provides wider support for older browsers. The obvious approach is to
use an HTML table to locate the
TextBox
and
ImageButton
controls. But this leads to another
problem.
The reason you used a
<span>
element in the first place was so that the control could be used
like a
TextBox
control or other standard controls within the flow layout of the page. For
example, the user should be able to place a text caption to the left and more content after it,
without causing the caption or the following content to wrap to a new line. If you use an HTML
table to locate the constituent controls, it will cause preceding and following content to wrap,
forcing the user to insert the whole lot into an HTML table (or use absolute positioning) to get
the layout desired.
Another possibility is to use a
<div>
element as the root control for the
SpinBox
control, but this
has the same problem as using an HTML table. In the end, this example uses the HTML table
but adds an extra cell to the left, where you insert a user-supplied value for the caption (see
Figure 8.14). It’s not ideal because preceding and following content will still wrap, but at least
11 0672326744 CH08 5/4/04 12:24 PM Page 338
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
339
Making the SpinBox Control Adaptive
the caption will appear in the correct position. And it seems to be the only solution for older
browsers.
TextboxCaption
ImageButtons
with <br />
HTML <table> element
HTML <td> table cells
FIGURE 8.14
The structure of the adaptive
SpinBox
control for older browsers.
To maintain the interface and behavior of the control across all browser types, you need to
support the caption in more recent browsers that work with the up-level version of the control.
You can expose the caption as a property of the control, and if the user sets this property, he or
she will expect to see it appear in all browsers. Figure 8.15 shows the updated structure of the
SpinBox
control for these newer browser types.
TextboxCaption
ImageButtons
position:absolute
<span> element
<span> element
position:relative
FIGURE 8.15
The structure of the adaptive
SpinBox
control for more recent browsers.
Adaptability Changes to the SpinBox Control Class
The following sections briefly review the changes required in the
SpinBox
control to implement
the dual behavior for up-level and down-level clients. When you look at the
CreateChildControls
method, you’ll see how you decide what output to send to each type of browser.
Changes to the Private and Public Declarations
You need to make a couple minor changes to the variable and property declarations of the
SpinBox
control. You must import the
System.Web.UI.HtmlControls
namespace because you’re
using the
HtmlGenericControl
class that it defines to create the nested
<span>
element for the up-
level version of the control. You also use a different class name this time (
AdaptiveSpinBox
).
You can add an enumeration to the control to define the “modes” it can run in. This allows a
user to specify, for example, down-level behavior, even if their browser supports the up-level
features:
‘ enumeration of target browser types
Public Enum ClientTargetType
AutoDetect = 0
11 0672326744 CH08 5/4/04 12:24 PM Page 339
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
UpLevel = 1
DownLevel = 2
End Enum
You also need a few more internal variables and the property declarations for the two new prop-
erties
Caption
and
ClientTarget
. The first two internal variables,
_usetable
and
_usecss2
, default
to
False
and are used in other routines within the control to manage the type of output you
send to the client. Notice that the
ClientTarget
property is read-only and is defined as a value
from the
ClientTargetType
enumeration. The internal
_client
variable that shadows the value of
the
ClientTarget
property sets the default to
AutoDetect
(see Listing 8.20).
LISTING 8.20 Registering for Postbacks in the Init Event
Private _usetable As Boolean = True
Private _usecss2 As Boolean = False
Private _caption As String = “”
Private _client As ClientTargetType = ClientTargetType.AutoDetect
Public Property Caption As String
Get
Return _caption
End Get
Set
_caption = value
End Set
End Property
Public WriteOnly Property ClientTarget As ClientTargetType
Set
_client = value
End Set
End Property
Changes to the CreateChildControls Method
The largest number of changes occur in the
CreateChildControls
method, where you
generate the control tree for the
SpinBox
control. In it, you add code that uses the ASP.NET
BrowserCapabilities
object (which you met in Chapter 7) to detect the current browser type
and decide what features it supports.
Listing 8.21 assumes that the client is a down-level device and then checks whether it supports
JavaScript. If it does not, there’s no point in generating the interactive version of the control
that uses CSS2 scripting. If JavaScript is supported, you can use the browser name and major
version number to decide what to do next. Notice that for Internet Explorer 5 and higher, and
for Opera 6 and higher, you specify that it’s an up-level device and that you’ll use CSS2 script-
ing, but you will not generate an HTML table.
8
Building Adaptive Controls
340
11 0672326744 CH08 5/4/04 12:24 PM Page 340
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
341
Making the SpinBox Control Adaptive
LISTING 8.21 Detecting the Browser Type and Capabilities
‘ check if the current browser supports features
‘ required for “smart” operation and if user specified
‘ the mode they want (Version6 or Downlevel)
If _client <> ClientTargetType.DownLevel Then
‘ start by assuming DownLevel
_client = ClientTargetType.DownLevel
‘ get reference to BrowserCapabilities object
Dim oBrowser As HttpBrowserCapabilities = Context.Request.Browser
‘ must support client-side JavaScript
If oBrowser(“JavaScript”) = True Then
‘ get browser type and version
Dim sUAType As String = oBrowser(“Browser”)
Dim sUAVer As String = oBrowser(“MajorVersion”)
‘ see if the current client is IE5 or above
If (sUAType = “IE”) And (sUAVer >= 5) Then
_client = ClientTargetType.UpLevel
_usetable = False
_usecss2 = True
End If
‘ see if the current client is Netscape 6.0/Mozilla 1.0
If (sUAType = “Netscape”) And (sUAVer >= 5) Then
_client = ClientTargetType.UpLevel
_usetable = True
_usecss2 = True
End If
‘ see if the current client is Opera 6.0
If (sUAType = “Opera” And sUAVer >= 6) Then
_client = ClientTargetType.UpLevel
_usetable = False
_usecss2 = True
End If
End If
End If
11 0672326744 CH08 5/4/04 12:24 PM Page 341
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
‘ save current value of _client in viewstate
ViewState(sCID & “target”) = _client.ToString()
‘ display detected client type value in Trace
Context.Trace.Write(“CreateChildControls:” & Me.UniqueID, _
“Saved target ‘“ & _client.ToString() & “‘ in viewstate”)
The odd ones out as far as browsers go are Netscape and Mozilla. If the current browser is
Netscape or Mozilla, with a version number of 5 or higher (which actually equates to Netscape
6.0 and Mozilla 1.0), it is up-level, and you can use CSS2 scripting. However, due to the problem
with the
<span>
element and the absolute-positioned
ImageButton
controls shown earlier, you
have to generate the structure of the control as an HTML table. It will still be interactive because
you’ll inject the client-side script and add the client-side event handlers.
You also need to save the client target value (the value of the
_client
variable) in the viewstate
of the page so that you can extract it next time. This is a property of the control that users will
expect to be maintained across postbacks. If they have set it to
DownLevel
, they won’t expect the
code to perform the detection again after each postback and reset the value.
Creating Browser-Specific Output
Now you can build the control tree needed. To make it easier to manage, the tasks required to
create the control output have been separated into three routines:
n
CreateCSS2Controls
—This routine creates basically the same control tree as the standard
version of the
SpinBox
control you saw earlier in this chapter. The only differences are that
the root
<span>
control is no longer relative positioned, and it contains the caption text
and the nested
<span>
control that is relative positioned (refer to Figure 8.14 for more
details).
n
CreateHTMLTable
—This routine creates the control structure shown in Figure 8.13. This is
the HTML table version, consisting of three cells that contain the caption, the text box,
and the two image buttons. One interesting point here is that you have to use a
LiteralControl
instance to create the
<br />
element that is required to wrap the second
ImageButton
under the first one in the right-hand cell. If you use an
HtmlGenericControl
instance, you actually get the string
“<br></br>”
, which causes most browsers to insert two
line breaks.
n
InjectClientScript
—This routine uses exactly the same code that is used in the standard
version of the
SpinBox
control to generate the
<script>
element that references the client-
side script file for the control (which must be located in the
/aspnet_client/custom/
folder
of the Web site). It also adds the client-side event handler attributes to the
TextBox
control
and the two
ImageButton
controls.
We don’t describe the three routines in detail here because they are generally repetitive and do
not introduce anything new to the discussion. You can view the source code to see these
8
Building Adaptive Controls
342
LISTING 8.21 Continued
11 0672326744 CH08 5/4/04 12:24 PM Page 342
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
343
Making the SpinBox Control Adaptive
routines. (Remember that each sample contains a [view source] link at the foot of the page. See
www.daveandal.net/books/6744/
.)
Listing 8.22 shows the next section of the
CreateChildControls
method, where the
_usetable
and
_usecss2
variables are used to decide which of the three routines just described are executed. The
result is that the control generates output that is suitable for the current browser and provides
the best possible support it can, depending on the features of that browser. Next, although not
shown in Listing 8.22, the values of the properties are displayed in the
Trace
object in exactly
the same way as in the standard
SpinBox
control example.
LISTING 8.22 Creating the Appropriate Control Tree
‘ now ready to create the appropriate set of controls
If _usetable = False Then
‘ serving to version-6 client, use absolute positioning
‘ (but not for Netscape 6.x or Mozilla 1.x)
CreateCSS2Controls()
Else
‘ serving to down-level client, create HTML table
‘ (including Netscape 6.x or Mozilla 1.x)
CreateHTMLTable()
End If
If _usecss2 = True Then
‘ serving to client that supports CSS2 so inject script
InjectClientScript()
End If
Changes to the LoadPostData Method
For the
SpinBox
control example, the only other changes required to provide behavior that
adapts to different clients are to the code in the
LoadPostData
routine. You have to extract the
value from the postback and compare it to the existing value of the control, as stored in the
viewstate of the page. If these two values differ from one another, you raise the
ValueChanged
event. If they are the same, you use the existing value from the viewstate to populate the
control.
The issue with the adaptive control is that, in down-level clients, clicking the up and down
buttons does not automatically change the value in the text box—because there is no client-side
11 0672326744 CH08 5/4/04 12:24 PM Page 343
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
script to do that. Such clicks will always cause postbacks to the server. So you have to check for
a click on either of the two
ImageButton
controls, and you have to see if the value in the text box
has been changed.
Listing 8.23 shows the
LoadPostData
method. After it extracts the value for the text box from the
postback collection, it gets the value when the page was originally created from the viewstate
and the value of the client target type. (Both of these values are saved in the viewstate in the
CreateChildControls
method.)
LISTING 8.23 The LoadPostData Method in the Adaptive SpinBox Control
Overridable Function LoadPostData(key As String, _
vals As NameValueCollection) _
As Boolean _
Implements IPostBackDataHandler.LoadPostData
‘ occurs when data in postback is available to control
‘ get value of control from postback collection
Dim sNewValue As String = vals(key & “_textbox”)
Context.Trace.Write(“LoadPostData:” & key, _
“Loaded postback value ‘“ & sNewValue & “‘ from Request”)
‘ get value from viewstate - i.e. when page was last created
Dim sExistingValue As String = ViewState(key & “_textbox”)
Context.Trace.Write(“LoadPostData:” & key, _
“Loaded existing value ‘“ & sExistingValue & “‘ from viewstate”)
‘ get client target type from viewstate
Dim sClientType As String = ViewState(key & “_target”)
Context.Trace.Write(“LoadPostData:” & key, _
“Loaded target ‘“ & sClientType & “‘ from viewstate”)
If (sClientType = ClientTargetType.UpLevel.ToString()) _
Or (sNewValue <> sExistingValue) Then
‘ either client type is “UpLevel” and value was
‘ incremented by client-side script, or user typed
‘ new value in Textbox in “DownLevel” client
If sNewValue <> sExistingValue Then
‘ value in control has been changed by user
‘ set internal member to posted value and return True
‘ so that PostDataChangedEvent will be raised
_text = sNewValue
8
Building Adaptive Controls
344
11 0672326744 CH08 5/4/04 12:24 PM Page 344
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
345
Making the SpinBox Control Adaptive
Return True
Else
‘ value in control has not changed
‘ set internal member to viewstate value and write message
‘ return False because no need to raise ValueChanged event
_text = sExistingValue
Return False
End If
Else
‘ client type may be “DownLevel” and value was not incremented
‘ so check if “up” or “down” button caused the postback
If vals(key & “_imageup.x”) <> “” Then
‘ “up” image button was clicked so increment value
‘ new value will be checked in CreateChildControls event
‘ to ensure its within maximum and minimum value limits
‘ use Try Catch in case viewstate empty or text not a number
Try
_text = CType(Int32.Parse(sExistingValue) + _increment, _
String)
Context.Trace.Write(“LoadPostData:” & key, _
“Incremented value to ‘“ & _text)
Catch
Context.Trace.Write(“LoadPostData:” & key, _
“Error reading viewstate: “ & sExistingValue)
End Try
‘ return True so that PostDataChangedEvent will be raised
Return True
End If
If vals(key & “_imagedown.x”) <> “” Then
‘ “down” image button was clicked so decrement value
Try
_text = CType(Int32.Parse(sExistingValue) - _increment, _
String)
Context.Trace.Write(“LoadPostData:” & key, _
“Decremented value to ‘“ & _text)
LISTING 8.23 Continued
11 0672326744 CH08 5/4/04 12:24 PM Page 345
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Catch
Context.Trace.Write(“LoadPostData:” & key, _
“Error reading viewstate: “ & sExistingValue)
End Try
‘ return True so that PostDataChangedEvent will be raised
Return True
End If
End If
End Function
Then you can see if this is an up-level client or if the value of the text box has been changed.
Remember that for down-level clients, the user could have typed a new value into the text
box and then submitted the page. If the value has changed, you save it in the internal
_text
variable and return
True
to indicate that you want the page framework to call the
RaisePostBackDataChangedEvent
method, where you’ll raise the
ValueChanged
event.
If the text box value has not changed, you must check whether the user submitted the page
from a down-level client by clicking the up or down button. You can detect whether one of
these buttons was clicked by looking for its value in the postback collection.
ImageButton
controls send the x and y coordinates of the mouse pointer within the image when they are
clicked, or they send zero for both coordinates when the spacebar is used to click the image. All
you have to do is try to increment or decrement the current value (stored in the
_text
variable)
by the current value of the
Increment
property (stored in the
_increment
variable) and return
True
to cause the
ValueChanged
event to be raised.
If you turn on tracing for the page and initiate a postback by clicking the up or down button,
you’ll see the messages that the code writes to the
Trace
object. In Figure 8.16, you can see
the values in the postback collection and the viewstate being loaded, and you can see the
ValueChanged
event being raised. You can also see the points at which the value and the client
target type are saved back into the viewstate and the values of the other properties of the
control.
Testing and Using an Adaptive SpinBox Control
The demonstration page for the adaptive
SpinBox
control that is provided with the samples for
this book is just about identical to the one shown for the standard
SpinBox
control earlier in this
chapter. The page allows the new
Caption
property to be set and shows that caption next to the
control. Of course, the classname is different this time, so the
Register
directive looks like this:
<%@ Register TagPrefix=”ahh” Namespace=”Stonebroom”
Assembly=”adaptive-spinbox” %>
8
Building Adaptive Controls
346
LISTING 8.23 Continued
11 0672326744 CH08 5/4/04 12:24 PM Page 346
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
347
Making the SpinBox Control Adaptive
The adaptive version of the
SpinBox
control looks and behaves the same in Internet Explorer and
Opera as the standard version does. However, it now works in other browsers as well. For
example, Figure 8.17 shows it in Mozilla, where the up and down buttons now work as
expected.
FIGURE 8.16
The trace output from the adap-
tive
SpinBox control following a
postback.
FIGURE 8.17 The adaptive SpinBox control
in Mozilla 1.5.
Figure 8.18 shows the adaptive
SpinBox
control demonstration page in Netscape Navigator 4.5.
The original version of the control fails to show the text box or position the up and down
buttons correctly in this browser—but the adaptive version works as it should.
11 0672326744 CH08 5/4/04 12:24 PM Page 347
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... login, and so on The problem you face is how to create this structure so that you gain consistency across pages without losing the ease of development that ASP.NET brings What you want is the master pages scenario that ASP.NET 2.0 provides, but for ASP.NET1.1 Master pages give you the ability to use some sort of template to define the content that should appear on all pages, and at runtime this content... master page defined 4 If no Content control is found in the content page, the default content from the ContentPlaceHolder control is used This process is easy to re-create in ASP.NET 1.1, with one major exception: It’s not part of the ASP.NET Page Framework Therefore, you can’t use a MasterPageFile attribute on the page directive, and you don’t have automatic support for master pages However, you can write... Framework 1.1 Configuration This useful program provides access to many features of the NET Framework, including the GAC (shown as Assembly Cache in the left tree-view window) To add an assembly, you simply right-click the Assembly Cache entry in the left window of the NET Configuration tool and select Add; then you locate the assembly In Figure 8.20, the assembly DLL has been copied into the Framework\v1.1.4322... But then I’m quite dull, so that’s only to be expected Page Footer Page Header Menu Page Header Menu 354 A product description goes here A product description goes here Page Footer Unfortunately, ASP.NET1.1 has no built-in support for master pages, so you have to build a solution yourself The simplest way is to define a site layout and simply enforce it—tell your developers “this is what it must look... the default set for ASP.NET by declaring it in the section of machine.config or web.config: 351 352 8 Building Adaptive Controls Then your ASP.NET pages can use... Viewing details of an assembly in the GAC with the NET Configuration tool Testing the GAC-Installed Control After you have installed the assembly for the SpinBox control in the GAC, you can use it in an ASP.NET page The demonstration page provided for this is identical to the one for the adaptive version of the control, with the exception of the Register directive To register an assembly that is in the... the usual way The batch file make.bat (also in the samples you can download from www.daveandal.net/books/6744/) does this for you, by executing the following command: C:\WINNT\Microsoft.NET\Framework\v1.1.4322\vbc /t:library ➥/out:GACSpinBox.dll /r:System.dll,System.Web.dll gac-spinbox.vb 349 350 8 Building Adaptive Controls Installing the SpinBox Assembly into the GAC After you compile the class file,... following: n Hide the implementation from the user in a far more comprehensive manner than with user controls n Easily raise events that can be handled in the hosting page just like the events of the standard ASP.NET controls n Install the controls in the GAC so that they are available to any application running on the machine This chapter looks at the basic issues involved in building server controls, including... install the assembly into the GAC The batch file named addtogac.bat (in the samples you can download from www.daveandal.net/books/6744/) contains the command required: “C:\Program Files\Microsoft.NET\SDK\v1.1\Bin\gacutil” /i GACSpinBox.dll If all goes well, you’ll see the message “Assembly successfully added to the cache.” Listing and Removing the Assembly from the GAC The samples for this book, which you... you can download from www.daveandal.net/books/6744/) in a command window when the current folder contains the source class file The following command is required: “C:\Program Files\Microsoft.NET\SDK\v1.1\Bin\sn” -k GACSpinBox.snk Notice that you provide the full path to the sn.exe utility to make sure that you use the correct version if you have more than one version of the NET Framework installed . ease of devel-
opment that ASP. NET brings. What you want is the master pages scenario that ASP. NET 2.0
provides, but for ASP. NET 1. 1. Master pages give you. defaultLanguage=”vb”>
</system.web>
FIGURE 8. 21
Viewing details of an assem-
bly in the GAC with the .NET
Configuration tool.
11 0672326744 CH08 5/4/04 12 :24 PM Page 3 51
Please purchase PDF Split-Merge