漫漫技术人生路

C#

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  234 随笔 :: 0 文章 :: 30 评论 :: 8 引用

公告

2006年10月11日 #

-- -- set language n'简体中文'
-- -- declare @b int
-- --
-- -- set @b= datename(month,getdate())
-- -- select @b
-- -- go
-- -- declare @a int
-- --
-- -- set @a=datepart(year,getdate())
-- -- select @a
-- --
-- -- go
-- -- declare @c varchar(50)
-- -- set @c= datename(year,getdate())+n'year'+cast(datepart(month,getdate()) as varchar)+n'month'+datename(day,getdate())+n'day'
-- -- select @c
-- --
-- -- select convert(varchar(10),getdate(),120)
-- --
-- -- select convert(char(11),datename(year,getdate()))+'1-1'
-- --
-- -- select convert(char(12),getdate(),114)
--
-- --   create function selectname
-- --  (
-- --  @id varchar(11)
-- --  )
-- --  returns table
-- --  as
-- --   return ( select au_lname from authors where au_id=@id)
--
-- -- select * from selectname('213-46-8915')

-- create view tt
-- as
--  select * from selectname('213-46-8915')

-- create procedure dd
-- @a  varchar(11)
-- as
-- select * from selectname(@a)

-- exec dd '213-46-8915'

-- USE pubs
-- IF EXISTS (SELECT name FROM sysobjects
--       WHERE name = 'reminder' AND type = 'TR')
--    DROP TRIGGER reminder
-- GO
-- CREATE TRIGGER reminder
-- ON titles
-- FOR INSERT, UPDATE, DELETE
-- AS
--    EXEC master..xp_sendmail 'MaryM',
--       'Don''t forget to print a report for the distributors.'
-- GO
-- select   列名=name   from   syscolumns   where   id=object_id(N'authors')

-- create trigger trt on authors
-- for update
-- as
-- update forTrigger set dd='3333'

-- update authors set au_lname='fff' where au_id='213-46-8915'
USE pubs
GO
-- Turn recursive triggers ON in the database.
ALTER DATABASE pubs
  SET RECURSIVE_TRIGGERS ON
GO
CREATE TABLE emp_mgr (
  emp char(30) PRIMARY KEY,
   mgr char(30) NULL FOREIGN KEY REFERENCES emp_mgr(emp),
   NoOfReports int DEFAULT 0
)
GO
CREATE TRIGGER emp_mgrins ON emp_mgr
FOR INSERT
AS
DECLARE @e char(30), @m char(30)
DECLARE c1 CURSOR FOR
  SELECT emp_mgr.emp
  FROM   emp_mgr, inserted
  WHERE emp_mgr.emp = inserted.mgr

OPEN c1
FETCH NEXT FROM c1 INTO @e
WHILE @@fetch_status = 0
BEGIN
  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly
  WHERE emp_mgr.emp = @e                            -- added employee.

  FETCH NEXT FROM c1 INTO @e
END
CLOSE c1
DEALLOCATE c1
GO
-- This recursive UPDATE trigger works assuming:
--   1. Only singleton updates on emp_mgr.
--   2. No inserts in the middle of the org tree.
CREATE TRIGGER emp_mgrupd ON emp_mgr FOR UPDATE
AS
IF UPDATE (mgr)
BEGIN
  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Increment mgr's
  FROM inserted                            -- (no. of reports) by
  WHERE emp_mgr.emp = inserted.mgr         -- 1 for the new report.

  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports - 1 -- Decrement mgr's
  FROM deleted                             -- (no. of reports) by 1
  WHERE emp_mgr.emp = deleted.mgr          -- for the new report.
END
GO
-- Insert some test data rows.
INSERT emp_mgr(emp, mgr) VALUES ('Harry', NULL)
INSERT emp_mgr(emp, mgr) VALUES ('Alice', 'Harry')
INSERT emp_mgr(emp, mgr) VALUES ('Paul', 'Alice')
INSERT emp_mgr(emp, mgr) VALUES ('Joe', 'Alice')
INSERT emp_mgr(emp, mgr) VALUES ('Dave', 'Joe')
GO
SELECT * FROM emp_mgr
GO
-- Change Dave's manager from Joe to Harry
UPDATE emp_mgr SET mgr = 'Harry'
WHERE emp = 'Dave'
GO
SELECT * FROM emp_mgr
GO

posted @ 2006-10-11 20:59 javaca88 阅读(57) 评论(0) 编辑

将 JavaScript 与 ASP.NET 2.0 配合使用

发布日期: 2006-6-13 | 更新日期: 2006-6-13

适用于:
ASP.NET 2.0
Visual Web Developer 2005 Express Edition

摘要:学习如何将 JavaScript 与 ASP.NET 2.0 应用程序配合使用。

*
本页内容
简介 简介
将 JavaScript 添加到服务器控件 将 JavaScript 添加到服务器控件
执行简单的按钮翻转 执行简单的按钮翻转
设置控件焦点 设置控件焦点
使用较大的 JavaScript 函数 使用较大的 JavaScript 函数
Page.ClientScript.RegisterStartupScript() 方法 Page.ClientScript.RegisterStartupScript() 方法
Page.ClientScript.RegisterClientScriptBlock() 方法 Page.ClientScript.RegisterClientScriptBlock() 方法
将 JavaScript 放到单独的文件 (.js) 中 将 JavaScript 放到单独的文件 (.js) 中
结论 结论

简介

Web 开发人员一直在通过将服务器端处理和客户端处理结合使用来解决浏览器的限制。客户端的工作逻辑和应用程序进程可使基于浏览器的应用程序看起来响应更及时且更“快速”。过去,对于客户端开发来说,大多数开发人员使用 JavaScript,并将此编程语言混合到了他们知名的 Microsoft Active Server 页面与服务器端 Microsoft Visual Basic Scripting Edition 或 Microsoft JScript 代码中。现在,有了 Microsoft ASP.NET 及其提供的新模型,Web 开发人员往往想知道如何在他们的 ASP.NET 页面中正确使用 JavaScript 函数。

在先前的一篇 MSDN 文章中,我曾经介绍过如何在 ASP.NET 1.x 应用程序中有效地使用 JavaScript。不过,在 ASP.NET 2.0 简介中,您会发现完成此项任务的方法已发生了改变。因此,重新回顾一下如何更好地创建使用 JavaScript 的 ASP.NET 应用程序是很重要的。本文将介绍一些现在可用的以前 JavaScript 函数的使用方法。完成该任务有多种方法,本文将介绍各种可能的方法。本文还将通过一些简短的示例介绍一些在 ASP.NET 页面中对 JavaScript 的一些较为常见的使用方法。

返回页首返回页首

将 JavaScript 添加到服务器控件

将 JavaScript 添加到位于 ASP.NET 页面中的某个特定服务器控件是非常简单的。我们以按钮服务器控件为例。如果您使用任一 Microsoft Visual Studio 2005 将 Button HTML 服务器控件(HtmlInputButton 类)拖放到某个页面中,并将其作为服务器控件运行,则应具有以下代码结构:

<input id="Button1" type="button" value="button" runat="server" />

这是一个普通按钮,可通过 ASP.NET 页面的代码分离或服务器端脚本以编程方式对其进行控制。例如,要在生成页面时指定按钮文本,只需在该元素变成 HTML 服务器控件(右键单击该控件,然后选择 Run As Server Control(作为服务器控件运行))后使用该按钮的 value 属性即可。

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs)

     Button1.Value = DateTime.Now.ToString()
End Sub

C#

protected void Page_Load(object sender, EventArgs e)
{
   Button1.Value = DateTime.Now.ToString();
}

这段代码只是在页面上提供了一个按钮,该按钮的文本为日期和时间。


图 1. 在按钮上显示日期和时间

需要特别注意的是,此处的 ASP.NET 页面是从生成该页面的服务器来获取时间的。因此,如果 Web 服务器位于美国中央时区 (CST -6 GMT) 的某个位置,则无论请求此页面的人位于何处,他们都将获得相同的时间。

如果想要此按钮显示查看该页面的人所在时区的时间,又该如何呢?完成此项任务的最简单方法就是在客户端使用 JavaScript。

