[原創]FineUI秘密花園(二十八) — 窗體控件概述(下)


本篇文章會繼續講解窗體控件的使用。

 

表格與編輯窗體


表格與編輯窗體的交互在項目中經常需要用到,為此FineUI專門為表格控件擴展了WindowField列,下面是一個典型的例子:

   1:  <ext:Grid ID="Grid2" Title="Grid2" PageSize="80" ShowBorder="false" AllowPaging="true"
   2:      OnPageIndexChange="Grid2_PageIndexChange" ShowHeader="False" runat="server" EnableCheckBoxSelect="True"
   3:      DataKeyNames="Id,Name" OnSort="Grid2_Sort" EnableRowNumber="True">
   4:      <Columns>
   5:          // 省略其他列...
   6:          <ext:WindowField TextAlign="Center" Width="60px" WindowID="Window1" Icon="Pencil"
   7:              ToolTip="編輯" DataIFrameUrlFields="Id,Name" DataIFrameUrlFormatString="../grid/grid_iframe_window.aspx?id={0}&name={1}"
   8:              Title="編輯" IFrameUrl="~/alert.aspx" />
   9:      </Columns>
  10:  </ext:Grid>
  11:                 
  12:  <ext:Window ID="Window1" Title="彈出窗體" Hidden="true" EnableIFrame="true" IFrameUrl="about:blank"
  13:      EnableMaximize="true" Target="Top" EnableResize="true" runat="server" OnClose="Window1_Close"
  14:      IsModal="true" Width="750px" EnableConfirmOnClose="true" Height="550px">
  15:  </ext:Window>


表格控件WindowField列有如下屬性需要特別關注:

  • WindowID:點擊此字段彈出的窗體ID
  • DataIFrameUrlFields:綁定到窗體IFrame地址的字段名稱列表
  • DataIFrameUrlFormatString:綁定到窗體IFrame地址的字段格式化字符串

還有其他一些屬性我們可能會用到:

  • UrlEncode:對每個綁定到IFrame地址的字段進行URL編碼(默認為true)
  • DataWindowTitleField:綁定到窗體標題的字段名稱
  • DataWindowTitleFormatString:綁定到窗體標題的字段格式化字符串
  • Enabled:是否可用(如果不可用,則會被渲染為靜態文本)
  • IFrameUrl:窗體IFrame地址
  • Title:窗體標題
  • Icon:窗體圖標
  • IconUrl:窗體圖標地址

其中UrlEncode屬性用來對地址參數進行編碼,比如本例中Major可能是“材料科學學院”,則生成的IFrame地址為 http://gsa.ustc.edu.cn/search?q=%E6%9D%90%E6%96%99%E7%A7%91%E5%AD%A6%E5%AD%A6%E9%99%A2

如果作為IFrame地址的字段包含空格、中文或者其他特殊字符,則這個屬性有助於生成瀏覽器可用的有效鏈接地址。


Window控件需要特別注意的屬性是EnableIFrame、IFrameUrl,如果需要在窗體關閉進行處理還需要注冊OnClose事件處理函數(CloseAction屬性的默認值是HidePostBack,不需要特別設置)。
由於默認窗體IFrame中不需要加載任何頁面,所以設置IFrameUrl為about:blank.


彈出編輯窗體時的界面效果:

image

 

子窗體與父窗體傳值


這里的子窗體指的是包含IFrame的彈出子窗體,由於子窗體包含的頁面和父窗體屬於兩個不同的頁面,這就涉及Asp.Net兩個頁面如何傳值的問題。

  • 父頁面向子頁面傳值:這個比較簡單,一般通過地址欄參數傳遞,比如父頁面是列表頁面list.aspx,編輯某一條目時地址為edit_item.aspx?id=322
  • 父頁面向子頁面傳值:
    • 臨時Session,在關閉子頁面之前,將要保存的數據存入Session中,Session("edit_result1") = "1111";  然后在父頁面中獲取此保存的值(需要刷新或者回發父頁面)Session("edit_result1").ToString()
    • 臨時Cookie,方法同Session,只不過Cookie是將數據保存在客戶端而不是服務器,但是有大小限制
    • JavaScript傳值,其實臨時Session和臨時Cookie都不是好的解決辦法,不僅性能有問題而且編碼復雜。由於子頁面和父頁面位於相同的域名下(不違反JavaScript的同源策略),所以可以直接在子頁面中查找父頁面的表單字段,並將結果保存到父頁面的表單字段中。

FineUI充分理解這種需求,並提供了方便的函數來幫助我們在父窗體向子窗體傳值,大致步驟如下:

  1. 告訴子窗體,父窗體中可以被作為接受結果數據的表單字段有哪些
  2. 打開子窗體
  3. 用戶操作后得到結果,將結果保存到父窗體中接受數據的表單字段
  4. 關閉子窗體

下面通過一個示例來認識這一過程:

