[原創]FineUI秘密花園(二十九) — 用戶控件概述


這里的用戶控件指的是繼承自System.Web.UI.UserControl的控件,由於本質上用戶控件屬於Asp.Net,所以可以直接放在form標簽或者ContentPanel控件中。后來FineUI增加了UserControlConnector控件,可以使用戶控件方便地參與頁面布局。本篇文章會詳細描述使用UserControlConnector的用戶控件與直接放在ContentPanel中的用戶控件的區別。

 

創建一個包含自定義屬性的用戶控件

我們將要創建的用戶控件如下圖所示:

image

 

這個用戶控件非常簡單,只包含一個面板和一個文本,ASPX標簽如下所示:

   1:  <ext:Panel runat="server" ID="Panel1" BodyPadding="5px" Title="用戶控件/面板一">
   2:      <Items>
   3:          <ext:Label runat="server" ID="labUserInfo">
   4:          </ext:Label>
   5:      </Items>
   6:  </ext:Panel>

來看下用戶控件的后台代碼:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      LoadData();
   4:  }
   5:   
   6:  private void LoadData()
   7:  {
   8:      labUserInfo.Text = String.Format("{0}今年{1}歲,住在{2}。", UserName, UserAge, UserCountry);
   9:   
  10:      if (!String.IsNullOrEmpty(Properties))
  11:      {
  12:          Panel1.RecoverPropertiesFromJObject(JObject.Parse(Properties));
  13:      }
  14:  }
  15:   
  16:   
  17:  private string userName;
  18:  private int userAge;
  19:  private string userCountry;
  20:  private string properties;
  21:   
  22:  public string Properties
  23:  {
  24:      get { return properties; }
  25:      set { properties = value; }
  26:  }
  27:   
  28:  public string UserName
  29:  {
  30:      get { return userName; }
  31:      set { userName = value; }
  32:  }
  33:   
  34:  public int UserAge
  35:  {
  36:      get { return userAge; }
  37:      set { userAge = value; }
  38:  }
  39:   
  40:  public string UserCountry
  41:  {
  42:      get { return userCountry; }
  43:      set { userCountry = value; }
  44:  }

 

從上面代碼可以看出,我們定義了四個屬性:

  • UserName:用戶名
  • UserAge:用戶年齡
  • UserCountry:用戶所在地區
  • Properties:JSON定義的面板屬性列表(比如:{BoxMargin:"0",BoxFlex:1}),可以通過RecoverPropertiesFromJObject來恢復。

 

在ContentPanel中添加用戶控件

在ContentPanel中使用用戶控件非常簡單,由於ContentPanel本來就是用來放置非FineUI的一個特殊控件,來看下代碼:

   1:  <ext:ContentPanel runat="server" ID="Panel1" EnableBackgroundColor="true" Width="600px"
   2:      Height="150px" Title="頁面/面板一ContentPanel->UserInfoControl)">
   3:      <uc1:UserInfoControl ID="UserInfoControl1" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   4:          runat="server" />
   5:  </ext:ContentPanel>

顯示效果:

image

 

分析下生成的HTML代碼:

   1:  <div id="Panel1_wrapper">
   2:      <div id="Panel1_content">
   3:          <div id="Panel1_UserInfoControl1_Panel1_wrapper"></div>
   4:      </div>
   5:  </div>
   6:   
   7:  <script>
   8:  var x2 = new Ext.Panel({
   9:      id: "Panel1_UserInfoControl1_Panel1",
  10:      renderTo: "Panel1_UserInfoControl1_Panel1_wrapper",
  11:      items: [x1],
  12:      title: "用戶控件/面板一"
  13:  });
  14:  var x0 = new Ext.Panel({
  15:      id: "Panel1",
  16:      renderTo: "Panel1_wrapper",
  17:      contentEl: "Panel1_content",
  18:      title: "頁面/面板一(ContentPanel->UserInfoControl)"
  19:  });
  20:  </script>

可以看出,此時用戶控件是直接渲染到 Panel1_UserInfoControl1_Panel1_wrapper 這個DIV中,而這個DIV位於Panel1面板中。

 