就此列举一例,我们要将终端用户(Web 页面的查看者)的计算机时间置于一个按钮 Web 服务器控件上。以下代码显示了如何完成该任务:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub Button1_Click(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        Response.Write("回发!")
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="按钮" 
         OnClick="Button1_Click" Font-Bold="True" Font-Names="Verdana" 
         Font-Size="Larger" />
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write("回发!");
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="按钮" 
         OnClick="Button1_Click" Font-Bold="True" Font-Names="Verdana" 
         Font-Size="Larger" />
    </div>
    </form>
</body>
</html>

在此小段代码中,要注意按钮的一些属性在被发送到客户端浏览器之前是如何指定给服务器端的。本例中,按钮上文本的字体被更改为具有特定大小的粗体 Verdana。客户端接收到按钮的 HTML 代码后,客户端 JavaScript 即会将该按钮的文本更改为终端用户计算机上的当前时间。针对整个页面生成的 HTML 代码如下:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
   使用 JavaScript
</title></head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
 value="/wEPDwUKMTY3NzE5MjIyMGRkVUxVdzEWBhD7U89t7JKIkQc6Cko=" />
</div>

    <div>
        <input type="submit" name="Button1" value="" id="Button1" 
         style="font-family:Verdana;font-size:Larger;font-weight:bold;" />
    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAgK394SHCAKM54rGBtsX8d2S8MO7sf02DOAiquFyBkeY" />
</div></form>
</body>
</html>

单击该按钮仍会出现一个回发(通过 Response.Write 命令查看),当重新呈现此页面时,按钮控件上会显示新时间。结果如图 2 所示。


图 2. 单击日期按钮

在本例中,我们通过 onload 属性将一些 JavaScript 直接置于页面的 <body> 元素中。对于 onload 属性的值,我们特意指向了第一个 <form> 节(因为在 HTML 中可能会有多个 form)中名为 Button1 的 HTML 元素。

虽然使用此方法来添加一些 JavaScript 以便与 ASP.NET Web 服务器控件配合使用很简单,但是我们也可以很容易地将一个 JavaScript 命令添加到按钮本身,如以下部分代码示例所示:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub Page_Load(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        Button1.Attributes.Add("onclick", _
           "javascript:alert('多加注意!!!')")
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button id="Button1" runat="server" Font-Bold="True" 
         Font-Names="Verdana" Font-Size="Larger" 
         Text="单击我!"></asp:Button>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server"> 
    protected void Page_Load(object sender, EventArgs e)
    {
        Button1.Attributes.Add("onclick", 
           "javascript:alert('多加注意!!!')");
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button id="Button1" runat="server" Font-Bold="True" 
         Font-Names="Verdana" Font-Size="Larger" 
         Text="单击我!"></asp:Button>
    </div>
    </form>
</body>
</html>

使用服务器控件的 attribute 属性将附加的 JavaScript 添加到控件特定的控件是一种很好的方式。本例中,通过将 Attribute.Add 属性与脚本关键字和脚本本身(两者均表示为字符串值)配合使用添加了 JavaScript。

返回页首返回页首

执行简单的按钮翻转

一谈到 Web 页面上的按钮,Web 开发人员想要为按钮赋予的较为常见的功能就是翻转效果。翻转效果就是当终端用户将其鼠标置于 Web 页面的某个按钮上时(并不单击该按钮),该按钮的颜色和形状将发生改变。对于具有多个按钮的 Web 页面而言,该功能尤为有用,从使用角度而言这是很有用的,会在终端用户单击按钮之前通知其要对该按钮执行单击操作了。

在服务器控件出现之前,该操作很容易实现,现在,尽管有了服务器控件,也不是那么困难。执行类似操作的代码如下:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub ImageButton1_Click(ByVal sender As Object, _
      ByVal e As System.Web.UI.ImageClickEventArgs)
        Label1.Text = "回发!"
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server"> 
  protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
  {
      Label1.Text = "回发!";
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

这次我们不通过 <body> 元素将 JavaScript 指定给服务器控件,而是使用控件的 onmouseoveronmouseout 事件。对于每个事件,我们均指定一个 JavaScript 值。onmouseover 事件表示终端用户将其鼠标置于控件上方的操作,而 onmouseout 表示终端用户将其鼠标从控件上方移开的操作。在本例中,我们希望当鼠标置于按钮上方时会显示一张图像,而在当加载页面后与当将鼠标从按钮移开后会显示原始图像。

如果您正在直接使用该类控件,而不是像我们在 <body> 元素中使用 JavaScript 时那样在 form 中指定控件,您可以使用 this 关键字,其后紧跟您试图更改的属性。

返回页首返回页首

设置控件焦点

ASP.NET 2.0 现在包括了为其中的一个 HTML 表单元素设置(光标的)焦点的功能。在 ASP.NET 2.0 之前,您必须亲自使用 JavaScript 来完成同样的任务。例如,如果您的 ASP.NET 1.x 页面中有多个文本框,则可通过在页面的 <body> 标记中使用以下代码来使页面在加载后将焦点设置为第一个 TextBox 控件。

<body onload="document.forms[0]['TextBox1'].focus();">

通过使用该构造代码,当页面被加载后,包含 ID TextBox1 的元素将获得焦点,从而使终端用户能够开始直接输入文本,而无需通过鼠标来定位焦点。

ASP.NET 2.0 通过添加 Focus() 方法使得该任务变得非常简单。现在,您可以通过下面的代码来完成对 TextBox 控件的焦点设置:

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
 ByVal e As System.EventArgs)
   TextBox1.Focus()
End Sub

C#

protected void Page_Load(object sender, EventArgs e)
{
   TextBox1.Focus();  
}

浏览器加载使用此方法的页面后,光标即已经被置于了文本框的内部,等待您开始键入文本。因此,您不必将鼠标移到相应的位置即可开始在表单中输入信息。Focus() 方法使您可以动态地将终端用户的光标置于指定的表单元素中(不仅仅是 TextBox 控件,而可以是从 WebControl 类派生而来的任何服务器控件)。

返回页首返回页首

使用较大的 JavaScript 函数

既然我们可以在 HTML 元素内部嵌入部分 JavaScript,甚至可以以动态方式使用 JavaScript 和 Web 服务器控件,那么如何将全部 JavaScript 函数置于您的代码中呢?

可通过多种方法来完成此任务,我们将介绍几种可在 ASP.NET 代码中使用的较为常见的方法。在本文中,我们将介绍如何使用新的 Page.ClientScript 属性。在 ASP.NET 2.0 之前,您需要使用 RegisterStartupScriptRegisterClientScriptBlock 方法。现在,这两个方法已被淘汰。在 ASP.NET 1.x 中注册脚本的两种可能方法均需要使用一组关键字/脚本参数。由于涉及到了两个独立的方法,因此极有可能会出现一些关键字名称冲突。Page.ClientScript 属性本身就可以完成所有的脚本注册,从而使您的代码少出错。

返回页首返回页首

Page.ClientScript.RegisterStartupScript() 方法

最初可用的选项之一就是使用一个可实现此功能的 .NET 类来注册脚本块。第一个是 RegisterStartupScript 方法。当您有一个想要在页面加载时启动的 JavaScript 函数时,最好使用该类。就此列举一例,在 Visual Studio 2005 中创建一个包含两个按钮的 ASP.NET 页面。Button1Button2 分别为这两个按钮的 ID。然后,在 Page_Load 事件内部嵌入以下代码。

Visual Basic

Page.ClientScript.RegisterStartupScript(Me.GetType(), "MyScript", _
   "function AlertHello() { alert('你好,ASP.NET'); }", True)

Button1.Attributes("onclick") = "AlertHello()"
Button2.Attributes("onclick") = "AlertHello()"

C#

Page.ClientScript.RegisterStartupScript(this.GetType(), "MyScript",
   "function AlertHello() { alert('你好,ASP.NET'); }", true);

Button1.Attributes["onclick"] = "AlertHello()";
Button2.Attributes["onclick"] = "AlertHello()";

RegisterStartupScript 方法的两个可能结构如下:

RegisterStartupScript (type, key, script)

RegisterStartupScript (type, key, script, script tag specification)

在上例中,您指定了类型 Me.GetType()、关键字及包含的脚本,然后是一个值为 True 的布尔值(以便 .NET 自动使用 <script> 标记将脚本嵌入 ASP.NET 页面中)。

Page_Load 事件中使用该代码会在浏览器中生成以下 HTML 代码(为简明起见,已删除了一些 HTML 代码):

<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
   使用 JavaScript
</title></head>
<body>
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
 value="/wEPDwUJMTM4ODA1MjE5D2QWAgIED2QWBAIBDw9kFgIeB29uY2xpY2s
 FDEFsZXJ0SGVsbG8oKWQCAw8PZBYCHwAFDEFsZXJ0SGVsbG8oKWRk+DQIaJpw5
 A7pyhzP8dxf/JGUSbA=" />
</div>

    <div>
        <input type="submit" name="Button1" value="Button" 
         onclick="AlertHello();" id="Button1" />
        <input type="submit" name="Button2" value="Button" 
         onclick="AlertHello();" id="Button2" />
    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAwK4yNWFBwKM54rGBgK7q7GGCHwBEr6DyGutQ/egvNrB3OYhCwM4" />
</div>

<script type="text/javascript">
<!--
function AlertHello() { alert('你好,ASP.NET'); }// -->
</script>
</form>
</body>
</html>

使用该 ASP.NET 页面时,请注意,在页面的底部、表单 (</form>) 的最后,嵌入了一个 JavaScript 函数。

应为页面上的所有 JavaScript 指定唯一的关键字,这一点十分重要(这可通过该方法中要求的 key 参数来实现)。如果多个 JavaScript 具有相同的关键字名称,则只会在页面中嵌入第一个 JavaScript。

返回页首返回页首

Page.ClientScript.RegisterClientScriptBlock() 方法

现在,我们通过使用 Page.ClientScript.RegisterClientScriptBlock 方法来创建一个更好版本的按钮翻转示例。先前的翻转按钮示例有一个问题,即当终端用户的鼠标置于按钮图像上时,必须通过单独的请求从服务器检索翻转图像。较好的翻转按钮情况是,按钮的翻转图像已经下载并存储到了浏览器的高速缓存中,以便当终端用户将鼠标置于按钮上时,会立即显示翻转图像。要完成该任务,我们必须构建一个 JavaScript 函数。以下示例介绍了该 JavaScript 函数以及如何使用 RegisterClientScriptBlock 方法将该函数置于页面中。就本例而言,代码分离只需要一个 Page_Load 事件及一个针对 ImageButton 服务器控件的按钮单击事件。

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
 ByVal e As System.EventArgs)
   Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _
      "MyScript", _
      "if (document.images) {" & _
      "MyButton = new Image;" & _
      "MyButtonShaded = new Image;" & _
      "MyButton.src = 'button1.gif;" & _
      "MyButtonShaded.src = 'button2.gif;" & _
      "}" & _
      "else {" & _
      "MyButton = '';" & _
      "MyButtonShaded = '';" & _
      "}", True)

   ImageButton1.Attributes.Add("onmouseover", _
      "this.src = MyButtonShaded.src;" & _
      "window.status='是的!请单击此处!';")
   ImageButton1.Attributes.Add("onmouseout", _
      "this.src = MyButton.src;" & _
      "window.status='';")
End Sub

Protected Sub ImageButton1_Click(ByVal sender As Object, _
  ByVal e As System.Web.UI.ImageClickEventArgs
    Label1.Text = "回发!"
End Sub

C#

<%@ Page Language="C#" %>
<script runat="server">   
protected void Page_Load(object sender, EventArgs e)
{
       Page.RegisterClientScriptBlock("MyScript", _
           "if (document.images) {" +
           "MyButton = new Image;" +
           "MyButtonShaded = new Image;" +
           "MyButton.src = 'button1.gif;" +
           "MyButtonShaded.src = 'button2.gif;" +
           "}" +
           "else {" +
           "MyButton = '';" +
           "MyButtonShaded = '';" +
           "}", true);

       ImageButton1.Attributes.Add("onmouseover",
          "this.src = MyButtonShaded.src;" +
          "window.status='是的!请单击此处!';");
       ImageButton1.Attributes.Add("onmouseout",
          "this.src = MyButton.src;" +
          "window.status='';");
    }
 
  protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
  {
     Label1.Text = "回发!";
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>使用 JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

使用此代码时,浏览器的 HTML 输出将如下所示:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1"><title>
   使用 JavaScript
</title></head>
<body>
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
 value="/wEPDwUKMTcyMTcwOTQ2NA9kFgICBA9kFgICAQ8PZBYEHgtvbm1
 vdXNlb3ZlcgVCdGhpcy5zcmMgPSBNeUJ1dHRvblNoYWRlZC5zcmM7d2luZ
 G93LnN0YXR1cz0nT2ggWWVzISBDbGljayBoZXJlISc7Hgpvbm1vdXNlb3V
 0BSl0aGlzLnNyYyA9IE15QnV0dG9uLnNyYzt3aW5kb3cuc3RhdHVzPScnO
 2QYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFDEltYWd
 lQnV0dG9uMXDJ4zl4FNylcdE+kep0e5wzi14T" />
</div>

<script type="text/javascript">
<!--
if  (document.images) 

{MyButton = new Image;MyButtonShaded = new Image;
MyButton.src = 'button1.gif';MyButtonShaded.src = 'button2.gif';}

else 

{MyButton= '';MyButtonShaded = '';}// -->
</script>

    <div>
        <p>
            <input type="image" name="ImageButton1" id="ImageButton1" 
             onmouseover="this.src = MyButtonShaded.src;window.status=
               '是的!请单击此处!';" 
             onmouseout="this.src = MyButton.src;window.status='';" 
             src="button1.gif" style="border-width:0px;" />
        </p>
        <p>
            <span id="Label1"></span>
        </p>

    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAgLhoLy4DwLSwpnTCEKaKJJN3KmLU7TP4vwT5VSKMT+M" />
</div></form>
</body>
</html>

对于该输出,请注意:通过使用 RegisterClientScriptBlock,JavaScript 函数紧跟在 HTML 代码中开启元素 <form> 的后面。除了使用 RegisterClientScriptBlock 方法添加了 JavaScript 函数外,我们还添加了一些额外的 JavaScript(只是为了增添点乐趣),以便在终端用户将鼠标置于按钮上时文本会显示在浏览器的状态栏中。如图 3 所示。


图 3. 活动的翻转按钮

对于所有此类 JavaScript 来说,最值得高兴的就是,对服务器端事件的普通回发将正常工作。在本例中单击 ImageButton 将产生一个回发,其中更改了标签服务器控件的 text 属性。

Page.ClientScript.RegisterStartupScript 与 Page.ClientScript.RegisterClientScriptBlock 之间的区别

我们已为您介绍了两种不同的可用来将 JavaScript 函数嵌入 ASP.NET 页面的方法,那么,二者之间有何不同呢?主要区别在于,RegisterStartupScript 方法是将 JavaScript 嵌入到 ASP.NET 页面的底部,恰好位于关闭元素 </form> 的前面。RegisterClientScriptBlock 方法是将 JavaScript 嵌入到页面中开启元素 <form> 的紧后面。那么,这有何不同呢?正如我们将要看到的,这有很大的不同。

就此列举一例,以下是在页面加载到浏览器时,将焦点置于该页面上的一个文本框中的方法 - 使用利用了 RegisterStartupScript 方法的 Visual Basic:

Page.ClientScript.RegisterStartupScript(Me.GetType(), "Testing", _ 
  "document.forms[0]['TextBox1'].focus();", True)

由于在浏览器运行到页面底部并执行此小段 JavaScript 时,就已生成了页面上的文本框,并已将其放到了页面中,因此,此方法运行正常。但是,如果不按照上述方法,而编写如下代码(使用 RegisterClientScriptBlock 方法):

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "Testing", _
  "document.forms[0]['TextBox1'].focus();", True)

文本框控件将不会获得焦点,且会在页面上生成一个 JavaScript 错误(如图 4 所示)。


图 4. 执行 JavaScript 时出错

出错的原因在于,浏览器将先遇到 JavaScript,而后文本框才会出现在页面中。因此,JavaScript 将无法找到 TextBox1

返回页首返回页首

将 JavaScript 放到单独的文件 (.js) 中

强烈建议将 JavaScript 函数放到单独的文件中(.js 文件)。一旦它们位于单独的文件中,并且是某个项目的一部分,即可使用某些曾经介绍过的方法将该文件导入到页面中。

例如,可通过以下代码将 .js 文件包括到 ASP.NET 页面中:

Visual Basic

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "MyScript", _
   "MyJavaScriptFile.js")

C#

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyScript", 
   "MyJavaScriptFile.js");