父頁面代碼:

   1:  <ext:SimpleForm ID="SimpleForm1" Title="表單" EnableBackgroundColor="true" BodyPadding="5px"
   2:      runat="server" Width="500px" EnableCollapse="True">
   3:      <Items>
   4:          <ext:TextBox Label="你所在的省份" ID="TextBox1" runat="server">
   5:          </ext:TextBox>
   6:          <ext:Button ID="Button1" EnablePostBack="false" runat="server" Text="從列表中選擇">
   7:          </ext:Button>
   8:      </Items>
   9:  </ext:SimpleForm>
  10:   
  11:  <ext:Window ID="Window1" Title="編輯" Popup="false" EnableIFrame="true" runat="server"
  12:      EnableMaximize="true" EnableResize="true" Target="Parent" OnClose="Window1_Close"
  13:      IsModal="True" Width="750px" Height="450px">
  14:  </ext:Window>

 

 

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          Button1.OnClientClick = Window1.GetSaveStateReference(TextBox1.ClientID)
   6:              + Window1.GetShowReference("./passvalue_iframe_iframe.aspx");
   7:      }
   8:  }
   9:   

界面效果:

image


子頁面代碼:

   1:  <ext:SimpleForm ID="SimpleForm1" ShowBorder="false" ShowHeader="false" Title="SimpleForm"
   2:      EnableBackgroundColor="true" BodyPadding="5px" runat="server" EnableCollapse="True">
   3:      <Items>
   4:          <ext:DropDownList ID="ddlSheng" Label="請選擇省份" ShowRedStar="true" runat="server" AutoPostBack="true"
   5:              OnSelectedIndexChanged="ddlSheng_SelectedIndexChanged">
   6:          </ext:DropDownList>
   7:      </Items>
   8:  </ext:SimpleForm>
   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          BindSheng();
   6:      }
   7:  }
   8:   
   9:  private void BindSheng()
  10:  {
  11:      ddlSheng.DataSource = SHENG_JSON;
  12:      ddlSheng.DataBind();
  13:   
  14:      ddlSheng.Items.Insert(0, new ListItem("選擇省份", "-1"));
  15:  }
  16:   
  17:  protected void ddlSheng_SelectedIndexChanged(object sender, EventArgs e)
  18:  {
  19:      if (ddlSheng.SelectedValue != "-1")
  20:      {
  21:          PageContext.RegisterStartupScript(ActiveWindow.GetWriteBackValueReference(ddlSheng.SelectedValue) + ActiveWindow.GetHideReference());
  22:      }
  23:  }

 

對比前面介紹的四個步驟,我們來看下分別對應的代碼:

  1. 告訴子窗體,父窗體中可以被作為接受結果數據的表單字段有哪些:Window1.GetSaveStateReference(TextBox1.ClientID)
  2. 打開子窗體:Window1.GetShowReference("./passvalue_iframe_iframe.aspx")
  3. 用戶操作后得到結果,將結果保存到父窗體中接受數據的表單字段:ActiveWindow.GetWriteBackValueReference(ddlSheng.SelectedValue)
  4. 關閉子窗體:ActiveWindow.GetHideReference()

在子窗體的下拉列表中選擇“安徽”后,子窗口關閉並返回父頁面:

image

image

 

注意:GetSaveStateReference 和GetWriteBackValueReference有重載方法,可以一次傳入多個表單字段,參考示例

 

回發父頁面

通過前面的學習,我們知道了如何是在子窗體(內嵌IFrame)關閉時回發父頁面。但是對於如下兩個需求,該如何實現呢?

  1. 不關閉子窗體(內嵌IFrame)的情況下回發父頁面;
  2. 內嵌IFrame的面板中回發父頁面。

 

下面通過一個示例來展示如何處理第二種情況,先看下最終的頁面效果:

image

 

這個頁面的標簽定義如下:

   1:  <ext:PageManager ID="PageManager1" runat="server" />
   2:  頁面一:parent_simplepostback.aspx
   3:  <ext:Label ID="labResult" runat="server">
   4:  </ext:Label>
   5:  <br />
   6:  <br />
   7:  <ext:Panel ID="Panel1" runat="server" EnableBackgroundColor="true" ShowBorder="true"
   8:      Width="400px" Height="250px" EnableIFrame="true" IFrameUrl="parent_simplepostback2.aspx"
   9:      ShowHeader="true" Title="面板一">
  10:  </ext:Panel>

 

后台代碼:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (IsPostBack)
   4:      {
   5:          if (Request.Form["__EVENTARGUMENT"] == "param_from_simplepostback2")
   6:          {
   7:              Alert.Show("來自子面板IFrame中的事件!");
   8:          }
   9:      }
  10:   
  11:      labResult.Text = "頁面加載時間:" + DateTime.Now.ToLongTimeString();
  12:  }

 

特別注意:和我們通常看到的 if(!IsPostBack) 不同,這里的邏輯是在頁面回發時判斷事件參數是否為 param_from_simplepostback2 (而不管事件來源是哪個控件,實際上從后面的代碼可以明顯看出,這個事件的來源為空,是由子頁面手工觸發的)。

 

點擊回發父頁面時的界面顯示:

image

 

那么,點擊此按鈕的邏輯該如何處理呢?

   1:  protected void Button1_Click(object sender, EventArgs e)
   2:  {
   3:      PageContext.RegisterStartupScript("parent.__doPostBack('','param_from_simplepostback2');");
   4:  }

 

其實就是調用父頁面的 __doPostBack 函數,指定此次回發事件的事件源為空,事件參數為 param_from_simplepostback2。

 

小結

窗體控件在實際項目中使用非常廣泛,特別是和表格控件一起提供的新增、編輯等功能。同時本章還詳細描述了如何實現子窗體和父頁面的傳值問題,在實際項目中也有廣泛的應用。

 

注:《FineUI秘密花園》系列文章由三生石上原創,博客園首發,轉載請注明出處。文章目錄 官方論壇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM