前言
FineUI中經常會用到啟用IFrame的Window控制元件,這樣有助於從物理上進行程式碼解耦和。IFrame的引入就會涉及傳值問題,如何在父視窗和子視窗之間相互傳值呢?
向子視窗傳值
向子視窗傳值只需要把要傳遞的引數放在頁面URL中即可,一般有兩種做法:
- 頁面回發,在後臺透過C#程式碼拼接需要的URL(推薦做法,方便!)
- 頁面第一次載入時,即註冊需要的URL(如果引數是頁面上某輸入框的值,則需要在URL中嵌入JavaScript程式碼)
來看一個例子,分別用上述兩種方式實現:
- 頁面的初始顯示
- 點選"從列表中選擇"按鈕,彈出選擇窗體(內嵌IFrame頁面),預設選中父頁面文字輸入框中的值
- 在彈出框內,點選"河南",立即關閉彈出框,並把選擇的值放到父頁面的文字輸入框內
暫時,我們只關心前兩步操作,也即是如何把文字輸入框的值傳遞到子視窗中。
- 頁面回發,在後臺透過C#程式碼拼接需要的URL(推薦做法,方便!)
1 <f:TextBox Label="你所在的省份" ID="tbxProvince" Text="安徽" runat="server"> 2 </f:TextBox> 3 <f:Button ID="Button1" OnClick="Button1_Click" runat="server" Text="從列表中選擇"> 4 </f:Button>
1 protected void Button1_Click(object sender, EventArgs e) 2 { 3 string openUrl = String.Format("./passvalue_iframe_iframe.aspx?selected={0}", HttpUtility.UrlEncode(tbxProvince.Text)); 4 5 PageContext.RegisterStartupScript(Window1.GetShowReference(openUrl)); 6 }
在按鈕的回發事件中,我們很容易透過控制元件的伺服器端屬性(tbxProvince.Text)來拼接需要的URL
- 頁面第一次載入時,即註冊需要的URL(如果引數是頁面上某輸入框的值,則需要在URL中嵌入JavaScript程式碼)
1 <f:TextBox Label="你所在的省份" ID="tbxProvince" Text="安徽" runat="server"> 2 </f:TextBox> 3 <f:Button ID="Button1" EnablePostBack="false" runat="server" Text="從列表中選擇"> 4 </f:Button>
1 protected void Page_Load(object sender, EventArgs e) 2 { 3 if (!IsPostBack) 4 { 5 string openUrl = String.Format("./passvalue_iframe_iframe.aspx?selected=<script>encodeURIComponent({0})</script>", tbxProvince.GetValueReference()); 6 7 Button1.OnClientClick = Window1.GetShowReference(openUrl); 8 } 9 }
注意:在上述 openUrl 引數中,我們嵌入了 <script> 標籤,這個是 FineUI 支援的特殊用法(在其他系統中可能不支援這個用法)!
大家一定要明白一個事情:在頁面第一次載入時,我們不可能直接獲得文字輸入框的值來拼接URL,因為使用者以後可能會修改這個值!
如果你這時檢視頁面原始碼,上述對 openUrl 操作被轉換為指令碼:
1 F('Window1').f_show('/iframe/passvalue_iframe_iframe.aspx?selected=' + encodeURIComponent(F('SimpleForm1_tbxProvince').getValue()));
向父視窗傳值(FineUI內建方法)
向父視窗傳值就沒那麼直觀了,幸好FineUI內建了一對方法來簡化這個操作,應該可以滿足 80% 的業務需求:
- 開啟子視窗時,呼叫 GetSaveStateReference,告知FineUI將來的返回值要儲存到哪些控制元件
1 protected void Button1_Click(object sender, EventArgs e) 2 { 3 string openUrl = String.Format("./passvalue_iframe_iframe.aspx?selected={0}", HttpUtility.UrlEncode(tbxProvince.Text)); 4 5 PageContext.RegisterStartupScript(Window1.GetSaveStateReference(tbxProvince.ClientID) 6 + Window1.GetShowReference(openUrl)); 7 }
- 關閉子視窗時,呼叫 GetWriteBackValueReference,將返回值儲存到父視窗的這些控制元件
1 protected void ddlSheng_SelectedIndexChanged(object sender, EventArgs e) 2 { 3 if (ddlSheng.SelectedValue != "-1") 4 { 5 PageContext.RegisterStartupScript(ActiveWindow.GetWriteBackValueReference(ddlSheng.SelectedValue) + ActiveWindow.GetHideReference()); 6 } 7 }
如果希望同時傳遞多個值,GetSaveStateReference 和 GetWriteBackValueReference 分別提供了過載方法。
向父視窗傳值(窗體的關閉事件)
上一節我們講到FineUI關閉窗體的三種處理方式,分別是隱藏、隱藏回發和隱藏重新整理,其中隱藏回發可以指定回發引數,正好用來向父頁面傳遞引數。
- 在子窗體中註冊窗體關閉指令碼,把要傳遞的引數放置在 GetHidePostBackReference 中
1 PageContext.RegisterStartupScript(ActiveWindow.GetHidePostBackReference("SelectProvince$要傳遞的引數"));
- 在父頁面的Window關閉事件中
1 protected void Window1_Close(object sender, WindowCloseEventArgs e) 2 { 3 if (e.CloseArgument.StartsWith("SelectProvince$")) 4 { 5 string provinceName = e.CloseArgument.Substring("SelectProvince$".Length); 6 7 ddlSheng.SelectedValue = provinceName; 8 } 9 }
其中,"SelectProvince$"是為了區分不同情況觸發的窗體關閉事件。
透過這種方式,無需編寫 JavaScript 程式碼也能方便的實現子窗體到父窗體的引數傳遞。
向父視窗傳值(自定義指令碼)
這種方法需要自己編寫JavaScript,需要對FineUI的客戶端指令碼比較熟悉,但也更加靈活。下面透過一個示例講解:
- 頁面的初始顯示
在父頁面定義全域性 JavaScript 函式:1 <script> 2 var shengClientID = '<%= ddlSheng.ClientID %>'; 3 4 function selectProvince(name) { 5 F(shengClientID).setValue(name); 6 } 7 </script>
如果子窗體可以找到本頁面的JavaScript物件window,則可以方便的呼叫 window.selectProvince 來傳遞引數
- 點選"從列表中選擇",在Top頁面開啟窗體,在彈出窗體內選擇省份
1 <map id="ChinaMap" name="ChinaMap"> 2 <area href="javascript:select('黑龍江');" coords="398,52,442,72" shape="rect"> 3 <area href="javascript:select('吉林');" coords="400,96,433,111" shape="rect"> 4 </map>
1 <script> 2 function select(provinceName) { 3 // 返回當前活動Window物件(瀏覽器視窗物件透過F.wnd.getActiveWindow().window獲取) 4 var activeWindow = F.wnd.getActiveWindow(); 5 activeWindow.window.selectProvince(provinceName); 6 activeWindow.f_hide(); 7 } 8 </script>
上面的 F.wnd.getActiveWindow 返回的是當前活動的Window控制元件例項,F.wnd.getActiveWindow().window就是Window控制元件例項所在的頁面的JavaScript物件window。知道了這個關係,就很容易理解這段程式碼了。
一個小問題,為什麼不直接呼叫 parent.selectProvince ?
能夠提出這個問題的一般 JavaScript 功底還不錯!
不過這個地方還真不行,如果你注意到前面的一個細節“點選從列表中選擇,在Top頁面開啟窗體”,所以現在的層次結構是這樣的:
- 在表單頁面定義了 window.selectProvince
- Window控制元件例項(編輯框)在主框架頁面(也就是表單頁面的父頁面)
- 中國地圖所在頁面的 parent 是主框架頁面,非表單頁面!
本章小結
本篇文章介紹了從父窗體向子窗體傳值,可以透過子窗體頁面的URL地址,而拼接此URL地址又有兩種做法,我們推薦在後臺透過C#方式做,簡單方便!從子窗體向父窗體傳值也有多種做法,FineUI提供的一對函式(GetSaveStateReference 和 GetWriteBackValueReference )足以滿足大部分的需求,其次還可以透過窗體的關閉事件以及自定義JavaScript指令碼來完成傳值。
原始碼與線上示例
本系列所有文章的原始碼均可自行下載:http://fineui.codeplex.com/
線上示例:
- http://fineui.com/demo/#/demo/iframe/passvalue_iframe.aspx
- http://fineui.com/demo/#/demo/iframe/triggerbox_iframe.aspx
- http://fineui.com/demo/#/demo/iframe/selectprovince1.aspx
如果本文對你有所啟發或者幫助,請猛擊“好文要頂”,支援原創,支援三石!
另附24張專業版高畫質大圖