一旦将 .js 文件导入到了 ASP.NET 页面中,即可像以前一样调用任何 JavaScript 函数。如果要管理 JavaScript 函数,并将它们与其他 ASP.NET 页面的逻辑分离,这是个不错的方法。也可使用该方法很容易地在多个 ASP.NET 页面中使用相同的 JavaScript 函数。

返回页首返回页首

结论

本文简要介绍了在 ASP.NET 页面中使用 JavaScript 的一些常见方法以及对 JavaScript 的一些较为常见的使用方法。需要注意的一些较为重要的提示是,要将 JavaScript 放到单独的 .js 文件中,并使用 RegisterStartupScriptRegisterClientScriptBlock 方法将 JavaScript 嵌入到页面中。使用 HtmlGenericControl 的功能将控件特定的 JavaScript 部署到 ASP.NET 页面中也是相当容易的。

关于作者

Bill Evjen 是 .NET 技术的积极拥护者,也是针对 .NET 的基于社团的学习创始人。自从 .NET 于 2000 年发布以来,他一直积极地致力于 .NET 方面的工作。同一年,Bill 创建了“圣路易斯 .NET 用户组”(http://www.stlnet.org) - 世界上最先创建的 .NET 用户组之一。Bill 也是“国际 .NET 联盟”(http://www.ineta.org) 的创始人,该联盟在全球拥有 400,000 多名成员。

以美国密苏里州圣路易斯为基地,Bill 是大家拥戴的 ASP.NET 和 XML Web 服务方面的作者和代言人。他所编写或参与合著的书籍达 10 余种,包括《Professional ASP.NET 2.0》、《Professional C# 2005》、《Professional VB 2005》、《XML Web Services for ASP.NET》以及《Web Services Enhancements: Understanding the WSE for Enterprise Applications, Visual Basic .NET Bible, and ASP.NET Professional Secrets》(均由 Wiley 出版发行)。除了书籍编写之外,Bill 还参与了很多会议的演讲,包括 DevConnections、VSLive 和 TechEd。

Bill 是 Lipper(一家归 Reuters 所有的公司)的技术架构师。他毕业于位于华盛顿州贝灵汉的西华盛顿大学,具有俄语学位。当不在计算机前忙于工作时,通常会在位于芬兰 Toivakka 的避暑别墅中找到他。您可通过 evjen@yahoo.com 与 Bill 取得联系。目前,其个人网络日志位于 http://www.geekswithblogs.net/evjen

posted @ 2006-10-11 20:46 javaca88 阅读(66) 评论(0) 编辑

最近在开发一款自定义服务器控件的时候,发现这样的一个问题:
虽然我实现了IPostBackDataHandler接口的LoadPostData方法,但是调试发现并不执行此方法。

后来找到了原因:
向浏览器render的标准html控件,缺少Name属性。
我想肯定是因为没有Name属性,而form中的数据是通过Name/Value的形式提交,没有Name属性,则该html控件的数据没有提交到服务器。

于是override AddAttributesToRender 方法,问题得以解决。

1 protected override void AddAttributesToRender(HtmlTextWriter writer)
2         {
3             writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
4             base.AddAttributesToRender (writer);
5         }


正是如此,引用一段MSDN的原文吧:

注意 呈现逻辑必须为控件的名称特性分配 UniqueID,如下面的示例所示。如果客户端的控件名称特性与其 UniqueID 不匹配,则页框架无法将回发事件传送给该控件。

[C#]
protected override void Render(HtmlTextWriter output) {
output.Write("<INPUT TYPE=submit name=" + this.UniqueID + " Value='Click Me' />");
posted @ 2006-10-11 20:32 javaca88 阅读(42) 评论(0) 编辑

利用 ASP.NET 2.0 创建自定义 Web 控件

发布日期: 09/03/2004 | 更新日期: 09/03/2004

Jayesh Patel、Bryan Acker、Robert McGovern
Infusion Development

适用于:
Microsoft ASP.NET 2.0
Microsoft Visual Studio 2005

摘要:ASP.NET 2.0 中新的自适应呈现模型为控件编写人员提供了很多新的选项。本文展示了这些选项如何使创建 ASP.NET 的自定义控件变得比以前更加容易。

*
本页内容
简介 简介
自适应呈现模型 自适应呈现模型
创建自定义服务器控件 创建自定义服务器控件
TagKey TagKey
使用自定义控件 使用自定义控件
创建复合服务器控件 创建复合服务器控件
创建复合控件 创建复合控件
添加控件行为 添加控件行为
回调示例 回调示例
使用设计器 使用设计器
小结 小结

简介

从使用基本的文本编辑器到创作标记页面,Web 开发已经经历了一个漫长的过程。目前,集成开发环境 (IDE) 为开发过程中的几乎每个方面都提供了图形化表示形式。此外,还实现各种说明性编程技术以提高效率并降低出现错误的几率。Visual Studio 2005 和 ASP.NET 2.0 中的控件体系结构遵循了这些编程趋势,并且提供了可靠的、可扩展的环境,该环境设计为使开发人员可以创建能够以说明方式配置的控件。

此外,ASP.NET 中新的自适应呈现模型减少了编写可专门识别其目标浏览器的控件的需要。换句话说,控件开发人员可以专注于设计控件,而让 ASP.NET 框架负责转换控件并针对不同类型的浏览器和设备呈现它。

尽管 ASP.NET 2.0 在控件设计过程中提供了增量改进功能,但实际控件呈现模型已经完全进行了更改。作为自定义控件开发人员,您将会看到利用 ASP.NET 的几个新选项。最重要的是,您将会发现只需编写较少的代码便可完成相同的任务。

在 ASP.NET 2.0 中,创建自定义服务器控件有很多方法,每种方法都有其优点和局限性。本文将讨论与自定义控件的创建和配置相关的详细信息。代码示例和体系结构概念要求您对 C# 编程语言具有中等水平的理解。

返回页首返回页首

自适应呈现模型

在 ASP.NET 1.x 中,自定义控件开发人员必须设计每个服务器控件,以便它可以识别不同的浏览器类型并发出正确的输出。ASP.NET 1.x 控件框架提供了几项功能以使该任务变得更简单,但开发人员仍然必须根据浏览器的类型编写切换程序、开发适当的 HTML,然后针对不同类型的浏览器测试控件。此外,如果开发人员希望控件在移动设备上显示,他必须创建一个与普通 Web 浏览器上使用的控件不同的全新控件。

ASP.NET 2.0 通过新的自适应呈现模型简化了浏览器检测和呈现过程。在 ASP.NET 2.0 中引入的自适应呈现模型旨在用于支持那些众多能够使用标记格式(包括 HTML、WML、XHTML 或 CHMTL)的不同设备。

自适应呈现模型体系结构

每个控件都可以链接到一个适配器,它会针对特定的目标设备修改控件的行为和标记。例如,HTML 适配器将 ASP.NET 控件生成为标准的 HTML 和 DHTML,以便普通 Web 浏览器使用。另一方面,WML 适配器将相同的控件转换成无线标记语言,以便蜂窝电话或其他移动设备使用。

customwebcontrolsaspnet2_fig01

1. 控件-适配器寿命周期

上图说明了控件方法与适配器方法之间一对一的映射。如果有适配器(如果控件的 Adapter 属性不为空),执行就会在控件和适配器方法之间传输,如上图所示。在生成阶段,控件对象或适配器对象都可以生成输出(通常情况下两者不同时生成输出)。通常情况下,如果有适配器,那么适配器的实现将覆盖控件的实现。在 ASP.NET 2.0 中,自适应呈现模型适用于所有 ASP.NET 控件(不仅仅是移动控件),并且允许 ASP.NET 2.0 支持统一的控件体系结构。

实际意义

自适应呈现模型的实际意义有两个主要方面。第一,作为开发人员,您可以一次设计控件并期望它可以在具有适配器的任何类型的设备或浏览器上使用。第二,您可以对常用适配器利用广泛的 Microsoft 测试,减少您自己浏览器的特定测试。

自适应呈现模型还为 ASP.NET 2.0 提供了将其他服务添加到控件生成过程中的机会。由于具有适配器模型,您可以:

根据目标的类型,使用筛选器 来更改控件的外观。

根据目标的类型,使用模板来更改整个页面布局。

根据浏览器控制在浏览器上的呈现,而不必依赖于 ASP.NET 1.x 的 uplevel/downlevel 确定。

在本文中,我们将重点放在创建自定义控件的应用方面。但是,请牢记自适应呈现模型是新的基础框架。

返回页首返回页首

创建自定义服务器控件

Visual Studio 2005 提供了很多用于开发自定义服务器控件的有用工具。为了说明某些功能,我们将创建一个 MailLink 控件,它公开了两个属性:EmailText。该控件将生成必需的 HTML 来将所提供的 Text 包装到 mailto: 链接标记中。

创建项目

在 Visual Studio 2005 中,我们通过在新建项目向导中选择适当的图标来创建一个新的“Web Control Library”项目:

customwebcontrolsaspnet2_fig02thumb

2. Visual Studio 2005 中的新建项目向导

该项目是利用默认的自定义控件类实现创建的。对于我们的示例,我们将该默认文件重命名为 MailLink.cs。

:在解决方案资源管理器中重命名该文件时,Visual Studio 2005 将会自动更新类名。

MailLink 的源代码在由项目向导生成的默认模板上构建。MailLink 类从 WebControl 基类自动派生。

public class MailLink : WebControl  {

WebControl 类提供默认实现方法,可以很简单地覆盖这些方法来为我们的控件提供详细说明。

添加属性

MailLink 示例中,我们需要添加 EmailText 属性。为了正确配置这些属性,我们不仅必须编写代码,还要分配几个特性。

[Bindable(true),
 Category("Appearance"),
 DefaultValue(""),
 Description("The e-mail address.")]

public virtual string Email {
     get { 
        string s = (string)ViewState["Email"];
        return (s == null) ? String.Empty : s;
     }
     set {
        ViewState["Email"] = value;
     }
}

特性(以粗体表示)定义了新控件将如何与设计器 (Visual Studio) 进行交互。Email 属性的特性告诉 Visual Studio 如何在设计过程中处理属性:

BindableEmail 属性可绑定 到数据源。您可以将 Email 字段链接到数据库、XML 文件或任何其他 DataSet。该特性强制 Visual Studio 在控件的可绑定属性列表中显示 Email 属性。

AppearanceEmail 属性将显示在 Appearance 类别下的属性视图中。您可以选择想要的任何类别,包括默认类别:AppearanceAccessibilityBehaviorDataLayoutMisc。只要用户选择了属性的类别组织方法,Email 属性将会显示在 Appearance 下。

DefaultValueEmail 属性具有一个空的默认值。尽管空值对于 Email 字段来说有意义,但对于您添加到控件中的其他属性可能并不合适。当用户将您的控件放到他们的 Web 页上时,选择适当的默认值可为用户免去不计其数的单击操作。

Description — 属性说明显示在控件列表下,并且也可能作为工具提示出现。Email 属性将具有 The e-mail address 说明。

Localizable — 它会用发送信号的方式通知 ASP.NET 2.0 Framework 该控件包括可以针对不同语言或位置进行配置的文本属性。

您可以使用 System.ComponentModel 命名空间中的各种特性来进一步改进任何特殊属性的外观和行为。我们将在本文的使用设计器部分中更详细地介绍修改属性或控件的行为的方法。

接下来,我们需要添加 Text 属性。Text 属性与 Email 属性稍有不同,因为我们希望将 Text 显示为由 MailLink 控件发出的 HTML 的一部分。为此,我们需要从 System.Web.UI 命名空间中添加一个新的特性。

[Bindable(true),
 Category("Appearance"),
 DefaultValue(""),
 Description("The text to display on the link."),
 Localizable(true),
 PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual string Text { 
    get {
        string s = (string)ViewState["Text"];
        return (s == null) ? String.Empty : s;
    }
    Set { 
        ViewState["Text"] = value;
    }
}

Text 属性的 PersistenceMode(PersistenceMode.InnerDefaultProperty) 特性(粗体代码)指定设计器应该将该属性作为控件标记内的内部内容序列化。该特性还声明 Text 是控件的默认属性。当用户在 Visual Studio 中使用这个控件时,Text 属性将会作为该控件的内部文本自动显示在图形设计器上,并且如果用户单击该控件并尝试更改显示的文本,Text 属性将会自动更改。

另一方面,应用到属性的特性会影响设计期间用户与控件的交互方式。在运行过程中,这些特性被 ASP.NET 运行时忽略。

有关 ViewState 的注释

请注意,用于两个属性的 GetSet 方法都利用 ViewState 对象。ViewState 对象是一个内置到 WebControl 类中的帮助器对象。从开发角度讲,ViewState 可被视为一个集合类,用于存储在回发过程中我们想要保留的任意属性。实际上,ViewState 封装了确定如何执行持久性(使用 Cookie、会话等等)所需的所有代码和逻辑。

生成控件

在定义了控件属性之后,接下来的步骤就是要设计将由控件发出的实际响应。在 MailLink 示例中,我们希望设计控件来生成基本的 HTML 标记。

返回页首返回页首

TagKey

WebControl 的默认实现会生成一个 标记。我们的 MailLink 控件通过为 TagKey 属性提供它自己的实现来覆盖该默认实现。TagKey 属性定义将要封装控件内容的最外面的标记。

幸运的是,我们可以使用 HtmlTextWriterTag 枚举来指示链接 标记,而不必实际编写 HTML 文本。该枚举方法用于最常用的 HTML 标记。

protected override HtmlTextWriterTag TagKey {
     get {
        return HtmlTextWriterTag.A;
     }
}

如果您需要生成一个不属于 HtmlTextWriterTag 枚举的一部分的标记,您必须覆盖 WebControl.TagName 属性,而非 TagKey 属性。TagName 属性会返回由控件生成的实际 HTML 标记字符串。TagName 的默认 WebControl 实现只调用 TagKey,并以完美的提取方式提取正确的 HTML。

AttributesToRender

在定义了基本标记之后,接下来的步骤就是分配我们要添加到该标记中的各种特性。我们的 MailLink 控件将覆盖 AddAttibutesToRender 方法以便为“mailto”标记添加适当的标记。

protected override void AddAttributesToRender(
  HtmlTextWriter writer){
     base.AddAttributesToRender(writer);
     writer.AddAttribute(HtmlTextWriterAttribute.Href, 
       "mailto:" + Email);
}

对基类的 addAtributeToRender() 调用会被调用,以确保可以正确生成其他样式和特性。如果我们忽略该基本调用,我们可能会失去内置到所有 Web 控件中的母版页设计、筛选器或其他功能。

RenderContents

最后,由于所需的 WebControl 类的方法和属性都已被覆盖,因此可以使用 RenderContents 方法来编写文本。出于安全原因,MailLink 使用 HtmlTextWriter.WriteEncodedText 方法编写 HTML 编码输出。HTML 编码安全地将潜在的危险字符转换为更安全的表示形式。

protected override void RenderContents(
  HtmlTextWriter writer) {
    if (Text == String.Empty) {
        Text = Email;
    }
    writer.WriteEncodedText(Text);
}

请注意,我们只生成 Text 属性。如果 Text 属性为空,我们将利用 Email 属性填充它。请记住,Text 属性旨在用作控件标记的内部文本。这种类型的控件至少需要某一可显示的文本(以便用户进行单击)。如果我们试图生成一个空字符串,我们将失去链接标记的预期功能。

如何生成的?

Render() 方法基本上控制着 WebControl 的整个输出。默认情况下,Render() 方法实际上会依次调用 RenderBeginTag()RenderContents() 以及 RenderEndTag()。尽管在 ASP.NET 1.x 中调用结构并未变化,但由于该呈现模型,修改这些调用的影响却发生了变化。

您可以覆盖 Render() 方法来发出您想要的任何内容。换句话说,您可能已经跳过了覆盖 TagKey 属性、AttributestoRender 属性和 RenderContents() 方法,并且仅使 Render() 编写“text”。但是,这种做法可能会严重影响自适应呈现。如果重写 Render() 来直接发出最终输出,您会绕过内置到 WebControl 类中的大多数自适应呈现特性。

自适应呈现模型和各种适配器的作用是:截获对各种标记方法的调用并转换特定设备的输出。在 MailLink 的特定示例中,几乎所有的标记语言都支持用于 链接的相同语法。但是,其他标记通常在不同的标记语言中会有截然不同的转换。如果我们为这样的标记使用了 Render(),我们的控件将只能在某些浏览器上使用,而适配器无法更改该行为。通过设计控件以使用自适应元素而不是使用 Render(),您可以让 ASP.NET 框架有机会根据浏览器提供在浏览器上的呈现服务。

返回页首返回页首

使用自定义控件

自定义控件能够以很多方法包括在 Web 应用程序中。标准方法是将自定义控件编译到一个程序集中,然后在使用该控件的所有 Web 应用程序中添加一个对该程序集的引用。

使用 EmailLink

为了使用 EmailLink 控件,您需要:

1.

MyControls 项目编译到一个程序集中。

customwebcontrolsaspnet2_fig03

3. 编译包含 EmailLink 控件的 MyControls 命名空间

2.

在新的 Web 项目中添加一个对已编译程序集的引用。

customwebcontrolsaspnet2_fig04

4. 编译应用程序并添加一个引用

在正确添加引用之后,自定义控件应该出现在工具箱中的“MyControls Components”下。

customwebcontrolsaspnet2_fig05

5. 工具箱中的 EmailLink

MyControls 程序集中的所有组件都使用默认的齿轮图标,因为我们未曾在每个控件上设置特定的图标。设置图标如同在该控件类上调整图标属性那样简单。

页面上的控件

在添加了对包含控件的程序集的引用之后,您可以将 MailLink 控件拖动到设计器表面并像使用任何其他 ASP.NET 服务器控件那样使用它。

customwebcontrolsaspnet2_fig06

6. MailLink 自定义控件

6 展示了 MailLink 控件的设计器视图。请注意,Properties 窗口公开了预期的 EmailText 元素,它们可以用于配置控件。通过将自定义控件编译到可重复使用的程序集中,MailLink 控件可以被很多 Web 应用程序重复使用。

返回页首返回页首

创建复合服务器控件

诸如 LoginGridView 这些可靠的控件是由很多基本控件组成的。在 ASP.NET 1.x 中,您必须通过艰苦的工作将嵌套标记和元素添加到自定义控件中来开发复合控件。在 ASP.NET 2.0 中,您可以通过扩展 System.Web.UI.WebControls.CompositeControl 类来构建复杂的复合控件。CompositeControl 类提供了将多个控件的输出合并到单个统一的控件中所必需的框架。

管理复合控件比管理基本自定义控件稍微困难一些,因为复合控件需要一些自定义布局的信息。复合控件将它们的呈现和事件处理任务委托给构成控件。子组件的所有关联的适配器类也会被自动应用。这样,如果您具有适当的适配器,复合控件将会在任何目标浏览器类型或设备上正确地呈现。

返回页首返回页首

创建复合控件

创建复合控件的初始过程与创建自定义服务器控件的初始过程相似。但是,该过程还涉及了更多的步骤。在以下示例中,我们将创建一个由 LabelTextBox 组成的简单的复合 AgeCollector 控件,它旨在收集生日的信息。

复合控件类应该通过从 CompositeControl 继承开始。

public class AgeCollector : CompositeControl
{
}

定义属性

对于我们的简单控件,我们必须为标签 (Prompt) 和文本框 (DateOfBirth) 创建属性。

  [Bindable(true), Category("Appearance"),
    DefaultValue("Please enter your date of birth:"),
    Description("Text to prompt user with.")
    Localizable(true)]
  public virtual String Prompt {  
    get 
    { 
      string s = (string)ViewState["Prompt"];
      return (s == null) ? String.Empty : s;
    }
            set {
                ViewState["Prompt"] = value;
            }
        }

再一次,我们使用特性为属性提供说明和默认值。我们选择了使提示可以进行本地化,以便该控件无论何时都可以用于要求进行国际化的应用程序中。实际的提示可以绑定到包含语言特定文本的资源文件。

还必须定义 DateOfBirth 属性。但是,我们不是使用 String,而是使用 DateTime 数据类型来正确地存储日期。

  [Bindable(true), Category("Appearance"),
    DefaultValue(""),
    Description("Date of Birth Input area")]
  public virtual DateTime DateOfBirth {
    get
    {
      bject o = ViewState["DateOfBirth"];
      return (o == null) ? DateTime.Now : (DateTime)o;
    }
    set { 
     ViewState["DateOfBirth"] = value;
    }
  }

CreateChildControls 方法

我们的复合控件由一个标签和一个文本框组成。我们无法使用简单控件的技术来显示这两个标记,除非使用强制方式和 Render() 方法。因为我们希望利用自适应呈现并显示我们的两个控件,所以我们需要覆盖内置到 CompositeControl 类中的 CreateChildControls() 方法。这种方法使我们可以定义控件,并将我们的复合控件的属性传递到要显示的单个控件中。

  protected override void CreateChildControls() {
    //Create and load the label
    Label lab1 = new Label();
    lab1.Text = Prompt;
    lab1.ForeColor = this.ForeColor;
    this.Controls.Add(lab1);
    
    //Add a line break between the label and text box
    Literal lit = new Literal();
    lit.Text = "";
    this.Controls.Add(lit);

    //Add the Textbox
    TextBox tb = new TextBox();
    tb.ID = "tb1";
    tb.Text = DateOfBirth.ToString();
    this.Controls.Add(tb);

    //call the parent method
    base.CreateChildControls();
  }

请注意,我们必须初始化每个控件、分配所有属性,然后将控件添加到内置到 CompositeControl 类中的 Controls 集合。我们还使用了 Literal 对象将换行符
置于标签和控件之间。Literal 对象是非常简单的控件,您可以使用它在功能元素之间插入原始 HTML。

请注意,我们还对基本方法进行了调用,以便确保我们的复合控件具有内置到 CompositeControl 基类中的任何其他功能。尤其是,基本方法会强制 ASP.NET 将 Controls 集合的所有元素添加到控件树中。如果我们忽略这个调用,或者将其置于我们方法的顶部,那么复合控件将不会正确地生成。

完整的 AgeCollector

当我们的 AgeCollector 控件生成时,ASP.NET 将在每个子控件上实际调用适当的方法,并将结果合并到复合控件的输出中。换句话说,如果我们已正确地设计了简单控件,那么该复合控件就只是一个容器。自适应呈现模型将会自动应用到每个子控件中。但是,实际的 CompositeControl 将不会被修改,因为它不包含需要更改的任何控件。

以下是另一个实例,其中使用的适当方法 (CreateChildControls()) 利用了自适应呈现模型,而不是简单地在 WebControl 上重载 Render() 方法。由于自适应呈现模型和 CompositeControl 的特性,ASP.NET 2.0 节省了我们的开发时间、减少了代码行数并减少了很多的测试烦恼。只要我们知道元素控件可通过特定适配器正确地生成,CompositeControl 将会通过该适配器正确地生成。

如果我们将控件拖动到 ASP.NET 页面上并查看属性,我们将会看到具有 PromptDateOfBirth 属性的单个控件。

customwebcontrolsaspnet2_fig07

7. AgeCollector 使用

请注意,如果我们将复合控件的 ForeColor 更改为红色,我们实际上更改了 LabelForeColor。但是,我们尚未链接某些其他属性。例如,我们无法更改 DateOfBirth 字段的 ForeColor。换句话说,当您构建一个复合控件时,您始终需要考虑应该公开哪些子控件属性。

返回页首返回页首

添加控件行为

到目前为止,我们设计的两个控件都是简单、静态的控件。也就是说,这些控件不会完成利用普通的内置控件或简单用户控件 (.ascx) 无法完成的任何操作。构建自定义服务器控件的主要原因之一就是要提供使用现有控件集无法执行的新功能。

事件模型

在 Web 窗体页面中,与服务器控件关联的事件由客户端引发并由 Web 服务器处理。对于在客户机上由服务器控件引发的事件,ASP.NET 2.0 事件模型收集有关请求的信息,并使用 HTTP Post 将详细信息传递到服务器。服务器上的 Page Framework 对该公告作出解释以确定发生的事件,然后调用适当的处理程序方法。

customwebcontrolsaspnet2_fig08thumb

8. 典型的服务器控件事件

ASP.NET 2.0 可处理几乎所有捕获、传输和解释事件的方法。详细信息对于开发人员来说是隐藏的,开发人员只需要关心服务器上的处理程序方法的实现。

大多数服务器事件要求一个到服务器的往返以便进行处理,因此支持有限数量的单击类型事件。出于性能原因,不支持鼠标悬停和其他内部事件。

回发事件

ASP.NET 2.0 中的很多服务器控件都生成回发事件。回发事件将页面传递到服务器以便进行处理。这是一个非常昂贵的操作,因为它要求页面通过网络进行传递。

回发模型自从 ASP.NET 1.x 就没有进行过显著更改。为了创建一个可处理回发的控件,您的控件必须实现 IPostBackDataHandler 接口,它定义了两个方法:

LoadPostData — 该方法处理您控件的回发数据。

RaisePostDataChangedEvent — 该事件通知应用程序由于处理回发数据,该控件的状态已经更改。

PostDataChangedEvent 调用引发的事件必须在该控件内部定义。然后,用户可以在开发过程中编写实际的事件方法。

非回发事件

某些服务器控件支持非回发事件。此类事件会更改控件的状态,但并不要求立即进行处理。这些事件由控件缓存,而不是立即传递到服务器以进行处理。例如,ListBox 控件可能包含很多元素。如果用户选择一个不同的元素,那么控件将在不通知服务器的情况下显示适当的更改并记住其新状态。在张贴包含 ListBox 的窗体之后,ListBox 控件将提交事件(选定的项)。

非回发事件的默认行为可以通过设置 AutoPostBack 属性进行更改。如果 AutoPostBack 设置为 true,那么通常由客户端缓存的事件发送信号通知服务器立即进行处理。启用 AutoPostBack 的控件要求客户机允许运行脚本。

ASP.NET 2.0 并未以任何明显的方式更改该模型。

回调和带外请求

标准的 Web 协议设计用于同步通讯。每个请求接收响应的速度与服务器生成数据的速度同样快。但是,很多任务都需要带外 请求,例如同一时间访问第三方资源。这些请求未处于浏览器和 Web 服务器之间的标准通讯带区内,因此被认为是带外请求。

ASP.NET 1.x 中的带外

进行带外数据请求的要求提示众多开发人员可以创造性地使用可用资源来获得所需的功能。例如,通过使用 ActiveX 组件和 JavaScript,开发人员能够进行外部 HTTP 调用而无需完全回发到服务器。下面的 JavaScript 示例说明了可以与 ASP.NET 1.x 一起使用的带外 HTTP 请求。

function RetrieveGoogleFrontPage() {
   var XmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
   XmlHttp.Open("GET", "http://www.fakedomain.com", false);
   XmlHttp.Send();
   return XmlHttp.responseText;
}

这种机制的一个缺点就是 XmlHttp.responseText 包含该请求的完整结果。开发人员将必须编写只返回商业数据的特殊页面,否则响应会由于不必要的标记而非常庞大。

ASP.NET 2.0 中的带外

ASP.NET 2.0 概括了 XmlHttp 对象的使用并提供了内置的回调功能。新系统的核心有两个关键项:System.Web.UI.ICallbackEventHandlerPage.GetCallbackEventReference 方法。

Page.GetCallbackEventReference 方法及其重载用于指定将参与回调事件的 JavaScript 方法。

public string GetCallbackEventReference(
  Control control, 
  string argument, 
  string clientCallback, 
  string context
);

上述代码显示了 GetCallBackEventReference 所需的最小参数集,这些参数将在下面进行详细说明。

Controlcontrol 参数确定实现 RaiseCallbackEvent 方法的 ICallbackEventHandler

Argumentargument 字符串包含客户端脚本。评估该脚本的结果将作为 eventArgument 参数传递到 RaiseCallbackEvent

ClientCallbackclientCallback 参数包含客户端事件处理程序的名称,该处理程序将接收成功服务器事件的结果。

Contextcontext 参数包含一个客户端脚本。评估该脚本的结果将传递到客户端事件处理程序,该处理程序在 clientCallback 参数中指定为 context 参数。

CallbackEventHandlerGetCallbackEventReference 方法相结合在客户端和服务器之间产生异步通讯。

返回页首返回页首

回调示例

以下 Web 页使用回调机制查询服务器以获得其当前时间。该页面弹出一个 JavaScript 警告,在无需完整页面回发的情况下显示当前时间。

<%@ Page Language="C#" CompileWith="Default3.aspx.cs" 
ClassName="Default3_aspx" %>
<%@ Register TagPrefix="cc1" 
  Namespace="MyControls" 
  Assembly="WebControlLibrary3" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
      <script language="javascript">
         function GetServerTime() {
            var message = '';
            var context = '';
            <%=CallBack%>
         }
         function ShowServerTime(timeMessage, context) {
            alert('The time on the server is:\n' + timeMessage);
         }
         function OnError(message, context) {
            alert('An unhandled exception has occurred:\n' + message);
         }
      </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <cc1:timesnap id="TimeSnap1" runat="server"> </cc1:timesnap>
        <input type="button" value="GetTime" 
          onclick="GetServerTime();" />&nbsp;
    </div>
    </form>
</body>
</html>

上述页面源代码包含三个关键 JavaScript 函数:GetServerTime()ShowServerTime()OnError()。这些 JavaScript 函数与页面的 GetCallbackEventReference 带外请求相关联。

public partial class Default3_aspx {
  public string CallBack;
  void Page_Load(object sender, EventArgs e) {
    CallBack = this.GetCallbackEventReference(TimeSnap1,
     "message","ShowServerTime","context","OnError");
    }
}

GetCallbackEventReference 方法需要为其第一个参数实现 ICallbackEventHandler 接口的对象。通过实现 RaiseCallbackEvent() 方法,TimeSnap 自定义服务器控件符合接口要求。

    public class TimeSnap : WebControl, ICallbackEventHandler
    {
        ...
        public string RaiseCallbackEvent(string eventArgument) {
            // Uncomment next line to test error handler
            // throw new ApplicationException(
            // "Some unhandled exception");
            return DateTime.Now.ToLocalTime().ToShortTimeString();
        }
    }
}

TimeSnap.RaiseCallbackEvent() 方法仅返回 string 格式的当前时间。

customwebcontrolsaspnet2_fig09

9. 回调请求输出

9 说明了按下 GetTime 按钮的结果。向服务器发出带外请求,从而产生显示服务器上当前时间的“Alert”窗口。发出这个请求不需要回发,因此控件的最初生成时间不会改变。

返回页首返回页首

使用设计器

在前面的示例中,我们已经使用了几个标准的特性来规定自定义控件的属性将与设计器 (Visual Studio) 进行交互的方式。我们为各种控件属性分配了特性以定义属性将在其中出现的类别、定义属性是否应该具有一个默认值、定义属性的说明应该是什么样子以及属性是否应该为 bindable。在 ASP.NET 1.x 中,附加的设计器类 使您可以创建用于编辑属性的新对话框、自动将属性值从 String 转换为其他数据类型(反之亦然),并显示只在运行时生成的控件的占位符数据。

设计器类有助于将控件开发分成两个阶段。第一,您必须开发自定义控件。第二,您必须决定开发人员将如何与设计环境内的控件进行交互。设计器类通过在每个自定义控件的顶部充当装饰师来完成第二个任务。换句话说,如果您要开发很多自定义控件,您可以创建一个标准的可重复使用的设计器集,并通过特性简单地将设计器应用到每个自定义控件中。

ASP.NET 2.0 为设计器模型提供了几项增强功能:

新的复合控件设计器 — CompositeControlDesiger 类完全识别复合控件,并且提供支持父子控件关系的功能。

新的数据绑定控件设计器 — DataBoundControlDesignerDatabound 控件提供了很多新功能。您可以使用该设计器来提供模拟数据,或者在设计期间自动连接到活 datasource

增强的备用设计时区域支持 — 新的 DesignerRegion 类及其子类提供了一种非常灵活的机制以便显示控件。您可以使用 DesignerRegion 来设置控件的选项卡式视图。您还可以使用 EditableDesignerRegion 控件为控件创建新的模板。

增强的模板支持 — 现在,设计器类提供了更简洁的机制以便将新的模板添加到控件中。模板化控件是一种将控件逻辑和控件显示分开的控件。显示通过模板进行定义,而逻辑在实际控件中进行编码。

增强的任务支持 — 现在,设计器可以合并设计时的任务。最常见的任务将可在视图之间切换。但是,其他任务可以包括控件的自动配置或资源文件的自动创建。任务可以在设计时控件上显示为菜单(与允许您配置 GridView 控件的菜单相似)。

增强的事件支持 — 设计器中的事件模型已经进行了改进。现在,您可以创建事件来响应在不同区域中的单击或对各种任务的单击。使用设计器时,只要用户在特定区域上单击就可以使控件切换视图、自动生成代码或更改配置。

ASP.NET 2.0 具有一个经过显著改进的设计器模型,它可以使专业控件开发人员的工作更加简单。如果您只是为自己使用而构建一个单个的控件,该设计器就大材小用了。但是,如果您要为分发而构建一个控件,您可以使用新的设计器来全面地自定义 Visual Studio 2005 中控件的行为。

返回页首返回页首

小结

尽管 ASP.NET 2.0 包含了一个内容丰富的扩展控件集,但开发人员通常有很多理由来创建自定义控件。由于 ASP.NET 2.0 中的增强功能,创建自定义控件的过程要比在 ASP.NET 1.x 中更快、更容易。新的 CompositeControl 基类完全利用自适应呈现模型,并为创建复杂的控件提供了一个简单、易于使用的容器。如果您的控件需要回发或回调功能,ASP.NET 2.0 简化了处理客户端脚本文件和开发带外请求的过程。最后,在您开发控件后,您可以使用各种设计器类来完全配置控件在可视化设计器(例如 Visual Studio 2005)内的行为。

相关书籍

A First Look at ASP.NET V. 2.0

ASP.NET 2.0 Revealed

Developing ASP.NET Server Controls and Components

关于作者

Jayesh Patel — Jay Patel 是 .NET 和 Java 技术的开发人员。Jay 的研究重点在于基于编程的模式和灵活方法。

Bryan Acker — Bryan Acker 是 Infusion Development 的技术编写人员。Bryan 在 ASP、ASP.NET Web 开发和 Web 宿主方面有非常深厚的背景。

Robert McGovern — Rob McGovern 是一名资深作家、开发人员并且是 Infusion Development 的项目经理。Rob 参加过数个不同的 ASP.NET 项目,包括“CodeNotes for ASP.NET”和“The JSP to ASP.NET migration guide”。

Infusion Development Corporation 是 Microsoft 认证的解决方案提供商,为跻身财富杂志 1000 强的公司提供自定义软件开发、培训和咨询服务,主要对金融服务行业提供上述服务。基于在纽约和多伦多的办事处,Infusion Development 已经建立了一个国际化的客户基地,其中包括一些世界最大的金融服务、证券经纪和软件开发行业的公司。Infusion Development 的员工同时还是 CodeNotes 系列书籍的作者和创始者。

posted @ 2006-10-11 20:26 javaca88 阅读(54) 评论(0) 编辑

前几天也碰到日志文件过大的问题,数据库实际大小为600M, 日志文件实际大小为33M,
  试了多种方式,SHIRNK DATABASE, TRUNCATE LOG FILE, 都没办法将文件缩小。无论如
  后来找到下面的代码,就可以将日志文件缩小到自己想要的大小了。把代码COPY到查询分
析器里,,然后修改其中的3个参数(数据库名,日志文件名,和目标日志文件的大小),运行
  -----
  SET NOCOUNT ON
  DECLARE @LogicalFileName sysname,
  @MaxMinutes INT,
  @NewSize INT
  USE Marias -- 要操作的数据库名
  SELECT @LogicalFileName = 'Marias_log', -- 日志文件名
  @MaxMinutes = 10, -- Limit on time allowed to wrap log.
  @NewSize = 100 -- 你想设定的日志文件的大小(M)
  -- Setup / initialize
  DECLARE @OriginalSize int
  SELECT @OriginalSize = size
  FROM sysfiles
  WHERE name = @LogicalFileName
  SELECT 'Original Size of ' + db_name() + ' LOG is ' +
  CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' +
  CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'
  FROM sysfiles
  WHERE name = @LogicalFileName
  CREATE TABLE DummyTrans
  (DummyColumn char (8000) not )
  DECLARE @Counter INT,
  @StartTime DATETIME,
  @TruncLog VARCHAR(255)
  SELECT @StartTime = GETDATE(),
  @TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'
  DBCC SHRINKFILE (@LogicalFileName, @NewSize)

  EXEC (@TruncLog)
  -- Wrap the log if necessary.   WHILE @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired
  AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)
  AND (@OriginalSize * 8 /1024) > @NewSize
  BEGIN -- Outer loop.
  SELECT @Counter = 0   WHILE ((@Counter < @OriginalSize / 16) AND (@Counter < 50000))
  BEGIN -- update
  INSERT DummyTrans VALUES ('Fill Log')
  DELETE DummyTrans
  SELECT @Counter = @Counter + 1
  END
  EXEC (@TruncLog)
  END
  SELECT 'Final Size of ' + db_name() + ' LOG is ' +
  CONVERT(VARCHAR(30),size) + ' 8K pages or ' +

  CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'

  FROM sysfiles
  WHERE name = @LogicalFileName
  DROP TABLE DummyTrans
  SET NOCOUNT OFF

posted @ 2006-10-11 20:13 javaca88 阅读(48) 评论(0) 编辑

SQL语句导入导出大全 
/******* 导出到excel
EXEC master..xp_cmdshell \'bcp SettleDB.dbo.shanghu out c:\\temp1.xls -c -q -S\"GNETDATA/GNETDATA\" -U\"sa\" -P\"\"\'

/*********** 导入Excel
SELECT * 
FROM OpenDataSource( \'Microsoft.Jet.OLEDB.4.0\',
\'Data Source=\"c:\\test.xls\";User ID=Admin;Password=;Extended properties=Excel 5.0\')...xactions

/*动态文件名
declare @fn varchar(20),@s varchar(1000)
set @fn = \'c:\\test.xls\'
set @s =\'\'\'Microsoft.Jet.OLEDB.4.0\'\',
\'\'Data Source=\"\'+@fn+\'\";User ID=Admin;Password=;Extended properties=Excel 5.0\'\'\'
set @s = \'SELECT * FROM OpenDataSource (\'+@s+\')...sheet1$\'
exec(@s)
*/

SELECT cast(cast(科目编号 as numeric(10,2)) as nvarchar(255))+\' \' 转换后的别名
FROM OpenDataSource( \'Microsoft.Jet.OLEDB.4.0\',
\'Data Source=\"c:\\test.xls\";User ID=Admin;Password=;Extended properties=Excel 5.0\')...xactions

/********************** EXCEL导到远程SQL
insert OPENDATASOURCE(
\'SQLOLEDB\',
\'Data Source=远程ip;User ID=sa;Password=密码\'
).库名.dbo.表名 (列名1,列名2)
SELECT 列名1,列名2
FROM OpenDataSource( \'Microsoft.Jet.OLEDB.4.0\',
\'Data Source=\"c:\\test.xls\";User ID=Admin;Password=;Extended properties=Excel 5.0\')...xactions


/** 导入文本文件
EXEC master..xp_cmdshell \'bcp dbname..tablename in c:\\DT.txt -c -Sservername -Usa -Ppassword\'

/** 导出文本文件
EXEC master..xp_cmdshell \'bcp dbname..tablename out c:\\DT.txt -c -Sservername -Usa -Ppassword\'

EXEC master..xp_cmdshell \'bcp \"Select * from dbname..tablename\" queryout c:\\DT.txt -c -Sservername -Usa -Ppassword\'

导出到TXT文本,用逗号分开
exec master..xp_cmdshell \'bcp \"库名..表名\" out \"d:\\tt.txt\" -c -t ,-U sa -P password\'


BULK INSERT 库名..表名
FROM \'c:\\test.txt\'
WITH (
FIELDTERMINATOR = \';\',
ROWTERMINATOR = \'\\n\'
)


--/* dBase IV文件
select * from 
OPENROWSET(\'MICROSOFT.JET.OLEDB.4.0\'
,\'dBase IV;HDR=NO;IMEX=2;DATABASE=C:\\\',\'select * from [客户资料4.dbf]\')
--*/

--/* dBase III文件
select * from 
OPENROWSET(\'MICROSOFT.JET.OLEDB.4.0\'
,\'dBase III;HDR=NO;IMEX=2;DATABASE=C:\\\',\'select * from [客户资料3.dbf]\')
--*/

--/* FoxPro 数据库
select * from openrowset(\'MSDASQL\',
\'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\\\',
\'select * from [aa.DBF]\')
--*/

/**************导入DBF文件****************/
select * from openrowset(\'MSDASQL\',
\'Driver=Microsoft Visual FoxPro Driver;
SourceDB=e:\\VFP98\\data;
SourceType=DBF\',
\'select * from customer where country != \"USA\" order by country\')
go
/***************** 导出到DBF ***************/
如果要导出数据到已经生成结构(即现存的)FOXPRO表中,可以直接用下面的SQL语句

insert into openrowset(\'MSDASQL\',
\'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\\\',
\'select * from [aa.DBF]\')
select * from 表

说明:
SourceDB=c:\\ 指定foxpro表所在的文件夹
aa.DBF 指定foxpro表的文件名.



/*************导出到Access********************/
insert into openrowset(\'Microsoft.Jet.OLEDB.4.0\', 
\'x:\\A.mdb\';\'admin\';\'\',A表) select * from 数据库名..B表

/*************导入Access********************/
insert into B表 selet * from openrowset(\'Microsoft.Jet.OLEDB.4.0\', 
\'x:\\A.mdb\';\'admin\';\'\',A表)

文件名为参数
declare @fname varchar(20)
set @fname = \'d:\\test.mdb\'
exec(\'SELECT a.* FROM opendatasource(\'\'Microsoft.Jet.OLEDB.4.0\'\',
\'\'\'+@fname+\'\'\';\'\'admin\'\';\'\'\'\', topics) as a \')

SELECT * 
FROM OpenDataSource( \'Microsoft.Jet.OLEDB.4.0\',
\'Data Source=\"f:\\northwind.mdb\";Jet OLEDB:Database Password=123;User ID=Admin;Password=;\')...产品

********************* 导入 xml 文件

DECLARE @idoc int
DECLARE @doc varchar(1000)
--sample XML document
SET @doc =\'
<root>
<Customer cid= \"C1\" name=\"Janine\" city=\"Issaquah\">
<Order oid=\"O1\" date=\"1/20/1996\" amount=\"3.5\" />
<Order oid=\"O2\" date=\"4/30/1997\" amount=\"13.4\">Customer was very satisfied
</Order>
</Customer>
<Customer cid=\"C2\" name=\"Ursula\" city=\"Oelde\" >
<Order oid=\"O3\" date=\"7/14/1999\" amount=\"100\" note=\"Wrap it blue 
white red\">
<Urgency>Important</Urgency>
Happy Customer.
</Order>
<Order oid=\"O4\" date=\"1/20/1996\" amount=\"10000\"/>
</Customer>
</root>
\'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, \'/root/Customer/Order\', 1)
WITH (oid char(5), 
amount float, 
comment ntext \'text()\')
EXEC sp_xml_removedocument @idoc


???????

/**********************Excel导到Txt****************************************/
想用
select * into opendatasource(...) from opendatasource(...)
实现将一个Excel文件内容导入到一个文本文件

假设Excel中有两列,第一列为姓名,第二列为很行帐号(16位)
且银行帐号导出到文本文件后分两部分,前8位和后8位分开。


邹健:
如果要用你上面的语句插入的话,文本文件必须存在,而且有一行:姓名,银行账号1,银行账号2
然后就可以用下面的语句进行插入
注意文件名和目录根据你的实际情况进行修改.

insert into
opendatasource(\'MICROSOFT.JET.OLEDB.4.0\'
,\'Text;HDR=Yes;DATABASE=C:\\\'
)...[aa#txt]
--,aa#txt)
--*/
select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) 
from 
opendatasource(\'MICROSOFT.JET.OLEDB.4.0\'
,\'Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\\a.xls\'
--,Sheet1$)
)...[Sheet1$]


如果你想直接插入并生成文本文件,就要用bcp

declare @sql varchar(8000),@tbname varchar(50)

--首先将excel表内容导入到一个全局临时表
select @tbname=\'[##temp\'+cast(newid() as varchar(40))+\']\'
,@sql=\'select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) 
into \'+@tbname+\' from 
opendatasource(\'\'MICROSOFT.JET.OLEDB.4.0\'\'
,\'\'Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\\a.xls\'\'
)...[Sheet1$]\'
exec(@sql)

--然后用bcp从全局临时表导出到文本文件
set @sql=\'bcp \"\'+@tbname+\'\" out \"c:\\aa.txt\" /S\"(local)\" /P\"\" /c\'
exec master..xp_cmdshell @sql

--删除临时表
exec(\'drop table \'+@tbname)


/********************导整个数据库*********************************************/

用bcp实现的存储过程


/*
实现数据导入/导出的存储过程
根据不同的参数,可以实现导入/导出整个数据库/单个表
调用示例:
--导出调用示例
----导出单个表
exec file2table \'zj\',\'\',\'\',\'xzkh_sa..地区资料\',\'c:\\zj.txt\',1
----导出整个数据库
exec file2table \'zj\',\'\',\'\',\'xzkh_sa\',\'C:\\docman\',1

--导入调用示例
----导入单个表
exec file2table \'zj\',\'\',\'\',\'xzkh_sa..地区资料\',\'c:\\zj.txt\',0
----导入整个数据库
exec file2table \'zj\',\'\',\'\',\'xzkh_sa\',\'C:\\docman\',0

*/
if exists(select 1 from sysobjects where name=\'File2Table\' and objectproperty(id,\'IsProcedure\')=1)
drop procedure File2Table
go
create procedure File2Table
@servername varchar(200) --服务器名
,@username varchar(200) --用户名,如果用NT验证方式,则为空\'\'
,@password varchar(200) --密码
,@tbname varchar(500) --数据库.dbo.表名,如果不指定:.dbo.表名,则导出数据库的所有用户表
,@filename varchar(1000) --导入/导出路径/文件名,如果@tbname参数指明是导出整个数据库,则这个参数是文件存放路径,文件名自动用表名.txt
,@isout bit --1为导出,0为导入
as
declare @sql varchar(8000)

if @tbname like \'%.%.%\' --如果指定了表名,则直接导出单个表
begin
set @sql=\'bcp \'+@tbname
+case when @isout=1 then \' out \' else \' in \' end
+\' \"\'+@filename+\'\" /w\'
+\' /S \'+@servername
+case when isnull(@username,\'\')=\'\' then \'\' else \' /U \'+@username end
+\' /P \'+isnull(@password,\'\')
exec master..xp_cmdshell @sql
end
else
begin --导出整个数据库,定义游标,取出所有的用户表
declare @m_tbname varchar(250)
if right(@filename,1)<>\'\\\' set @filename=@filename+\'\\\'

set @m_tbname=\'declare #tb cursor for select name from \'+@tbname+\'..sysobjects where xtype=\'\'U\'\'\'
exec(@m_tbname)
open #tb
fetch next from #tb into @m_tbname
while @@fetch_status=0
begin
set @sql=\'bcp \'+@tbname+\'..\'+@m_tbname
+case when @isout=1 then \' out \' else \' in \' end
+\' \"\'+@filename+@m_tbname+\'.txt \" /w\'
+\' /S \'+@servername
+case when isnull(@username,\'\')=\'\' then \'\' else \' /U \'+@username end
+\' /P \'+isnull(@password,\'\')
exec master..xp_cmdshell @sql
fetch next from #tb into @m_tbname
end
close #tb
deallocate #tb 
end
go


/************* Oracle **************/
EXEC sp_addlinkedserver \'OracleSvr\', 
\'Oracle 7.3\', 
\'MSDAORA\', 
\'ORCLDB\'
GO

delete from openquery(mailser,\'select * from yulin\')

select * from openquery(mailser,\'select * from yulin\')

update openquery(mailser,\'select * from yulin where id=15\')set disorder=555,catago=888

insert into openquery(mailser,\'select disorder,catago from yulin\')values(333,777)


补充:

对于用bcp导出,是没有字段名的.

用openrowset导出,需要事先建好表.

用openrowset导入,除ACCESS及EXCEL外,均不支持非本机数据导入
posted @ 2006-10-11 20:11 javaca88 阅读(47) 评论(0) 编辑

包括安装时提示有挂起的操作、收缩数据库、压缩数据库、转移数据库给新用户以已存在用户权限、检查备份集、修复数据库等

 (一)挂起操作

在安装Sql或sp补丁的时候系统提示之前有挂起的安装操作,要求重启,这里往往重启无用,解决办法:

到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

删除PendingFileRenameOperations

(二)收缩数据库
--重建索引
DBCC REINDEX
DBCC INDEXDEFRAG
--收缩数据和日志
DBCC SHRINKDB
DBCC SHRINKFILE

(三)压缩数据库
dbcc shrinkdatabase(dbname)

(四)转移数据库给新用户以已存在用户权限
exec sp_change_users_login 'update_one','newname','oldname'
go

(五)检查备份集
RESTORE VERIFYONLY from disk='E:\dvbbs.bak'

(六)修复数据库
ALTER DATABASE [dvbbs] SET SINGLE_USER
GO
DBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCK
GO
ALTER DATABASE [dvbbs] SET MULTI_USER
GO


--CHECKDB 有3个参数:
--REPAIR_ALLOW_DATA_LOSS
--  执行由 REPAIR_REBUILD 完成的所有修复,包括对行和页进行分配和取消分配以改正分配错误、结构行或页的错误,以及删除已损坏的文本对象。这些修复可能会导致一些数据丢失。修复操作可以在用户事务下完成以允许用户回滚所做的更改。如果回滚修复,则数据库仍会含有错误,应该从备份进行恢复。如果由于所提供修复等级的缘故遗漏某个错误的修复,则将遗漏任何取决于该修复的修复。修复完成后,备份数据库。
--REPAIR_FAST 进行小的、不耗时的修复操作,如修复非聚集索引中的附加键。这些修复可以很快完成,并且不会有丢失数据的危险。
--REPAIR_REBUILD 执行由 REPAIR_FAST 完成的所有修复,包括需要较长时间的修复(如重建索引)。执行这些修复时不会有丢失数据的危险。

--DBCC CHECKDB('dvbbs') with NO_INFOMSGS,PHYSICAL_ONLY

SQL SERVER日志清除的两种方法
在使用过程中大家经常碰到数据库日志非常大的情况,在这里介绍了两种处理方法……

方法一

一般情况下,SQL数据库的收缩并不能很大程度上减小数据库大小,其主要作用是收缩日志大小,应当定期进行此操作以免数据库日志过大
1、设置数据库模式为简单模式:打开SQL企业管理器,在控制台根目录中依次点开Microsoft SQL Server-->SQL Server组-->双击打开你的服务器-->双击打开数据库目录-->选择你的数据库名称(如论坛数据库Forum)-->然后点击右键选择属性-->选择选项-->在故障还原的模式中选择“简单”,然后按确定保存
2、在当前数据库上点右键,看所有任务中的收缩数据库,一般里面的默认设置不用调整,直接点确定
3、收缩数据库完成后,建议将您的数据库属性重新设置为标准模式,操作方法同第一点,因为日志在一些异常情况下往往是恢复数据库的重要依据

方法二

SET NOCOUNT ON
DECLARE @LogicalFileName sysname,
        @MaxMinutes INT,
        @NewSize INT


USE     tablename             -- 要操作的数据库名
SELECT  @LogicalFileName = 'tablename_log',  -- 日志文件名
@MaxMinutes = 10,               -- Limit on time allowed to wrap log.
        @NewSize = 1                  -- 你想设定的日志文件的大小(M)

-- Setup / initialize
DECLARE @OriginalSize int
SELECT @OriginalSize = size
  FROM sysfiles
  WHERE name = @LogicalFileName
SELECT 'Original Size of ' + db_name() + ' LOG is ' +
        CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' +
        CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'
  FROM sysfiles
  WHERE name = @LogicalFileName
CREATE TABLE DummyTrans
  (DummyColumn char (8000) not null)


DECLARE @Counter   INT,
        @StartTime DATETIME,
        @TruncLog  VARCHAR(255)
SELECT  @StartTime = GETDATE(),
        @TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'

DBCC SHRINKFILE (@LogicalFileName, @NewSize)
EXEC (@TruncLog)
-- Wrap the log if necessary.
WHILE     @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired
      AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName) 
      AND (@OriginalSize * 8 /1024) > @NewSize 
  BEGIN -- Outer loop.
    SELECT @Counter = 0
    WHILE  ((@Counter < @OriginalSize / 16) AND (@Counter < 50000))
      BEGIN -- update
        INSERT DummyTrans VALUES ('Fill Log') 
        DELETE DummyTrans
        SELECT @Counter = @Counter + 1
      END  
    EXEC (@TruncLog) 
  END  
SELECT 'Final Size of ' + db_name() + ' LOG is ' +
        CONVERT(VARCHAR(30),size) + ' 8K pages or ' +
        CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'
  FROM sysfiles
  WHERE name = @LogicalFileName
DROP TABLE DummyTrans
SET NOCOUNT OFF

 

删除数据库中重复数据的几个方法
数据库的使用过程中由于程序方面的问题有时候会碰到重复数据,重复数据导致了数据库部分设置不能正确设置……

方法一

declare @max integer,@id integer
declare cur_rows cursor local for select 主字段,count(*) from 表名 group by 主字段 having count(*) > 1
open cur_rows
fetch cur_rows into @id,@max
while @@fetch_status=0
begin
select @max = @max -1
set rowcount @max
delete from 表名 where 主字段 = @id
fetch cur_rows into @id,@max
end
close cur_rows
set rowcount 0

方法二

有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略。
1、对于第一种重复,比较容易解决,使用
    select distinct * from tableName
就可以得到无重复记录的结果集。
如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除
    select distinct * into #Tmp from tableName
    drop table tableName
    select * into tableName from #Tmp
    drop table #Tmp
发生这种重复的原因是表设计不周产生的,增加唯一索引列即可解决。

2、这类重复问题通常要求保留重复记录中的第一条记录,操作方法如下
    假设有重复的字段为Name,Address,要求得到这两个字段唯一的结果集
    select identity(int,1,1) as autoID, * into #Tmp from tableName
    select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID
    select * from #Tmp where autoID in(select autoID from #tmp2)
    最后一个select即得到了Name,Address不重复的结果集(但多了一个autoID字段,实际写时可以写在select子句中省去此列)

 

更改数据库中表的所属用户的两个方法
大家可能会经常碰到一个数据库备份还原到另外一台机器结果导致所有的表都不能打开了,原因是建表的时候采用了当时的数据库用户……


--更改某个表
exec sp_changeobjectowner 'tablename','dbo'


--存储更改全部表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch
 @OldOwner as NVARCHAR(128),
 @NewOwner as NVARCHAR(128)
AS

DECLARE @Name   as NVARCHAR(128)
DECLARE @Owner  as NVARCHAR(128)
DECLARE @OwnerName  as NVARCHAR(128)

DECLARE curObject CURSOR FOR
 select 'Name'   = name,
  'Owner'   = user_name(uid)
 from sysobjects
 where user_name(uid)=@OldOwner
 order by name

OPEN  curObject
FETCH NEXT FROM curObject INTO @Name, @Owner
WHILE(@@FETCH_STATUS=0)
BEGIN    
 if @Owner=@OldOwner
 begin
  set @OwnerName = @OldOwner + '.' + rtrim(@Name)
  exec sp_changeobjectowner @OwnerName, @NewOwner
 end
-- select @name,@NewOwner,@OldOwner

 FETCH NEXT FROM curObject INTO @Name, @Owner
END

close curObject
deallocate curObject


GO


SQL SERVER中直接循环写入数据
没什么好说的了,大家自己看,有时候有点用处

declare @i int
set @i=1
while @i<30
begin
   insert into test (userid) values(@i)
   set @i=@i+1
end

 

无数据库日志文件恢复数据库方法两则
数据库日志文件的误删或别的原因引起数据库日志的损坏


方法一

1.新建一个同名的数据库

2.再停掉sql server(注意不要分离数据库)

3.用原数据库的数据文件覆盖掉这个新建的数据库

4.再重启sql server

5.此时打开企业管理器时会出现置疑,先不管,执行下面的语句(注意修改其中的数据库名)

6.完成后一般就可以访问数据库中的数据了,这时,数据库本身一般还要问题,解决办法是,利用
数据库的脚本创建一个新的数据库,并将数据导进去就行了.

USE MASTER
GO

SP_CONFIGURE 'ALLOW UPDATES',1 RECONFIGURE WITH OVERRIDE
GO

UPDATE SYSDATABASES SET STATUS =32768 WHERE NAME='置疑的数据库名'
Go

sp_dboption '置疑的数据库名', 'single user', 'true'
Go

DBCC CHECKDB('置疑的数据库名')
Go

update sysdatabases set status =28 where name='置疑的数据库名'
Go

sp_configure 'allow updates', 0 reconfigure with override
Go

sp_dboption '置疑的数据库名', 'single user', 'false'
Go

方法二

事情的起因
昨天,系统管理员告诉我,我们一个内部应用数据库所在的磁盘空间不足了。我注意到数据库事件日志文件XXX_Data.ldf文件已经增长到了3GB,于是我决意缩小这个日志文件。经过收缩数据库等操作未果后,我犯了一个自进入行业以来的最大最愚蠢的错误:竟然误删除了这个日志文件!后来我看到所有论及数据库恢复的文章上都说道:“无论如何都要保证数据库日志文件存在,它至关重要”,甚至微软甚至有一篇KB文章讲如何只靠日志文件恢复数据库的。我真是不知道我那时候是怎么想的?!

这下子坏了!这个数据库连不上了,企业管理器在它的旁边写着“(置疑)”。而且最要命的,这个数据库从来没有备份了。我唯一找得到的是迁移半年前的另外一个数据库服务器,应用倒是能用了,但是少了许多记录、表和存储过程。真希望这只是一场噩梦!

没有效果的恢复步骤
附加数据库
_Rambo讲过被删除日志文件中不存在活动日志时,可以这么做来恢复:

1,分离被置疑的数据库,可以使用sp_detach_db
2,附加数据库,可以使用sp_attach_single_file_db

但是,很遗憾,执行之后,SQL Server质疑数据文件和日志文件不符,所以无法附加数据库数据文件。

DTS数据导出
不行,无法读取XXX数据库,DTS Wizard报告说“初始化上下文发生错误”。

posted @ 2006-10-11 20:10 javaca88 阅读(44) 评论(0) 编辑

create   trigger   命令示例  
  下面的示例创建了更新触发器。防止大于   50   的值输入到   customer   表的   maxordamt   字段中。第一个   replace   命令执行时,产生错误信息,因为   maxordamt   字段的值大于   50。第二个   replace   命令没有产生错误,因为   maxordamt   的值小于或等于   50。    
   
  close   databases  
  set   path   to   (sys(2004)   +   'samples\data\')   &&   设置数据库的路径  
  open   database   testdata   &&   打开   testdata   数据库  
  use   customer   &&   打开   customer   表  
   
  create   trigger   on   customer   for   update   as   maxordamt   <=   50  
  on   error   &&   还原系统错误处理程序  
  replace   maxordamt   with   60   &&   显示错误信息  
  replace   maxordamt   with   50   &&   值是可接受的  
posted @ 2006-10-11 20:05 javaca88 阅读(363) 评论(0) 编辑

如果一个触发器在执行操作时引发了另一个触发器,而这个触发器又接着引发下一个触发器……这些触发器就是嵌套触发器。触发器可嵌套至 32 层,并且可以控制是否可以通过"嵌套触发器"服务器配置选项进行触发器嵌套。

如果允许使用嵌套触发器,且链中的一个触发器开始一个无限循环,则超出嵌套级,而且触发器将终止。

可使用嵌套触发器执行一些有用的日常工作,如保存前一触发器所影响行的一个备份。例如,可以在 titleauthor 上创建一个触发器,以保存由 delcascadetrig 触发器所删除的 titleauthor 行的备份。在使用 delcascadetrig 时,从 titles 中删除title_id PS2091 将删除 titleauthor 中相应的一行或多行。要保存数据,可在 titleauthor 上创建 DELETE 触发器,该触发器的作用是将被删除的数据保存到另一个单独创建的名为 del_save 表中。例如:

CREATE TRIGGER savedel
  ON titleauthor
FOR DELETE
AS
  INSERT del_save
  SELECT * FROM deleted

不推荐按依赖于顺序的序列使用嵌套触发器。应使用单独的触发器层叠数据修改。



说明  由于触发器在事务中执行,如果在一系列嵌套触发器的任意层中发生错误,则整个事务都将取消,且所有的数据修改都将回滚。在触发器中包含 PRINT 语句,用以确定错误发生的位置。


递归触发器
触发器不会以递归方式自行调用,除非设置了 RECURSIVE_TRIGGERS 数据库选项。有两种不同的递归方式:

直接递归
即触发器激发并执行一个操作,而该操作又使同一个触发器再次激发。例如,一应用程序更新了表 T3,从而引发触发器 Trig3。Trig3 再次更新表 T3,使触发器 Trig3 再次被引发。

间接递归
即触发器激发并执行一个操作,而该操作又使另一个表中的某个触发器激发。第二个触发器使原始表得到更新,从而再次引发第一个触发器。例如,一应用程序更新了表 T1,并引发触发器 Trig1。Trig1 更新表 T2,从而使触发器 Trig2 被引发。Trig2 转而更新表 T1,从而使 Trig1 再次被引发。

当将 RECURSIVE_TRIGGERS 数据库选项设置为 OFF 时,仅防止直接递归。若要也禁用间接递归,请将 nested triggers 服务器选项设置为 0。

示例
A. 使用递归触发器解决自引用关系
递归触发器的一种用法是用于带有自引用关系的表(亦称为传递闭包)。例如,表 emp_mgr 定义了:

一个公司的雇员 (emp)。


每个雇员的经理 (mgr)。


组织树中向每个经理汇报的雇员总数 (NoOfReports)。
递归 UPDATE 触发器在插入新雇员记录的情况下可以使 NoOfReports 列保持最新。INSERT 触发器更新经理记录的 NoOfReports 列,而该操作递归更新管理层向上其它记录的 NoOfReports 列。

USE pubs
GO
-- Turn recursive triggers ON in the database.
ALTER DATABASE pubs
  SET RECURSIVE_TRIGGERS ON
GO
CREATE TABLE emp_mgr (
  emp char(30) PRIMARY KEY,
   mgr char(30) NULL FOREIGN KEY REFERENCES emp_mgr(emp),
   NoOfReports int DEFAULT 0
)
GO
CREATE TRIGGER emp_mgrins ON emp_mgr
FOR INSERT
AS
DECLARE @e char(30), @m char(30)
DECLARE c1 CURSOR FOR
  SELECT emp_mgr.emp
  FROM   emp_mgr, inserted
  WHERE emp_mgr.emp = inserted.mgr

OPEN c1
FETCH NEXT FROM c1 INTO @e
WHILE @@fetch_status = 0
BEGIN
  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly
  WHERE emp_mgr.emp = @e                            -- added employee.

  FETCH NEXT FROM c1 INTO @e
END
CLOSE c1
DEALLOCATE c1
GO
-- This recursive UPDATE trigger works assuming:
--   1. Only singleton updates on emp_mgr.
--   2. No inserts in the middle of the org tree.
CREATE TRIGGER emp_mgrupd ON emp_mgr FOR UPDATE
AS
IF UPDATE (mgr)
BEGIN
  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Increment mgr's
  FROM inserted                            -- (no. of reports) by
  WHERE emp_mgr.emp = inserted.mgr         -- 1 for the new report.

  UPDATE emp_mgr
  SET emp_mgr.NoOfReports = emp_mgr.NoOfReports - 1 -- Decrement mgr's
  FROM deleted                             -- (no. of reports) by 1
  WHERE emp_mgr.emp = deleted.mgr          -- for the new report.
END
GO
-- Insert some test data rows.
INSERT emp_mgr(emp, mgr) VALUES ('Harry', NULL)
INSERT emp_mgr(emp, mgr) VALUES ('Alice', 'Harry')
INSERT emp_mgr(emp, mgr) VALUES ('Paul', 'Alice')
INSERT emp_mgr(emp, mgr) VALUES ('Joe', 'Alice')
INSERT emp_mgr(emp, mgr) VALUES ('Dave', 'Joe')
GO
SELECT * FROM emp_mgr
GO
-- Change Dave's manager from Joe to Harry
UPDATE emp_mgr SET mgr = 'Harry'
WHERE emp = 'Dave'
GO
SELECT * FROM emp_mgr
GO

以下是更新前的结果:

emp                            mgr                           NoOfReports
------------------------------ ----------------------------- -----------
Alice                          Harry                          2
Dave                           Joe                            0
Harry                          NULL                           1
Joe                            Alice                          1
Paul                           Alice                          0

以下为更新后的结果:

emp                            mgr                           NoOfReports
------------------------------ ----------------------------- -----------
Alice                          Harry                          2
Dave                           Harry                          0
Harry                          NULL                           2
Joe                            Alice                          0
Paul                           Alice                          0
posted @ 2006-10-11 20:04 javaca88 阅读(138) 评论(0) 编辑