posts - 65, comments - 283, trackbacks - 18, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

2008年5月26日

JavaScript对象标记法,英文名称 JavaScript Object Notation(简称JSON),是一种文字格式标记法,相较于 XML 而言,JSON 明显更为简洁。而 JSON 这种精简的数据表示方式,非常适合用于 AJAX 的数据转输。
我们使用「BasePage 撰写 PageCommand 事件 (使用 CallBack)」一文中提及的 PageCommand 来执行 AJAX,并在 PageCommand 事件中回传 JSON 字符串,客户端以 JavaScript 取得回传的 JSON 对象。

在页面上放置一个 Button 来执行 CallBack PageCommand,Button.OnClientClick 使用 GetCallBackPageCommandEventReference 方法取得执行 PageCommand 事件的客户端指令码,客户端以 ReceiveServerData JavaScript 函式来接收伺服端的回传数据。当引发 PageCommand 时,透过 e.CallbackResult 属性来回传 JSON 字符串给客户端的 ReceiveServerData 函式。

 

aspx.vb 的程序代码如下

Partial Class Default
    
Inherits Bee.Web.TBBasePage

    
Protected Sub Page_Load(ByVal sender As ObjectByVal e As System.EventArgs) Handles Me.Load
        Button1.OnClientClick 
= Me.BeeScript.GetCallBackPageCommandEventReference("JSON""""ReceiveServerData"""& ";return false;"
    
End Sub

    
Protected Sub Page_PageCommand(ByVal sender As ObjectByVal e As TBBasePage.PageCommandEventArgs) Handles Me.PageCommand
        e.CallbackResult 
= "{'myCats': [ {'name': 'Hero', 'age': 5, 'color': 'silver' }, {'name': 'Euro', 'age': 2, 'color': ['brown', 'white', 'black']}]}"
    
End Sub
End Class

 

客户端负责接收 CallBack 伺服端回传数据的 ReceiveServerData 函式如下所示,会将传回的 JOSN 字符串使用 eval 函式来转换为 JSON 对象。

    <script type="text/jscript">
    
function ReceiveServerData(value){
        
var obj = eval ("(" + value + ")");
        alert(
'I have ' + obj.myCats.length + ' cats.');
        alert(obj.myCats[
0].name);
        alert(obj.myCats[
1].name);
    }
    
</script>

 

执行结果如下


 

 

 

参考数据:
http://www.json.org/
http://caterpillar.onlyfun.net/Gossip/AjaxGossip/JSON.html

posted @ 2008-08-21 06:24 jeff377 阅读(344) | 评论 (0)编辑

一般我们可以使用 FindControl 去找到子控件,但是若我们需要去找指定型别的父控件要如何寻找呢?例如去寻找指定 TextBox 控件所属的 UpdatePanel 父控件。针对上述的需求,以下将提供解决方式。
在 Control 有一个 Parent 属性,表示该控件的父控件,所以我们可以利用递归方式逐层往上判断 Parent 属性是否为指定型别,符合的话传回该父控件。以下的 FindParent 函式就是在寻找指定型别的父控件。
    ''' <summary>
    
''' 尋找指定型別的父控制項。
    
''' </summary>
    
''' <param name="Control">控制項。</param>
    
''' <param name="Type">欲尋找的型別。</param>
    Public Shared Function FindParent(ByVal Control As Control, ByVal Type As System.Type) As Control
        
If Control.Parent Is Nothing Then
            
Return Nothing
        
Else
            
If Type.IsInstanceOfType(Control.Parent) Then
                
Return Control.Parent
            
Else
                
Return FindParent(Control.Parent, Type)
            
End If
        
End If
    
End Function

 

如果要寻找 TextBox 所属的 UpdatePanel 则可以撰写如下程序代码即可。

 

        Dim oParent As Control
        oParent 
= FindParent(TextBox1, GetType(UpdatePanel))

posted @ 2008-08-20 22:12 jeff377 阅读(40) | 评论 (0)编辑

     摘要: 序列化是将对象状态转换为可保存或可传输格式的处理序。序列化的反面是还原序列化,它可以将数据流转换成对象。在 .NET 程序中常用的序列化方式如下表所示。 序列化类别 说明 .NET Framework 版本 XmlSerializer XML 序列化 2.0 SoapFormatter SOAP 序列化 2.0 BinaryFormatter 二进制序列化 2.0 DataContractSeri... 阅读全文

posted @ 2008-08-19 23:54 jeff377 阅读(96) | 评论 (0)编辑

     摘要: 前言在「BasePage 撰写 PageCommand 事件」一文中说明如何在 PostBack 时引发 PageCommand 事件,本文将依此继续扩展,让 CallBack 也同样可以引发相同的 PageCommand 事件。一般的 PostBack 会将整个页面的数据至伺服端,当伺服端处理完毕时,也是整个页面 Render 回传给客户端呈现;CallBack 是传开发人员定义的数据至伺服端,... 阅读全文

posted @ 2008-08-03 00:38 jeff377 阅读(751) | 评论 (4)编辑

     摘要: 前言在「撰写自用 Confirm 方法」一文中提到的「案例三:先执行伺服端程序再弹出询问讯息,依客户端响应再接续执行」,当客户端响应询问讯息后,会呼叫 __doPostBack() 函式来产生 PostBack 的动作,页面再自行判断 Me.Request.Form("__EVENTTARGET") 及 Me.Request.Form("__EVENTARGUMENT") 来处理后序的作业。可是这... 阅读全文

posted @ 2008-08-02 10:06 jeff377 阅读(940) | 评论 (3)编辑

     摘要: 前言上一篇「让 ASP.NET 也可以使用 MsgBox 方法」文章中提到如何封装 JavaScript 的 alert 方法,另一个常使用在客户端处理「询问讯息」的就是 JavaScript 的 confirm 方法,在此篇文章我们将撰写自用的 Confirm 方法,使页面的程序代码尽量不要直接去撰写 JavaScript 程序代码,以增加系统的维护性。程序实作我们将使用「撰写自用的 Scrip... 阅读全文

posted @ 2008-08-01 08:03 jeff377 阅读(1813) | 评论 (3)编辑

使用 VB6 或 VB.NET 的开发人员,一定常会使用到 MsgBox 这个函式来显示讯息,如果使用 VB.NET 在开发 ASP.NET 程序,会发现似乎 MsgBox 这个函式好像可以使用,就直接使用 MsgBox 来显示讯息。

 

MsgBox("这是讯息")

 

在 VS 开发环境中执行程序,MsgBox 函式好像也可以正常显示讯息;可是一旦网站发布出去后,就会发现 MsgBox 函式失效了。这是什么原因呢?MsgBox 函式是伺服端的语言,而客户端只能透过浏览器解析 HTML 及 JavaScript,所以 MsgBox 函式是无法使用在 ASP.NET 的程序,只能在开发侦错时使用。在 ASP.NET 中,要在客户端显示讯息正确的方法是要使用 RegisterStartupScript 方法来输出 JavaScript 的 alert 函式。

 

ScriptManager.RegisterStartupScript(MeMe.GetType(), "alert""alert('这是讯息')"True)    
 
或    
   
Me.ClientScript.RegisterStartupScript(Me.GetType(), "alert""alert('这是讯息')"True)

 

是不是觉得在 ASP.NET 中要显示讯息麻烦多了,能否让 ASP.NET 中也可以使用 MsgBox 来显示讯息呢?其实方法很简单,就是自己写一个 MsgBox 方法就好了,就可以延用以前习惯的 MsgBox 来显示讯息。我们在 BasePage 中撰写 MsgBox 方法,这个 MsgBox 方法还处理消息正文中含「单引号」及「换行」的部分,将这些特殊字符串转换为对应的 JavaScript 跳脱字符。

 

    ''' <summary>
    
''' 弹出提示讯息。
    
''' </summary>
    
''' <param name="Message">消息正文。</param>
    Public Sub MsgBox(ByVal Message As String)
        
Dim sScript As String
        
Dim sMessage As String

        sMessage 
= Strings.Replace(Message, "'""\'"'处理单引号
        sMessage = Strings.Replace(sMessage, vbNewLine, "\n"'处理换行
        sScript = String.Format("alert('{0}');", sMessage)
        ScriptManager.RegisterStartupScript(
MeMe.GetType(), "alert", sScript, True)
    
End Sub

 

所有继承 BasePage 的页面都可以使用 MsgBox 方法来显示讯息。

 

    Protected Sub Button1_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button1.Click
        
Dim sMessage As String

        sMessage 
= "alert 讯息换行测试" & vbNewLine & "测试'单引号' "
        
MsgBox(sMessage)
    
End Sub

 

 

備註:處理 JavaScript 的相關函式,筆者比較建議使用「撰寫自用的 ScriptManager 來管理用戶端指令碼」一文中提供的方式來處理,所以可以將 MsgBox 方法撰寫在該文中的 TBScriptManager 類別。

posted @ 2008-08-01 07:54 jeff377 阅读(316) | 评论 (6)编辑

Strings.Replace 方法是用在字符串取代常用方法,常用的呼叫方式如下

Strings.Replace("原字符串","寻找的字符串","取代的字符串"

可是最近发现一个问题,就是当原字符串为 String.Empty (空字符串) 时,其传回值会为 Nothing。
如下程序代码会发生「参考的对象具有 'Nothing' 的值」的错误讯息。因为原字符串为空字符串,透过 Strings.Replace 方法会传回 Nothing,所以会造成这个错误。


Strings.Replace(string.Empty,"@","").Length

所以在使用 Strings.Replace 方法要特别注意这点,防止发生异常的错误。而我的作法就是撰写另一个 StrReplace 方法来取代 Strings.Replace 方法,防止这类错误。

        ''' <summary>
        
''' 字符串取代。
        
''' </summary>
        
''' <param name="Expression">原始字符串。</param>
        
''' <param name="Find">搜寻的子字符串。</param>
        
''' <param name="Replacement">取代的子字符串。</param>

        Public Shared Function StrReplace(ByVal Expression As String, _
            
ByVal Find As StringByVal Replacement As StringAs String
            
If String.IsNullOrEmpty(Expression) Then
                
Return String.Empty
            
Else
                
Return Replace(Expression, Find, Replacement)
            
End If
        
End Function

posted @ 2008-07-11 00:30 jeff377 阅读(165) | 评论 (0)编辑

     摘要: 摘要之前在「Calendar 动态产生子控件的 Event Handler」一文中有提到如何处理 Calendar 在 DayRender 事件动态产生按钮的事件处理,文中最后有提及,若 Calendar 控件有类似 GridView 控件中有 RowCommand 事件,在使用上就可以更简化。所以本文将扩展 Calendar 控件,新增 DayCommand 事件,就动态产生的按钮可以可以引发 ... 阅读全文

posted @ 2008-06-22 20:00 jeff377 阅读(1485) | 评论 (0)编辑

摘要
在网络上看到很多 GridView 内含子 GridView 的范例,虽然方法不同不过程序代码都有点小复杂,想说难道没有更简单易懂的方法吗?
在此文章中将用十几行的程序代码,就教你快速学会并搞定这种 Master-Detail GridView 的需求。
 
程序代码实作
我们以 Northwind 数据库为例,首先在页面上放置二组 GridView+SqlDataSoruce,分别系结至 [Orders] 、[Order Details] 这二个资料表。



我們先來看一下它的程式碼及執行結果,後續再做進一步的詳細說明。
我們只要在 GridView 的 RowDataBound 事件撰寫下面十幾行的程式碼就完成了,不要懷疑這已經是全部的程式碼。

    Protected Sub GridView1_RowDataBound(ByVal sender As ObjectByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
        
If (e.Row.RowState And DataControlRowState.Selected) = DataControlRowState.Selected Then
            
Dim oRow As New GridViewRow(0-1, DataControlRowType.DataRow, e.Row.RowType)
            GridView2.Visible 
= True
            GridView2.DataBind()
            
Dim sHTML As String = Bee.Web.WebFunc.ControlToHTML(GridView2)
            GridView2.Visible 
= False
            
Dim oCell As New TableCell
            oCell.Text 
= sHTML
            oCell.ColumnSpan 
= e.Row.Cells.Count
            oRow.Cells.Add(oCell)
            e.Row.Parent.Controls.AddAt(e.Row.RowIndex 
+ 2, oRow)
        
End If
    
End Sub

执行程序,选取 GridView 的某一数据列,就会展开其子 GridView 。执行换页动作,一样可以正常展开子 GridView。





接下来说明这个范例的一些细节,Master GridView 系结 [Orders] 数据表,设定 DataKeyNames="OrderID",当选取某笔数据时,GridView 的 SelectedValue 就是该笔数据的 OrderID 字段值。另外设定 GridView 的 EnableViewState="False",这个设定主要是让 GridView 选取时都会重新做 DataBind 的动作。

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
            DataKeyNames
="OrderID" DataSourceID="SqlDataSource1" EmptyDataText="沒有資料錄可顯示。"
            ForeColor
="#333333" GridLines="None" AllowPaging="True" EnableViewState="False">

再来就是 Detail GridView 系结 [Order Details] 数据表,一样设定 GridView 的 EnableViewState="False",且设定 Visible="False",也就是初始状态 Detail GridView 是隐藏的。

        <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" BackColor="LightGoldenrodYellow"
            BorderColor
="Tan" BorderWidth="1px" CellPadding="2" DataKeyNames="OrderID,ProductID"
            DataSourceID
="SqlDataSource2" EmptyDataText="沒有資料錄可顯示。" ForeColor="Black" GridLines="None" Visible="False" EnableViewState="False">


Detail GridView 所系结的 SqlDataSource 控件,将其 SelectParameters 的 @OrderID 参数关连至 Master GridView 的 SelectedValue。




            <SelectParameters>
                
<asp:ControlParameter ControlID="GridView1" Name="OrderID" PropertyName="SelectedValue"
                    Type
="Int32" />
            
</SelectParameters>


再来还有一个重要步骤,就是在 aspx 程序代码中,要设定 Page 的 EnableEventValidation="false",因为我们动态将 Detail GridView Render 出来插入 Master GridView 中,整个控件阶层都被异动,这样会造成事件验证失败。


<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default5.aspx.vb" Inherits="Default5" EnableEventValidation="false" %>


另外在 Master GridView 的 RowDataBound 事件中,有一个 ControlToHTML 方法是取得 Detail GridView 的 HTML 码,这个方法可以参考笔者另一篇「使用 BasePage 来解决 GridView 执行 RenderControl 产生的错误」文章有详细说明。

Dim sHTML As String = Bee.Web.WebFunc.ControlToHTML(GridView2)

 

posted @ 2008-06-21 01:51 jeff377 阅读(2461) | 评论 (18)编辑

若要计算二个日期经过几月又几天,需要考虑期间每个月份的天数,每个月的天数是不一样的。
所以我们可以先计算经过几个月,然后把起始日期累加异差月份数,再计算差异天数。

        Dim oDate1 As Date = Date.Parse("2008/5/1")
        
Dim oDate2 As Date = Date.Parse("2008/7/10")

        
'先算月份
        Dim iMonths As Integer = DateDiff(DateInterval.Month, oDate1, oDate2)
        
'再算天数
        Dim iDays As Integer = DateDiff(DateInterval.Day, DateAdd(DateInterval.Month, iMonths, oDate1), oDate2)

        
MsgBox(String.Format("经过{0}月{1}天", iMonths, iDays))

posted @ 2008-06-18 20:01 jeff377 阅读(176) | 评论 (0)编辑

     摘要: 我们常用 Hashtable 来描述索引键/值组的集合,Hashtable 的键值是区分大小写的。DimoHashAsNewHashtable()DimbIsFindAsBooleanoHash.Add("A","ValueA")oHash.Add("B","ValueA")oHash.Add("C","ValueA")bIsFind=oHash.Contains("a")'鍵值"a"不存在bIs... 阅读全文

posted @ 2008-06-17 00:54 jeff377 阅读(63) | 评论 (0)编辑

摘要
一般执行新增/修改完毕准备异动数据库前,通常会做一层数据正确性检查的动作;当我们使用 GridView 系结 SqlDataSoruce 来呈现数据,若 GridView 进行数据编辑存盘前也要做字段值的检查应该在如何做呢?应该在那个控件的那个事件去处理这个检查动作呢?

程序说明及实作
首先在页面上放置一个 GridView 及 SqlDataSource 控件,GridView 设为可编辑状态。





当 GridView 编辑储存时,我们要先做一些字段值正确性的检查动作,以下的范例为测试示范,只判断 LastName 字段不得为空,这种必填字段的判断一般只要使用 RequiredFieldValidator 控件在 Client 端即可。

方法一:在 GridView 的 RowUpdating 事件处理字段检查
GridView 在编辑储存前会引发 RowUpdating 事件,我们可以在此事件中处理字段检查,字段检查的程序代码如下。当字段检查不合法时,设定 e.Cancel = True 即可中断数据更新的动作。

    Protected Sub GridView1_RowUpdating(ByVal sender As ObjectByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
        
Dim sScript As String

        
If String.IsNullOrEmpty(e.NewValues.Item("LastName")) Then
            sScript 
= "alert('LastName 欄位不得為空')"
            
Me.ClientScript.RegisterStartupScript(Me.GetType, "error", sScript, True)
            e.Cancel 
= True
        
End If
    
End Sub

执行程序,故意将 LastName 清空,然后按 [更新] 钮进行储存,字段检查的动作就被执行了。



方法二:在 SqlDataSource 的 Updating 事件处理字段检查
对于 SqlDataSource 来说,编辑数据异动数据库之前,会引发 SqlDataSource 的 Updating 事件,字段检查的程序代码如下。当字段检查不合法时,设定 e.Cancel = True 即可中断数据更新的动作,这种方式的执行结果跟上个作法一样。

    Protected Sub SqlDataSource1_Updating(ByVal sender As ObjectByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs) Handles SqlDataSource1.Updating
        
Dim sScript As String
        
If String.IsNullOrEmpty(e.Command.Parameters("@LastName").Value) Then
            sScript 
= "alert('LastName 欄位不得為空')"
            
Me.ClientScript.RegisterStartupScript(Me.GetType, "error", sScript, True)
            e.Cancel 
= True
        
End If
    
End Sub


结论

以上的说明可以知道在 GridView.RowUpdating 事件及 SqlDataSource.Updating 事件都可以处理字段检查,在那个地方处理比较好呢?答案是由数据源头的 SqlDataSource 控件来处理会比较好,主要原因如下:
1.尽量不要在 UI 控件处理数据验证动作,因为一旦更换其它 UI 控件(如更换其它厂商开发的 GridView 控件),程序代码就又要改写。
2.不同的 UI 控件系结 SqlDataSource 控件,都可以适用相同方法。例如 FormView 及 GridView 不同的 UI 控件,都可以在 SqlDataSource.Updating 统一处理。
3.如果直接使用 SqlDataSource.Update 方法去执行更新动作,不会引发 UI 控件的相关事件,但是一样会引发 SqlDataSource.Updating 事件。

posted @ 2008-06-13 15:54 jeff377 阅读(1304) | 评论 (6)编辑

     摘要: 承上一篇「SqlDataSource 执行数据筛选」中,可以知道 SqlDataSource 的 SelectCommand 属性值不会被保留在 ViewState 中,所以我们在 Page 中覆写 LoadViewState 及 SaveViewState 方法来维护 SqlDataSource 的 SelectCommand 属性值。不过这样每次动态设定 SelectCommand 属性值都要... 阅读全文

posted @ 2008-06-12 19:54 jeff377 阅读(1286) | 评论 (0)编辑

     摘要: 摘要使用 SqlDataSource 控件可以很方便的与 UI 控件 (如 GridView、FormView) 系结来呈现数据,若需要针对 SqlDataSource 做数据筛选时,最直觉的方式就是去修改 SqlDataSoruce.SelectCommand 的 SQL 命令来执行数据筛选,这样设定的呈现结果感觉是正确的,数据真得依设定的条件来筛选过滤。可以当 UI 控件重新做 DataBin... 阅读全文

posted @ 2008-06-11 21:32 jeff377 阅读(1249) | 评论 (7)编辑

     摘要: 摘要若窗体(页面)具有「执行、新增、修改、删除」等操作权限控管,可以使用列举来描述使用者在该窗体的权限,详细的作法可以参考下面的「Enum 的设计与应用 - 简易权限设计」这篇文章。在此我们将利用这种列举的方式来描述窗体权限,并由 BasePage 来处理窗体权限的控管。程序说明及实作首先定义 EFormActions 列举,来描述窗体操作权限。/**/'''<summary>'''窗... 阅读全文

posted @ 2008-06-10 22:56 jeff377 阅读(2612) | 评论 (17)编辑

     摘要: 摘要 在 ASP.NET 中,ObjectDataSoruce 控件是实现三层式的重要关键,我们可以透过 ObjectDataSoruce 控件使用的自订中间层商务对象。不过一般找到的范例都是直接系结中间层商务对象,虽然范例通常写得相当符合对象导向,可是在实际运用上有下列几个问题。问题一:维护性不佳例如 Employee 商务对象的 Update 方法,可能有下列二种写法 [写法一] Update... 阅读全文

posted @ 2008-06-06 14:41 jeff377 阅读(1792) | 评论 (14)编辑

Calendar 控件可以透过 SelectedDate 属性来取目前选取的日期,不过它没有提供日期复选的功能。为达到日期复选的功能,我们在 DayRender 事件中,为每一个日期储存格加入一个 HtmlInputCheckBox 控件做日期选取,当 PostBack 时再透过 Request.Form 来取得客户端复选的日期。

Partial Class _Default
    
Inherits System.Web.UI.Page

    
Protected Sub Calendar1_DayRender(ByVal sender As ObjectByVal e As System.Web.UI.WebControls.DayRenderEventArgs) Handles Calendar1.DayRender
        
Dim oCheckBox As New HtmlControls.HtmlInputCheckBox()

        oCheckBox.Value 
= e.Day.Date.ToShortDateString
        oCheckBox.ID 
= "SelectDate"
        e.Cell.Controls.Clear()
        e.Cell.Controls.Add(oCheckBox)
        e.Cell.Controls.Add(
New LiteralControl(e.Day.DayNumberText))
    
End Sub


    
Protected Sub Button1_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button1.Click
        
Me.Response.Write("SelectDate: " & Me.Request.Form("SelectDate"))
    
End Sub

End Class

执行程序,勾选了6/2、6/10、6/18 三个日期。


当按下按钮产生 PostBack 时,透过 Request.Form 即可取得复选的日期。

posted @ 2008-06-04 21:45 jeff377 阅读(288) | 评论 (1)编辑

     摘要: 摘要在「GridView 加入自动编号字段」一文有提到如何在 GridView 中利用 TemplateField 来加入自动编号;本文将改用另一种方式,利用继承 DataControlField 来撰写自动编号字段,若 GridView 需要自动编号字段时只需加入字段即可。TBSerialNumberField 字段继承 DataControlField 命名为 TBSerialNumberFi... 阅读全文

posted @ 2008-05-29 22:02 jeff377 阅读(1625) | 评论 (7)编辑

     摘要: 摘要承上篇「扩展 CheckBoxList 控件 - 系结复选项目」中以整数值来描述复选项目,本文将以另一种方式,利用 Item 的 Value 或 Text 属性来描述复选项目,每个被勾选的项目,会将其 Value 或 Text 属性值,以逗点分隔的方式被记录下来。例如选项一.Value = 1选项二.Value = 2选项三.Value = 3选项四.Value = 4当复选了「选项一」及「选... 阅读全文

posted @ 2008-05-27 09:23 jeff377 阅读(1290) | 评论 (4)编辑

     摘要: 摘要CheckBoxList 控件是使用在项目复选的状态,我们可以使用一个整数值来描述复选项目,项目值以 2 的 N 次方来描述。例如选项一 = 2^0 = 1选项二 = 2^1 = 2选项三 = 2^2 = 4选项四 = 2^3 = 8... 依此类推当复选了「选项一」及「选项三」,则复选值为 1+4=5。当复选了「选项二」及「选项四」,则复选值为 2+8=10。若要使用上述的方式来描述复选项目... 阅读全文

posted @ 2008-05-26 08:10 jeff377 阅读(1509) | 评论 (5)编辑