日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[原创]FineUI秘密花园(二十一) — 表格之动态创建列

發布時間:2023/12/20 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [原创]FineUI秘密花园(二十一) — 表格之动态创建列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

有時我們需要根據數據來動態創建表格列,怎么來做到這一點呢?本章會詳細講解。

?

動態創建的列

還是通過一個示例來看下如何在FineUI中動態創建表格列,示例的界面截圖:

?

先來看下ASPX的標簽定義:

1: <ext:Grid ID="Grid1" runat="server" Width="650px" EnableCheckBoxSelect="true" EnableRowNumber="true" 2: Title="表格(動態創建的列)"> 3: </ext:Grid>

?

ASPX標簽中沒有定義任何列,所有列都是在后臺定義的:

1: // 注意:動態創建的代碼需要放置于Page_Init(不是Page_Load),這樣每次構造頁面時都會執行 2: protected void Page_Init(object sender, EventArgs e) 3: { 4: InitGrid(); 5: } 6: ? 7: private void InitGrid() 8: { 9: FineUI.BoundField bf; 10: ? 11: bf = new FineUI.BoundField(); 12: bf.DataField = "Id"; 13: bf.DataFormatString = "{0}"; 14: bf.HeaderText = "編號"; 15: Grid1.Columns.Add(bf); 16: ? 17: bf = new FineUI.BoundField(); 18: bf.DataField = "Name"; 19: bf.DataFormatString = "{0}"; 20: bf.HeaderText = "姓名"; 21: Grid1.Columns.Add(bf); 22: ? 23: bf = new FineUI.BoundField(); 24: bf.DataField = "EntranceYear"; 25: bf.DataFormatString = "{0}"; 26: bf.HeaderText = "入學年份"; 27: Grid1.Columns.Add(bf); 28: ? 29: bf = new FineUI.BoundField(); 30: bf.DataToolTipField = "Major"; 31: bf.DataField = "Major"; 32: bf.DataFormatString = "{0}"; 33: bf.HeaderText = "所學專業"; 34: bf.ExpandUnusedSpace = true; 35: Grid1.Columns.Add(bf); 36: ? 37: Grid1.DataKeyNames = new string[] { "Id", "Name" }; 38: } 39: ? 40: protected void Page_Load(object sender, EventArgs e) 41: { 42: if (!IsPostBack) 43: { 44: LoadData(); 45: } 46: } 47: ? 48: private void LoadData() 49: { 50: DataTable table = GetDataTable(); 51: ? 52: Grid1.DataSource = table; 53: Grid1.DataBind(); 54: }

整個代碼結構非常清晰,分為頁面的初始化階段和頁面的加載階段。