使用UserControlConnector添加用戶控件

   1:  <ext:Panel runat="server" ID="Panel2" EnableBackgroundColor="true" Width="600px"
   2:      Height="150px" Title="頁面/面板二Panel->UserControlConnector->UserInfoControl)">
   3:      <Items>
   4:          <ext:UserControlConnector runat="server">
   5:              <uc1:UserInfoControl ID="UserInfoControl2" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   6:                  runat="server" />
   7:          </ext:UserControlConnector>
   8:      </Items>
   9:  </ext:Panel>

顯示效果:

image

 

可以看到,使用UserControlConnector的顯示效果和放在ContentPanel中的效果一樣。但是兩者有本質的區別,來看下生成的HTML代碼:

   1:  <div id="Panel2_wrapper"></div>
   2:   
   3:  <script>
   4:  var x5 = new Ext.Panel({
   5:      id: "Panel2_ctl00_UserInfoControl2_Panel1",
   6:      items: [x6],
   7:      title: "用戶控件/面板一"
   8:  });
   9:  var x8 = new Ext.Panel({
  10:      id: "Panel2",
  11:      renderTo: "Panel2_wrapper",
  12:      items: [x5],
  13:      title: "頁面/面板二(Panel->UserControlConnector->UserInfoControl)"
  14:  });
  15:  </script>

此時,用戶控件不是直接被渲染到頁面上的DIV中,而是作為Panel2的items屬性(items: [x5]),也就是說用戶控件的渲染是由父控件控制的。

 

這種本質的區別也正是FineUI所追求的,由於用戶控件的渲染是由父控件控制的,所以可以很方便的參與頁面布局,比如改造上面的例子:

   1:  <ext:Panel runat="server" ID="Panel3" EnableBackgroundColor="true" Width="600px"
   2:      Height="150px" Layout="Fit" Title="頁面/面板三Layout=Fit, Panel->UserControlConnector->UserInfoControl)">
   3:      <Items>
   4:          <ext:UserControlConnector runat="server">
   5:              <uc1:UserInfoControl ID="UserInfoControl3" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   6:                  runat="server" />
   7:          </ext:UserControlConnector>
   8:      </Items>
   9:  </ext:Panel>

這個示例和上一個例子的唯一區別就是布局的使用(Layout=Fit),生成的界面效果確實完全不同的:

image

 

可以看到,用戶控件參與到了頁面布局,此時完全充滿了外部的面板。而這種效果是ContentPanel所無法實現的。

 

動態添加用戶控件

那么如何通過動態添加用戶控件的方式來實現上一個例子呢:

   1:  <ext:Panel runat="server" ID="Panel3" EnableBackgroundColor="true" Width="600px"
   2:      Height="150px" Layout="Fit" Title="頁面/面板三Layout=Fit, Panel->UserControlConnector->UserInfoControl)">
   3:  </ext:Panel>
   1:  protected void Page_Init(object sender, EventArgs e)
   2:  {
   3:      UserControlConnector ctrlConnector2 = new UserControlConnector();
   4:      Panel3.Items.Add(ctrlConnector2);
   5:      ctrlConnector2.Controls.Add(CreateANewUserControl());
   6:  }
   7:   
   8:  private UserInfoControl CreateANewUserControl()
   9:  {
  10:      UserInfoControl ctrl = LoadControl("~/usercontrol/UserInfoControl.ascx") as UserInfoControl;
  11:      ctrl.UserName = "陳萍萍";
  12:      ctrl.UserAge = 20;
  13:      ctrl.UserCountry = "合肥";
  14:   
  15:      return ctrl;
  16:  }

 

需要注意的有如下幾點:

  • 動態添加控件的代碼放在Page_Init中,在前面《表格之動態創建列》中有詳細描述;
  • 通過LoadControl來動態創建用戶控件。

 

用戶控件參與復雜的頁面布局

