讀者問題:Ajax 與 PlaceHolder 應用

摘要:讀者問題:Ajax 與 PlaceHolder 應用

問題

老師你好, 關於 Ajax 是否實現以下功能

我把PlaceHolder1放在UpdataPanel,想要動態增加TextBox放在PlaceHolder1裡頭;然後使用者輸入相關資訊,我也能讀到textbox的值.  接這使用者又按下"新增" 產生TextBox 放在PlaceHolder1,而之前在PlaceHolder1 鍵入的值 也完全保留~一直循這樣的動作 直到完成.  我試過很多遍,似乎Ajax "局部更新"還是無法達到類似功能.

不知道是原本就不能,還是有何小技巧呢?  thanks 忠實的讀者

解答

大家都知道,正由於網頁是無狀態的(Stateless),因此 ASP.NET 特別提供狀態管理(ViewState,以便網頁開發人員得以追蹤使用者的 UI 狀態。說穿了,這也不是什麼新技術,只不過利用隱藏的表單欄位來保存狀態。因此,我們將使用狀態管理來維護這些動態加入的控制項之狀態。

如圖表 1 所示,是網頁程式第一次執行的畫面,我們可以看到,網頁程式會建立一個具備  ASP.NET AJAX Control Toolkit 浮水印文字方塊(TextBoxWatermark功能的  TextBox  控制項,並於網頁的最一列與最後一列,顯示相關事件的時間。

 


圖表
1

 

 


圖表
2

 

 


圖表
3

 

 

每按下一次「新增 TextBox按鈕,便會自動加入一個新的 TextBox 控制項。當然,新加入的 TextBox 控制項也已經與 ASP.NET AJAX Control Toolkit 浮水印文字方塊(TextBoxWatermark建立關聯。於各個 TextBox 控制項中,輸入適當的資料,並按下「送出」按鈕之後,便可以看到網頁以非同步的方式,取得各個 TextBox 控制項的資料,並顯示在網頁上(如圖表2、圖表3所示)。

如圖表4所示者,是網頁的設計畫面。在頁面中,我們將 PlaceHolder 控制項放置於 UpdatePanel 控制項中,並將 UpdateMode 設定為 Conditional,以便當按下「新增 TextBox「送出」按鈕時,網頁以非同步方式局部更新該 UpdatePanel 控制項中的內容,也就是說,此舉得以讓 PlaceHolder 控制項中的內容被更新。


圖表
4

 

網頁的程式碼後置(Code-Behind)內容如下所列:

Option Strict On
' 匯入浮水印文字方塊(
TextBoxWatermark)所需的命名空間。
Imports AjaxControlToolkit

Partial Class _Default
  Inherits System.Web.UI.Page

  '
使用 HTML 的<br>標籤來斷行。
  Private br As LiteralControl = New LiteralControl("<br />")

  '
使用 HTML 的<hr>標籤來分隔。
  Private hr As LiteralControl = New LiteralControl("<hr />")

  Protected Sub
Page_Load(ByVal sender As Object, _
    ByVal e As System.EventArgs) _
    Handles Me.Load
    '
檢查是否為
PostBack
    If IsPostBack Then
      Label1.Text = "
PostBack 觸發的,於 " & Now.ToString()
      If ViewState("Mode").ToString() = "Add" AndAlso _
        ViewState("ControlsAdded") Is Nothing Then
        '
動態加入網頁初始時,所需的控制項。

        AddControls()
      End If

      '
動態加入
TextBox 控制項。
      If (CInt(ViewState("TextBoxID")) > 0) Then
        For intLoop As Integer = 1 To CInt(ViewState("TextBoxID"))
          AddNewTextBox(intLoop.ToString())
        Next
      End If
    Else
      Label1.Text = "
PostBack 觸發的,於 " & Now.ToString()
      ViewState("Mode") = "Init"
      AddControls()
    End If
  End Sub

  ' 覆寫載入狀態的動作,以便管理狀態。

  Protected Overrides Sub LoadViewState(ByVal savedState As Object)
    MyBase.LoadViewState(savedState)
    If CType(ViewState("ControlsAdded"), Boolean) = True Then
      AddControls()
    End If
  End Sub

  '
建立網頁初始時的控制項。
  Private Sub AddControls()
    '
建立 TextBox 控制項。
    Dim tb As New TextBox()
    tb.ID = "TB_0"
    tb.CssClass = "cssTextBox"

    '
建立浮水印文字方塊。
    Dim tbwe As New TextBoxWatermarkExtender()
    tbwe.ID = "TBWE_0"
    tbwe.TargetControlID = "TB_0"
    tbwe.WatermarkText = "
請輸入資料...(0)"
    tbwe.WatermarkCssClass = "cssWatermark"

    '
建立「新增 TextBox」按鈕。

    Dim btnAdd As New Button()
    btnAdd.Text = "
新增 TextBox"
    btnAdd.ID = "AddButton"
    btnAdd.Font.Bold = True
    btnAdd.BackColor = Drawing.Color.Blue
    btnAdd.ForeColor = Drawing.Color.White

    ' 指派「新增
 TextBox」按鈕的 Click 事件處理常式。
    AddHandler btnAdd.Click, AddressOf btnAdd_Click

    '
建立「送出」按鈕。
    Dim btnSend As New Button()
    btnSend.Text = "
送出"
    btnSend.ID = "SendButton"
    btnSend.Font.Bold = True
    btnSend.BackColor = Drawing.Color.Yellow
    btnSend.ForeColor = Drawing.Color.Black

    ' 指派「送出」按鈕的
Click 事件處理常式。
    AddHandler btnSend.Click, AddressOf btnSend_Click

    '
將所建立的控制項加至 PlaceHolder 控制項裡。
    PlaceHolder1.Controls.Add(tb)
    PlaceHolder1.Controls.Add(tbwe)
    PlaceHolder1.Controls.Add(hr)
    PlaceHolder1.Controls.Add(btnAdd)

    '
插入空白字元,以免兩個按鈕相連在一起。
    For i As Integer = 1 To 10
      PlaceHolder1.Controls.Add(New LiteralControl(" "))
    Next

    PlaceHolder1.Controls.Add(btnSend)
    PlaceHolder1.Controls.Add(br)

    ' 確認已經動態加入控制項。

    ViewState("ControlsAdded") = True
  End Sub

  ' 建立
TextBox 控制項。
  Private Sub AddNewTextBox(ByVal ControlID As String)
    Dim tb As New TextBox()
    tb.ID = "TB_" & ControlID

    '
建立 AJAX Control Toolkit 浮水印文字方塊(TextBoxWatermark)。
    Dim tbwe As New TextBoxWatermarkExtender()
    tbwe.ID = "TBWE_" & ControlID
    tbwe.TargetControlID = "TB_" & ControlID
    tbwe.WatermarkText = "
請輸入資料...(" & ControlID & ")"
    tbwe.WatermarkCssClass = "cssWatermark"

    '
TextBox 加入特定的位置上。
    PlaceHolder1.Controls.AddAt(CInt(ControlID), tb)
    PlaceHolder1.Controls.Add(tbwe)
  End Sub

  ' 「新增 TextBox」按鈕的
Click 事件處理常式。
  Protected Sub btnAdd_Click(ByVal sender As Object, _
    ByVal e As System.EventArgs)
    '
指定所按下的按鈕模式。

    ViewState("Mode") = "Add"

    '
為了避免 TextBox ID 相同,使用 ViewState 來記錄目前的 TextBox ID
    If ViewState("TextBoxID") Is Nothing Then
      ViewState("TextBoxID") = 1
    Else
      '
刻意使用 ViewState Add 方法。
      ViewState.Add("TextBoxID", CInt(ViewState("TextBoxID")) + 1)
    End If

    AddNewTextBox(ViewState("TextBoxID").ToString())
  End Sub

  ' 「送出」按鈕的
Click 事件處理常式。
  Protected Sub btnSend_Click(ByVal sender As Object, _
    ByVal e As System.EventArgs)
    '
指定所按下的按鈕模式。

    ViewState("Mode") = "Send"

    Const hrColor As String = _
      "<hr width='300px' color='cyan' align='left' size='5' />"

    '
建立 Label 控制項,以便顯示於 TextBox 所輸入的資料。
    Dim lbl As New Label()
    lbl.ID = "lblResult"
    lbl.Text = "<br />" & hrColor

    '
取得每個按鈕的內容。
    Dim tb As New TextBox()
    For intLoop As Integer = 0 To CInt(ViewState("TextBoxID"))
      tb = CType(PlaceHolder1.FindControl("TB_" & intLoop), TextBox)
      lbl.Text &= tb.ID & "
的內容為:" & tb.Text & "<br />"
    Next

    lbl.Text &= hrColor & "<br />"

    PlaceHolder1.Controls.Add(lbl)
  End Sub
End Class

感謝您的支持。

 

章立民研究室 2007/06/01