在頁面的初始化階段:

  • 創建一個新的FineUI.BoundField實例;
  • 設置此實例的DataField、DataFormatString、HeaderText等屬性;
  • 將新創建的列添加到Grid1.Columns屬性中。
  • ?

    頁面的加載階段就是綁定數據到表格,和之前的處理沒有任何不同。

    ?

    動態創建的模板列

    模板列的動態創建有點復雜,我們先來看下創建好的模板列:

    ?

    ASPX標簽和上面例子一模一樣,就不再贅述。我們來看下動態創建模板列的代碼:

    1: FineUI.TemplateField tf = new TemplateField(); 2: tf.Width = Unit.Pixel(100); 3: tf.HeaderText = "性別(模板列)"; 4: tf.ItemTemplate = new GenderTemplate(); 5: Grid1.Columns.Add(tf);

    ?

    這里的GenderTemplate是我們自己創建的類,這也是本例的關鍵點。

    1: public class GenderTemplate : ITemplate 2: { 3: public void InstantiateIn(System.Web.UI.Control container) 4: { 5: AspNet.Label labGender = new AspNet.Label(); 6: labGender.DataBinding += new EventHandler(labGender_DataBinding); 7: container.Controls.Add(labGender); 8: } 9: ? 10: private void labGender_DataBinding(object sender, EventArgs e) 11: { 12: AspNet.Label labGender = (AspNet.Label)sender; 13: ? 14: IDataItemContainer dataItemContainer = (IDataItemContainer)labGender.NamingContainer; 15: ? 16: int gender = Convert.ToInt32(((DataRowView)dataItemContainer.DataItem)["Gender"]); 17: 18: labGender.Text = (gender == 1) ? "男" : "女"; 19: } 20: }

    GenderTemplate實現了ITemplate接口,其中InstantiateIn在需要初始化模板中控件時被調用:

  • 創建一個Asp.Net的Label控件實例 (AspNet.Label labGender = new AspNet.Label());
  • 設置數據綁定處理函數(labGender.DataBinding += new EventHandler(labGender_DataBinding));
  • 將此Label實例添加到模板容器中(container.Controls.Add(labGender))。
  • ?

    之后,在對Label進行數據綁定時:

  • 首先得到當前Label實例,也即是sender對象;
  • 獲取Label的命名容器,此容器實現了IDataItemContainer接口;
  • 將此接口的DataItem強制轉換為DataRowView,因為數據源是DataTable;
  • 根據數據源的值設置Label的值。
  • ?

    上面的兩個示例,我們都把動態創建控件的代碼當時Page_Init函數中,這是為什么呢?

    要想明白其中的道理,我們還是要從Asp.Net中動態添加控件的原理說起。

    ?

    學習Asp.Net的視圖狀態和生命周期

    這個話題比較深入,也不大容易理解,建議大家在閱讀本節之前詳細了解Asp.Net的視圖狀態和頁面的生命周期,下面是兩個非常經典的參考文章(本節的部分圖片和文字都來自這兩篇文章):

  • Understanding ASP.NET View State
  • 創建動態數據輸入用戶界面
  • ?

    Asp.Net頁面的生命周期

    從上圖可以看出,Asp.Net頁面的生命周期分為如下幾個階段:

  • 實例化階段:根據ASPX標簽定義的靜態結構創建控件的層次結構,并會調用頁面的Page_Init事件處理函數。
  • 加載視圖狀態階段(僅回發):將VIEWSTATE中發現的視圖狀態數據恢復到控件的層次結構中。
  • 加載回發數據階段(僅回發):將回發的表單數據恢復到控件的層次結構中,如果表單控件的數據發生變化,還有可能在第5個階段觸發相應的事件。
  • 加載階段:此時控件的層次結構已經創建完畢,并且控件的狀態已經從視圖數據和回發數據中回發,此時可以訪問所有的控件屬性,并會調用頁面的Page_Load事件處理函數。
  • 觸發回發事件(僅回發)階段:觸發回發事件,比如按鈕的點擊事件、下拉列表的選中項改變事件。
  • 保存視圖狀態階段:保存所有控件的視圖狀態。
  • 渲染階段:將所有頁面控件渲染為HTML代碼。
  • 上面的這七個階段是每個Asp.Net開發人員都應該熟悉和掌握的,它可以幫助我們理解頁面中Page_Load和事件處理函數的邏輯關系。

    ?

    注意:上述處理過程不管是在頁面第一次加載還是在頁面回發,都會發生。理解這一點非常重要!

    ?

    動態添加控件的兩種模式

    動態添加控件需要在加載視圖狀態和加載回發數據之前進行,因為我們需要能夠在添加控件之后恢復這些數據。所以這個階段就對應了Page_Init處理函數,這也就是為什么上面兩個例子都在此函數中動態添加控件。

    ?

    但是由于在初始化階段時,視圖狀態和回發數據還沒有恢復,因此此時無法訪問存儲在視圖狀態或者回發數據中的控件屬性。所以還有一個常用的模式是在Page_Init中添加控件,在Page_Load中為動態創建的控件設置默認值。

    ?

    下面兩個示例分別展示了動態添加控件的兩種模式。

    動態添加控件模式一:

    1: protected void Page_Init(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: lab.Text = "Label1"; 6: ? 7: Form.Controls.Add(lab); 8: } 9: ? 10: protected void Page_Load(object sender, EventArgs e) 11: { 12: 13: }

    ?

    動態添加控件模式二:

    1: protected void Page_Init(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: ? 6: Form.Controls.Add(lab); 7: } 8: ? 9: protected void Page_Load(object sender, EventArgs e) 10: { 11: if (!IsPostBack) 12: { 13: AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label; 14: lab.Text = "Label1"; 15: } 16: }

    第二種模式是在初始化階段添加動態控件,然后在加載階段(!IsPostBack)設置控件的默認值。

    ?

    ?

    ?

    ?

    錯誤使用動態添加控件的例子一

    你可能會想上例中,為什么要將設置控件默認值的代碼放在 !IsPostBack 邏輯塊中,下面就來看下不放在!IsPostBack 邏輯塊中的例子。

    首先看下ASPX標簽結構:

    1: <form id="form1" runat="server"> 2: <asp:Button ID="Button1" Text="Change Text" OnClick="Button1_Click" runat="server" /> 3: <asp:Button ID="Button2" Text="Empty Post" runat="server" /> 4: <br /> 5: </form>

    再看下后臺的初始化代碼:

    1: protected void Page_Init(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: ? 6: Form.Controls.Add(lab); 7: } 8: ? 9: protected void Page_Load(object sender, EventArgs e) 10: { 11: AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label; 12: lab.Text = "Label1"; 13: } 14: ? 15: ? 16: protected void Button1_Click(object sender, EventArgs e) 17: { 18: AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label; 19: lab.Text = "Changed Label1"; 20: }

    按如下步驟操作:

  • 第一次打開頁面,顯示的文本是 Label1;
  • 點擊“Change Text”按鈕,顯示的文本是 Changed Label1;
  • 點擊“Empty Post”按鈕,顯示的文本是 Label1。
  • 這就不對了,點擊“Empty Post”按鈕時顯示的文本也應該是 Changed Label1,但是上例中文本控件的視圖狀態沒有保持,這是為什么呢?

    原因也很簡單,當用戶進行第三步操作(即點擊“Empty Post”按鈕):

  • 在初始化階段(Page_Init),添加了動態控件Label1;
  • 根據頁面的生命周期,之后進行的是加載視圖狀態(LoadViewState),此時動態控件Label1的文本是 Changed Label1;
  • 加載視圖狀態之后就開始跟蹤視圖狀態的變化;
  • 在加載階段(Page_Load),跟蹤到了控件屬性值的變化,Label1的值就又從Chenged Label1變成了Label1。
  • ?

    關鍵點:當控件完成加載視圖狀態階段后,就會立即開始跟蹤其視圖狀態的改變,之后任何對其屬性的改變都會影響最終的控件視圖狀態。

    理解這一點非常重要,如果你尚未理解這句話的意思,請多讀幾遍,再多讀幾遍,這句話同時會影響后面介紹的另外兩種動態添加控件的模式。

    ?

    如果你能理解上面提到的過程,說明你已經掌握了Asp.Net的頁面生命周期和ViewState的加載過程了。

    ?

    動態添加控件的另外兩種模式

    除了在初始化階段動態添加控件外,還可以再加載階段添加控件。這是因為當把一個控件添加到另一個控件的Controls集合時,所添加的控件的生命周期會立即同步到父控件的生命周期。比如,如果父控件處于初始化階段,則會觸發所添加控件的初始化事件;如果父控件處于加載階段,則會觸發所添加控件的的初始化事件、加載視圖事件、加載回發數據事件以及加載事件。

    ?

    由此,我們就有了另外兩種動態添加控件的模式:

    動態添加控件模式三:

    1: protected void Page_Load(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: lab.Text = "Label1"; 6: Form.Controls.Add(lab); 7: }

    ?

    對于這一種模式,你是否有這樣的疑問?:

    如果此標簽的Text屬性在某次Ajax回發時改變了,那么下次Ajax回發時,創建此標簽并賦默認值會不會覆蓋恢復的視圖狀態呢(因為此時已經過了加載視圖狀態階段)?

    其實不會這樣的,雖然在Page_Load已經過了加載視圖狀態階段,但是由于此標簽控件尚未添加到控件層次結構中,所以尚未經歷加載視圖狀態階段,只有在Controls.Add之后才會經歷標簽控件的初始化階段、加載視圖狀態階段、加載回發數據階段和加載階段。

    ?

    下面通過一個例子說明,首先看下ASPX標簽結構:

    1: <form id="form1" runat="server"> 2: <asp:Button ID="Button1" Text="Change Text" OnClick="Button1_Click" runat="server" /> 3: <asp:Button ID="Button2" Text="Empty Post" runat="server" /> 4: <br /> 5: </form>

    后臺代碼:

    1: protected void Page_Load(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: lab.Text = "Label1"; 6: Form.Controls.AddAt(label2Index, lab); 7: } 8: ? 9: protected void Button1_Click(object sender, EventArgs e) 10: { 11: AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label; 12: lab.Text = "Changed Label1"; 13: }

    進行如下操作:

  • 第一次打開頁面,顯示的文本是 Label1;
  • 點擊“Change Text”按鈕,顯示的文本是 Changed Label1;
  • 在Page_Load中設置斷點,點擊“Empty Post”按鈕,觀察標簽的Text屬性如下所示。
  • ?

    在執行Controls.Add之前,文本值還是Label1:

    ?

    在執行Controls.Add之后,文本值從視圖狀態恢復,變成了 Changed Label1:

    ?

    ?

    動態添加控件模式四:

    1: protected void Page_Load(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: 6: Form.Controls.Add(lab); 7: ? 8: if (!IsPostBack) 9: { 10: lab.Text = "Label1"; 11: } 12: }

    ?

    錯誤使用動態添加控件的例子二

    如果你認為自己已經掌握了動態添加控件的原理,不妨來看下面這個錯誤的例子,看能否指出其中錯誤的關鍵。

    先來看下ASPX標簽結構:

    1: <form id="form1" runat="server"> 2: <asp:Button ID="Button2" Text="Empty Post" runat="server" /> 3: <br /> 4: </form>

    ?

    在看后臺初始化代碼:

    1: protected void Page_Load(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: if (!IsPostBack) 6: { 7: lab.Text = "Label1"; 8: } 9: ? 10: Form.Controls.Add(lab); 11: }

    是不是和動態添加控件模式四比較類似,不過這里的用法卻是錯誤的,你能看出問題所在嗎?

    ?

    來運行一把:

  • 第一次加載頁面,顯示的文本是Label1;
  • 點擊“Empty Post”按鈕,顯示的文本為空(這就不對了,應該還是Label1)。
  • ?

    為什么會出現這種情況?我們來分析一下:

    • 第一次加載頁面時,設置了文本標簽的默認值,然后添加到控件層次結構中;
    • 添加到控件層次結構后,即開始跟蹤視圖狀態的變化,但是此標簽的Text屬性并沒改變,所以最終沒有保存到視圖狀態中;
    • 點擊按鈕回發時,文本標簽的默認值為空,然后添加到控件層次結構中,在加載視圖狀態階段沒有發現文本標簽的視圖,所以最終顯示為空。

    ?

    那為什么模式四是正確的呢?

    簡單來說,修改標簽的Text屬性時已經在跟蹤視圖狀態的改變了,所以這個修改的值被保存了下來;下次回發時又將此值從視圖中恢復了出來。

    ?

    ?

    錯誤使用動態添加控件的例子三

    如果上面的都掌握了,再來看下面這個錯誤的示例,ASPX標簽結構如下:

    1: <form id="form1" runat="server"> 2: <asp:Button ID="Button2" Text="Empty Post" runat="server" /> 3: <br /> 4: <asp:Label ID="Label2" Text="Label2" runat="server"></asp:Label> 5: </form>

    后臺初始化代碼如下:

    1: protected void Page_Load(object sender, EventArgs e) 2: { 3: AspNet.Label lab = new AspNet.Label(); 4: lab.ID = "Label1"; 5: lab.Text = "Label1"; 6: 7: int label2Index = Form.Controls.IndexOf(Label2); 8: ? 9: Form.Controls.AddAt(label2Index, lab); 10: ? 11: ? 12: if (!IsPostBack) 13: { 14: lab.Text = "Changed Label1"; 15: } 16: }

    這段代碼進行了如下處理:

  • 新創建一個標簽實例Label1,并設置默認值Label1;
  • 找到頁面上現有標簽Label2在父控件中的索引號;
  • 將新創建的Label1控件插入Label2所在的位置,也即是將Label2向后移動一個位置;
  • 在頁面第一次加載時更改新創建標簽Label1的文本為Changed Label1。
  • ?

    我們來看下頁面第一個加載的顯示:

    一切正常,被改變文本值的Label1位于Label2的前面。

    ?

    然后點擊“Empty Post”按鈕,會出現如下情況:

    為什么本應該保持狀態的Label2,現在的值卻變成了Changed Label1?

    ?

    根本原因是Asp.Net保存保存視圖狀態的方式,是按照控件出現的順序保存的,當然恢復也是按照順序進行的,關于這一特性,我有專門一篇文章詳細闡述。

    ?

    總之,簡單兩句話:

  • 在Page_Load中動態添加控件時,不要改變現有控件的順序;
  • 如果想改變現有控件的順序,可以再Page_Init中進行添加。
  • ?

    ?

    或者簡單一句話:在ASP.NET中,所有動態添加控件的代碼都要放到 Page_Init 中進行!

    ?

    ?

    小結

    其實在FineUI中編寫動態創建的表格列非常簡單,但是要想理解其中原理,就不那么簡單了。本篇文章的最后一節詳細描述了動態創建控件的原理,也希望大家能夠細細品味,深入了解Asp.Net的內部運行機制。

    下一篇文章我們會詳細講解如何從表格導出Excel文件。

    ?

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

    轉載于:https://www.cnblogs.com/sanshi/archive/2012/11/19/2776672.html

    總結

    以上是生活随笔為你收集整理的[原创]FineUI秘密花园(二十一) — 表格之动态创建列的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美精品久久 | 亚洲精品一品 | 国产免费美女 | 国产精品免费久久久久 | 东北高大丰满bbbbzbbb | 性少妇videosexfre | 久久国产人妻一区二区免色戒电影 | 美女爆乳18禁www久久久久久 | 天天插天天插 | av自拍网 | 非洲黄色片 | 欧美成人性生活片 | 精品国产一区二区视频 | 欧美日本韩国在线 | hd极品free性xxx护士 | 未满十八18禁止免费无码网站 | 特级大胆西西4444人体 | 成人免费视频免费观看 | 美女视频污 | 青青草好吊色 | 海角社区在线视频播放观看 | 久久久久久久极品内射 | 美女涩涩视频 | 日b影院| 豆花视频成人 | 无码精品在线观看 | 久久精品中文 | 免费精品视频在线观看 | 日本资源在线 | 亚洲 小说 欧美 激情 另类 | 成人亚洲在线 | 天天曰天天操 | 91麻豆蜜桃一区二区三区 | 人妻换人妻a片爽麻豆 | 天天摸天天射 | 内射国产内射夫妻免费频道 | 艳妇臀荡乳欲伦交换在线看 | 亚洲黄色免费网站 | 天堂在线www | 少妇性l交大片免费观看 | 日韩视频一区二区三区在线播放免费观看 | 国产精品久久av无码一区二区 | 欧美久久网 | 欧美日韩成人一区二区在线观看 | 午夜大片网 | 一级肉体全黄裸片中国 | 中文字幕第二区 | av黄色小说 | 亚洲精品高清视频在线观看 | 免费高清毛片 | 国产一二三区免费视频 | 青青草久久爱 | 无码一区二区三区视频 | 欧美黑人粗大 | 少妇人妻偷人精品视频蜜桃 | 午夜影院一区二区 | 欧美黑人一区二区三区 | 鲁鲁狠狠狠7777一区二区 | 国产精品熟妇一区二区三区四区 | 久久大 | 91超碰免费在线 | 亚洲三级久久 | 久久久999 | 国产三级精品三级在线观看 | 日韩精品亚洲一区 | av小次郎收藏 | 人人爽人人射 | 麻豆videos| 日本a级黄色| 91成品视频 | 美女脱裤子让男人捅 | 伊人影视久久 | 久久精品小视频 | 东北少妇露脸无套对白 | 91网站视频在线观看 | 99在线精品免费视频 | 老司机深夜福利网站 | 乡村乱淫 | 在线免费中文字幕 | 国产区一区二 | eeuss一区二区 | 99蜜桃臀久久久欧美精品网站 | 黑人一区二区三区 | 日韩成年人视频 | 美女扒开内裤让男人捅 | 精品国产精品国产偷麻豆 | 欧洲精品免费一区二区三区 | 秋霞午夜鲁丝一区二区 | 欧美日韩激情视频在线观看 | 黄色片一区 | 91看片淫黄大片91桃色 | 久久免费播放视频 | 欧美区一区二区三 | 精品一区在线播放 | 91最新入口 | 深夜福利视频在线 | 国产黄色一级网站 | 日日操网站 | 欧美三级大片 |