步步為營-83-用戶控件
使用ascx目的就是為了提高某部分功能的重復利用,和方法封裝思想相似
參考了http://blog.csdn.net/dyllove98/article/details/9152843.
1需求:
1.1 創建一個用戶控件ascx B, 拉一個TextBox在這個控件上
1.2 創建另一個用戶控件ascx A 在這個用戶控件上,拉一個Textbox 和一個按鈕,是讓用戶在文本框輸入數據,點一點銨鈕,這樣動態產生ascx B用戶控件,呈現於ascx A用戶控件的頁面上。
1.3 創建一個aspx網頁。把用戶控件ascxA引用至aspx網頁上。再在aspx網頁上拉一個按鈕。讓用戶點一點這個銨鈕,去獲取動態產生的文本框的值,並顯示於aspx網頁上。
2實現
2.1 ascxB的創建(一個文本框)
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AscxB.ascx.cs" Inherits="Web.UserControl.AscxB" %> <asp:TextBox ID="txtB" runat="server"></asp:TextBox>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="Web.WebForm1" %> //aspx頁面
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AscxB.ascx.cs" Inherits="Web.UserControl.AscxB" %> //ascx頁面
通過對比我們可以發現 a @標簽不一樣; b 繼承的類不一樣; c 內容不同(是否含有html代碼)
2.2 ascxA的創建(一個文本框TextBox,一個銨鈕Button和一個容器PlaceHolder。在銨鈕添加onclick事件OnClick="BtnGenerate_Click")
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AscxA.ascx.cs" Inherits="Web.UserControl.AscxA" %> <asp:TextBox ID="txtA" runat="server"></asp:TextBox> <asp:Button ID="BtnGenerate" runat="server" Text="創建文本框" OnClick="BtnGenerate_Click" /> <br /> <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
2.3 為了能讓AscxA動態加載到AscxB,通過接口實現
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI; namespace Web.Interface { public interface IUserControl { UserControl GetUserControl(); } }
2.3 ascx B實現接口:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Web.UserControls { public partial class AscxB : System.Web.UI.UserControl,Web.Interface.IUserControl { protected void Page_Load(object sender, EventArgs e) { } public UserControl GetUserControl() { return this; } } }
2.4 AscxA的後臺代碼
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web.UserControls { public partial class AscxA : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { } protected void BtnGenerate_Click(object sender, EventArgs e) { if (ViewState["yk"] == null) { ViewState["yk"] = true; DynamicGenerate(); } } private void DynamicGenerate() { //獲取文本框的值 int j = 1; Int32.TryParse(this.txtA.Text.Trim(),out j); for (int i = 0; i < j; i++) { //動態加載AscxB後,並轉化為接口 -- 如果直接接受呢? IUserControl uc = (IUserControl)this.LoadControl("~/AscxB.ascx"); //加載接口 this.PlaceHolder1.Controls.Add(uc.GetUserControl()); //加空格 this.PlaceHolder1.Controls.Add(new LiteralControl(" ")) } } } }
2.5 創建一個網頁.aspx,在此網頁中,我們引用用戶控件ascxa,還在拉一個銨鈕,和個Literal控件,銨鈕與Literal最開始狀態是隱藏的,主要是用來獲取數據與顯示數據。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestUserControl1.aspx.cs" Inherits="Web.TestUserControl1" %> <%@ Register Src="~/UserControl/AscxA.ascx" TagPrefix="uc1" TagName="AscxA" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <uc1:AscxA runat="server" id="AscxA" /> <br /> <asp:Button ID="btnShowBContents" runat="server" Text="顯示用戶控件B中的值" Visible="false"/> <br /> <asp:Literal ID="LiteralResult" runat="server" Visible="false"></asp:Literal> </body> </html>
引用完控件以後,會多兩行這個代碼
<%@ Register Src="~/UserControl/AscxA.ascx" TagPrefix="uc1" TagName="AscxA" %>
用戶自定義控件的相對路徑,和名字
<uc1:AscxA runat="server" id="AscxA" />
2.6 在Ascx A用戶控件,當有動態產生Ascx B控件之後,在網頁的Button才會顯示。如果沒有產生過銨鈕,網頁Button就是隱藏起來。
由於是否有控件產生是發生在ascx A用戶控件,而隱藏的對象在網頁上。這涉及到用戶控件與網頁之間的溝通與協調。
為了減低程序的復雜度,創建一個接口,這個接口主體只有一個只寫屬性。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Web.Interface { public interface IShowable { bool Show { set; } } }
2.7 接口寫好了,我們在網頁.aspx.cs實作這個接口。說明白一點,就是網頁的銨鈕只接受顯示與隱藏,是誰來決定顯示與隱藏,它管不了。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web { public partial class TestUserControl1 : System.Web.UI.Page,IShowable { protected void Page_Load(object sender, EventArgs e) { } protected void btnShowBContents_Click(object sender, EventArgs e) { } public bool Show { set { this.btnShowBContents.Visible = value; } } } }
2.8 具體是誰來控制顯示與隱藏呢,剛才所說,是在用戶控件ascx A的動態產生ascx B之後,這個網頁的Button就顯示。因此,我們去用戶控件ascx a的產生控件代碼中添加:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web.UserControls { public partial class AscxA : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { DynamicGenerate(); } protected void BtnGenerate_Click(object sender, EventArgs e) { if (ViewState["yk"] == null) { ViewState["yk"] = true; DynamicGenerate(); } } private void DynamicGenerate() { //獲取文本框的值 int j = 1; Int32.TryParse(this.txtA.Text.Trim(),out j); for (int i = 0; i < j; i++) { //動態加載AscxB後,並轉化為接口 -- 如果直接接受呢? IUserControl uc = (IUserControl)this.LoadControl("~/AscxB.ascx"); //加載接口 this.PlaceHolder1.Controls.Add(uc.GetUserControl()); //加空格 this.PlaceHolder1.Controls.Add(new LiteralControl(" ")) } ((IShowable)this.Page).Show = true; } } }
2.9有點疑問,怎樣能把網頁轉為接口呢? 因為我們上面有把網頁實現了IShowable這個接口。
Ok, 我們回到網頁cs,準備寫銨鈕click事件,來獲取數據。不過獲取數據起來,是有點困難,因為動態產生的控件,全是在用戶控件ascx A中呈現,而且每呈現的文本框是來自ascx B。
在網頁中,怎樣獲取用戶控件的ascx A的容器PlaceHolder呢? 還是寫另外一個接口,是為了讓網頁.aspx.cs去讀取用戶控件的Ascx A的PlaceHolder。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI.WebControls; namespace Web.Interface { public interface IPlaceHolderable { PlaceHolder GetPlaceHolder(); } }
2.10 用戶控件ascx A實用這個接口:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web.UserControls { public partial class AscxA : System.Web.UI.UserControl,IPlaceHolderable { protected void Page_Load(object sender, EventArgs e) { DynamicGenerate(); } protected void BtnGenerate_Click(object sender, EventArgs e) { if (ViewState["yk"] == null) { ViewState["yk"] = true; DynamicGenerate(); } } private void DynamicGenerate() { //獲取文本框的值 int j = 1; Int32.TryParse(this.txtA.Text.Trim(),out j); for (int i = 0; i < j; i++) { //動態加載AscxB後,並轉化為接口 -- 如果直接接受呢? IUserControl uc = (IUserControl)this.LoadControl("~/AscxB.ascx"); //加載接口 this.PlaceHolder1.Controls.Add(uc.GetUserControl()); //加空格 this.PlaceHolder1.Controls.Add(new LiteralControl(" ")); } //設置 頁面按鈕顯示 ((IShowable)this.Page).Show = true; } /// <summary> /// 實現接口 IPlaceHolder() /// </summary> /// <returns></returns> public PlaceHolder GetPlaceHolder() { return this.PlaceHolder1; } } }
2.11 這樣子,我們就可以在網頁.aspx.cs的獲取值的銨鈕獲取這個容器了。另外,由於容器根據用戶的需求,也許不止單一次產生一個ascx B用戶控件,也許會有好幾個。我們怎樣知道哪一個文本框TextBox是哪一個TextBox呢?
還是寫一個接口吧,
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI.WebControls; namespace Web.Interface { public interface ITextBoxable { TextBox GetTextBox(); } }
2.12 讓用戶控件AscxB來實現
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web.UserControls { public partial class AscxB : System.Web.UI.UserControl, Web.Interface.IUserControl,ITextBoxable { protected void Page_Load(object sender, EventArgs e) { } public UserControl GetUserControl() { return this; } public TextBox GetTextBox() { return this.txtB; } } }
2.13 到現在為止,我們完全可以去網頁代碼中,去寫銨鈕的Click獲取值的事件了:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Web.Interface; namespace Web { public partial class TestUserControl1 : System.Web.UI.Page,IShowable { protected void Page_Load(object sender, EventArgs e) { } protected void btnShowBContents_Click(object sender, EventArgs e) { //01 獲取placeholder容器 IPlaceHolderable ascxA = (IPlaceHolderable)this.AscxA; PlaceHolder ph = ascxA.GetPlaceHolder(); //PlaceHolder ph = this.AscxA.GetPlaceHolder(); //02 顯示文本框的值 string str = string.Empty; foreach (Control item in ph.Controls) { if (item is ITextBoxable) { ITextBoxable txt = (ITextBoxable)item; str += txt.GetTextBox().Text.Trim()+"<br/>"; } if (str.Length>0) { this.LiteralResult.Visible = true; this.LiteralResult.Text = str; } } } public bool Show { set { this.btnShowBContents.Visible = value; } } } }
2.4 註意
步步為營-83-用戶控件