上個例子使用了Fit布局,下面的例子會使用更加復雜的布局VBox,先看一個簡單的示例:

   1:  <ext:Panel runat="server" ID="Panel1" EnableBackgroundColor="true" Width="600px"
   2:      Height="200px" Layout="VBox" BoxConfigAlign="Stretch" BoxConfigPosition="Start"
   3:      BoxConfigPadding="5" BoxConfigChildMargin="0 0 5 0" Title="頁面/面板一Layout=VBox, Panel->(UserControlConnector->UserInfoControl,Panel))">
   4:      <Items>
   5:          <ext:UserControlConnector ID="UserControlConnector1" runat="server">
   6:              <uc1:UserInfoControl ID="UserInfoControl1" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   7:                  runat="server" />
   8:          </ext:UserControlConnector>
   9:          <ext:Panel runat="server" ID="Panel3" BodyPadding="5px" BoxFlex="1" BoxMargin="0"
  10:              Title="頁面/面板二">
  11:              <Items>
  12:                  <ext:Label runat="server" Text="胡斐今年22歲,住在駐馬店。">
  13:                  </ext:Label>
  14:              </Items>
  15:          </ext:Panel>
  16:      </Items>
  17:  </ext:Panel>

 

在這個例子中,Panel1包含兩個子控件,第一個控件是一個用戶控件(由於沒有應用布局屬性,所以用戶控件的高度將是默認的高度),另一個控件使用了布局屬性BoxFlex=1,也就是說占據剩余的全部高度。頁面顯示效果:

image

 

為了實現相同的效果,我們也可以使用用戶控件取代上例的第二個子控件,如下所示:

   1:  <ext:Panel runat="server" ID="Panel2" EnableBackgroundColor="true" Width="600px"
   2:      Height="200px" Layout="VBox" BoxConfigAlign="Stretch" BoxConfigPosition="Start"
   3:      BoxConfigPadding="5" BoxConfigChildMargin="0 0 5 0" Title="頁面/面板一">
   4:      <Items>
   5:          <ext:UserControlConnector ID="UserControlConnector2" runat="server">
   6:              <uc1:UserInfoControl ID="UserInfoControl2" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   7:                  runat="server" />
   8:          </ext:UserControlConnector>
   9:          <ext:UserControlConnector ID="UserControlConnector3" runat="server">
  10:              <uc1:UserInfoControl ID="UserInfoControl3" Properties="{BoxMargin:'0',BoxFlex:1}" UserName="胡斐" UserAge="22" UserCountry="駐馬店"
  11:                  runat="server" />
  12:          </ext:UserControlConnector>
  13:      </Items>
  14:  </ext:Panel>

 

要特別注意第二個用戶控件的Properties屬性(這個是我們自定義的),這是一個JSON字符串表示的對象,包含兩個屬於面板的屬性BoxMargin和BoxFlex,在前面我們已經看到這兩個屬性被最終應用到用戶控件中的面板上。

 

其實UserControlConnector可以包含多個子控件,因此上例可以簡化為:

   1:  <ext:Panel runat="server" ID="Panel4" EnableBackgroundColor="true" Width="600px"
   2:      Height="200px" Layout="VBox" BoxConfigAlign="Stretch" BoxConfigPosition="Start"
   3:      BoxConfigPadding="5" BoxConfigChildMargin="0 0 5 0" Title="頁面/面板二">
   4:      <Items>
   5:          <ext:UserControlConnector ID="UserControlConnector4" runat="server">
   6:              <uc1:UserInfoControl ID="UserInfoControl4" UserName="陳萍萍" UserAge="20" UserCountry="合肥"
   7:                  runat="server" />
   8:              <uc1:UserInfoControl ID="UserInfoControl5" UserName="胡斐" UserAge="22" UserCountry="駐馬店"
   9:                  runat="server" />
  10:          </ext:UserControlConnector>
  11:      </Items>
  12:  </ext:Panel>

 

此時,對第二個用戶控件Properties屬性的設置是在后台進行的:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          LoadData();
   6:      }
   7:  }
   8:   
   9:  private void LoadData()
  10:  {
  11:      JObject jo = new JObject();
  12:      jo.Add("BoxMargin", "0");
  13:      jo.Add("BoxFlex", 1);
  14:      UserInfoControl5.Properties = jo.ToString(Formatting.None);
  15:  }

 

小結

用戶控件有時非常實用,特別是對於一些需要在多個地方重用UI邏輯。而FineUI提供的UserControlConnector讓用戶控件可以很方便的參與頁面布局,從而在重用UI邏輯的同時保持頁面的美觀一致。

 

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


免責聲明!

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



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