熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> ASP編程 >> 正文

C#+ASP.NET 2.0 定制復合組件之高級篇

2013-11-15 12:50:56  來源: ASP編程 

  一 增加EnhancedListBox的客戶端功能
  
    為了使用客戶端代碼實現EnhancedListBox中項的重排序你必須使用JavaScript腳本並且要把它們依附到EnhancedListBox的兩個按鈕上為此我建議你使用往後考慮的方法就象編寫一個老式的ASP以前的Web頁面首先編寫一些生成HTML文件的JavaScript為此最好的方法是運行該控件然後觀察其源碼並把它的HTML代碼復制到一個編輯器再添加JavaScript列表(見下載源代碼)展示了你需要添加到你的控件中的JavaScript的原始形式然後借助於StringBuilder/StringWriter技術(參考源碼列表)該控件構建這部分代碼該JavaScript代碼由兩部分功能組成接收一個HTML控件(在本例中是一個<select>控件)使用選擇索引並且在列表中上下移動它(基本上與我在本文開始我使用服務器代碼向你展示的一樣)現在你要理解你把該JavaScript代碼添加到Web控件的何處為了實現在一個Web表單上有多個EnhancedListBox控件的情況下該JavaScript代碼不會被重復復制你需要使用PageClientScript對象的ReGISterClientScriptBlock方法輸出它
  
    要使這個方法起作用你必須在重載的OnInit事件中調用它(見源碼中列表)
  
    最後為使按鈕正確工作你需要把添加的客戶端方法依附到其上在列表中的代碼中你會看到引用了一個方法RenderButtons盡管我沒有把該代碼在此列出(請參考本文相應源碼)但是它能夠使用我在以前文章中介紹的技術生成按鈕當時在生成實際HTML標簽的之前標簽屬性是使用AddAttribute方法以棧式存放的在此你使用一樣的技術把客戶端方法依附到你的按鈕
  
  string s_MoveUp = MoveItemUp(documentall +thisClientID + );
  outputAddAttribute(HtmlTextWriterAttributeOnClicks_MoveUp);
  
    記住MoveItemUp是你已經編寫成功的JavaScript函數之一在生成用於排序的按鈕之前該代碼將以堆棧存放這些JavaScript命令對於向下(down)按鈕你使用一樣的技術注意我使用ClientId代表該生成後的控件的ID但是在這個控件位於一個復合控件內部時這個屬性要考慮使用父控件的名字
  
    現在你可以成功地把該控件應用於一個Web表單中你可以使用與你操作一個標准ListBox控件一樣的方式在其上添加一些項
  
    事實上這完全是一個投放位置占位符(或ASPNET ListBox控件)當你使用重排序按鈕時你將看到列表中的項相應地改變順序現在讓我們先記下這個問題如果你把一個按鈕拖動到一個Web表單上(不需要為之添加代碼)並執行一個回寄你猜會發生什麼呢?完全與我以前描述的一樣任何你使用重排序按鈕作的重排序改變都將恢復到在最近一次回寄之前該控件看上去的狀態因此讓我們修改一下這個問題
  
    首先我再添加一些JavaScript(源碼列表注意這部分代碼被添加到重載的OnInit方法中並且使用StringBuilder/StringWriter技術進行構建而且這個JavaScript方法的名字是BuildItemList這個函數負責構建列表框完整內容的一個字符串描述並且把該串放到要傳遞到該函數的一個HTML元素的value屬性中你可以把這看作是列表內容的一種串行化該串行化的輸出風格會根據你自己的設計的不同而有所不同調用這個JavaScript函數需要依附到該按鈕上的其它代碼
  
  string s_MoveUp = MoveItemUp(documentall + thisClientID + ); ;
  string s_BuildItemList =BuildItemList(documentall + thisClientID +
  documentall__ + thisClientID + ); ;
  outputAddAttribute(HtmlTextWriterAttributeOnclickMoveUp + + BuildItemList);
  
    現在讓我們來分析一下你發送到BuildItemList函數的兩個參數第一個參數相應於生成的控件(<select>標簽)的ID第二個參數是另外一個ID與前一個命名一致但是前面有一個__這是一個你仍然需要添加到你的Web控件的隱藏的文本框它將作為一個串行化項列表的占位符我要在OnPreRender事件中注冊這個隱藏的文本域
  
  protected override void OnPreRender(EventArgs e)
  {
    baseOnPreRender(e);
   if(Page != null)
   {
    PageClientScriptRegisterHiddenField(__ + thisID );
   }
  }
  
    注意我已經使用我們的控件的ID來標識隱藏的文本域
  
    到目前為止你已經擁有了一個完整功能的Web控件其中客戶端JavaScript被綁定到其中的兩個按鈕上該JavaScript成功地實現在ListBox中的項的重排序並且把其內容串行化為一個字符串然後該字符串被存儲在一個隱藏的文本域中所有這些都發生在客戶端如果一個回寄發生不會發生重排序因為當重排序時控件的Item服務器屬性還沒有收到你對它作的任何改變的消息但是幸運的是位於隱藏的文本域中的表單的一個串行化快照中發生了這一變化現在你有了可以與Item屬性一起使用的內容了那麼接下來你該如何實現呢?

  二 同步
  
    為了在第一次回寄和所有隨後的回寄中實現同步在IPostBackDataHandler接口的實現中提供了一個LoadPostData方法在每一次回寄時都要調用這個LoadPostData方法因此你需要在此做一些工作
  
    值得一提的是ASPNET 修整了一個在版本中被忽視的小地方然而這一修改能夠使你的工作容易許多ASPNET ListBox控件已經在兩個版本()中實現了IPostBackDataHandler接口但是在版本中微軟使這個接口的方法定義虛擬化(virtual在VB中稱作Overridable)這意味著你不必在EnhancedListBox控件中重新實現這個接口而是你僅需重載LoadPostData方法
  
    更重要的是這也意味著你可以存取基類實現而不必創建所有已經存在於你的擴展控件中的功能什麼功能呢?這包括微軟加於其中的一切用於處理Item集合SelectedIndexSelectedValue和SelectedItem屬性及其它許多執行ListBox控件功能的代碼在ASPNET 你必須在你的派生控件中實現這個接口並且要提供你自己對這兩個方法的定義代碼不僅包括你自己的加入的代碼而且還要重復微軟已經在其控制中所實現的一切
  
    我猜測微軟有人已經發現了他們的實現中的錯誤並且把方法變為virtual的這樣開發者能夠存取基類的代碼因此在源碼列表中向你展示如何實現重載的LoadPostData方法在這個重載中你將首先調用基類實現代碼然後加上你需要的代碼以與Item集合同步
  
    另外你還可以利用ListBox控件—通過把它編寫成一個復合控件此時你需要把ListBox中的每一個屬性映射到你的EnhancedListBox以便使它成為ListBox控件的一個投放位置點位符無論使用哪一種方法或者通過LoadPostData方法的重新創建你都仍然需要寫很多代碼如果我專門為ASPNET編寫這個控件那麼我很可能采取最直接的方案復合控件方案
  
    LoadPostData方法使你能夠存取寄送到服務器的每一個域包括你的隱藏文本域(存儲在要傳遞到這個方法的postCollection參數中)你可以問為什麼需要該隱藏文本域而不是使用這個參數來存取被回寄的<select>元素呢?現在我作一下解釋首先回顧一下典型的ASP時代當時你使用RequestForm屬性來存取頁面域在回寄時你能夠存取一個<select>元素的唯一的部分是選擇的項在該方案中你需要完整的列表內容(因此包括隱藏的文本域)列表向你展示如何分析該隱藏的文本域的內容並且把Item重新添加到Item集合中注意你是怎樣調用基類實現的
  
    最後在你第一次生成控件時你必須構建這個隱藏的文本域以防在任何重排序前發生頁面回寄Render方法的最後一行是
  
  outputWrite(<script language=JavaScript>BuildItemList(documentall + thisClientID +documentall__ + thisClientID +);</script>);
  
    你可以在列表的最後看到這一點
  
    現在你可以使用EnhancedListBox控件來重排序一些項回寄並且確保在重新生成頁面前控件的服務器存儲與在客戶端被改變的客戶端存儲完全同步因此現在讓我們使用相同的技術來構建一個復合控件ListMover

  三 構建復合控件—ListMover
  
    這個ListMover控件包含兩個EnhancedListBox控件還有一些按鈕用於在兩個列表之間來回移動項借助於這些復合控件構建技術你可以學習如何創建子控⑶沂褂靡恍〩TML生成它們最終的控件看上去如圖所示對於這個控件你要注意的是某些事情必須發生的位置
  
  
  圖這個ListMover控件提供了一種標准方式讓用戶在兩個列表間移動項
  
    首先借助於與在以前的控件中相同的技術你必須把在這個控件中需要的JavaScript代碼添加到OnInit事件的重載版本中列表顯示了你需要的JavaScript代碼如你在上一個控件中所做的一樣你也是使用JavaScript存取一個ListBox(<select>元素)中的元素而且我已經編制了函數分別實現把項添加到一個列表從一個列表中刪除項以及從一個列表中添加或刪除所有項
  
    我已經進行了功能的分離而不是創建單個move方法這樣以來我可以實現基於屬性設置而使得從一個列表中刪除項成為可選的毫無疑問這可以使最終的控件更為強壯些但是我在本文中不再分析這些代碼還應該注意就象在前面控件中一樣我也添加了一個BuildItemList方法
  
    現在你需要把這一客戶端代碼依附到復合控件的按鈕中你可以在CreateChildControls方法的最後完成這一點並且在此時完成子控件的初始化和構建控件集合在此我僅向你展示相應於一個按鈕的代碼(另外的按鈕代碼與此類似省略)
  
  string s_AddToLeft = AddSelectedItemToList(documentall +
  thislstItemsOnRightClientID + documentall
  + thislstItemsOnLeftClientID + +
  (thisAllowDuplicatesOnLeft ? true : false) + ); ;
  string s_RemoveFromRight = RemoveSelectedItemFromList(documentall +
  thislstItemsOnRightClientID + ); ;
  string s_BuildItemList = BuildItemList(documentall +
  thislstItemsOnRightClientID + documentall__ + lstItemsOnRightClientID + ); + BuildItemList(documentall + thislstItemsOnLeftClientID + documentall__
  + lstItemsOnLeftClientID + ); ;
  thisbtnAddAttributesAdd(onclick s_AddToLeft
  + + s_RemoveFromRight + + s_BuildItemList
  + return false);
  
    注意我實現了在以前的控件中同樣的工作我把JavaScript函數調用構建成一字符串並且把它們依附到一個按鈕上主要區別在於既然這是一個包含其它控件的復合控件那麼你可能使用把代碼添加到onclick事件的AttributesAdd方法這與在一個生成控件中把它放到一個棧上的方法形成對照還要注意我把多個功能放到onclick屬性中而且函數調用的最後返回false以便取消按鈕將執行的任何回寄
  
    最後代碼將在一個對Render重載的方法中初始化對客戶端函數BuildItemList的調用這看起來很象我在EnhancedListBox控件中向你介紹的那個在此不再重復注意在這個控件中我注冊了兩個隱藏的文本域每一個相應於一個ListBox
  
  protected override void OnPreRender(EventArgs e)
  {
   baseOnPreRender(e);
   if(Page != null)
   {
    PageClientScriptReGISterHiddenField(__ + thislstItemsOnRightClientID
  );
    PageClientScriptRegisterHiddenField(__ + thislstItemsOnLeftClientID
  );
    PageRegisterRequiresPostBack(this);
   }
  }
  
    現在你已經構建成功該復合控件能夠提供一些客戶端JavaScript並且把它綁定到按鈕上與以前一樣你可以把它放到一個表單上並且使用它但是在你添加同步代碼之前它仍將會遇到你在第一個控件中所遇到的問題—你可以前後移動項但是一旦你初始化一個回寄(通過表單上的任何其它控件)該控件就會恢復到它回寄之前的狀態
  
    為了修改這個問題你要實現你在第一個控件中所做的同樣的工作然而既然你在開發一個復合控件而不是擴展一個已經現有的控件那麼你需要實現IPostBackDataHandler接口並且提供LoadPostData和RaisePostDataChangedEvent方法的實現代碼這些實現(見列表)與前面的控件基本一致除了你要實現兩個EnhancedListBox控件中的項集合的同步而不是只考慮一個控件外並且與以前一樣你需要確保你保存你的SelectedIndex位置這樣以來在你完成項集合的同步後你就可以把它們設置回去還要注意在第一個控件中你重載了基控件的LoadPostData方法因此在某處調用了它的基類現在既然你要從頭編寫一個復合控件那麼就沒有基類可調用而僅需提供你自己的方法實現
  
    這個控件的最後版本包含若干新的屬性包括用來決定是否添加到一個列表中的項能夠被從另一個列表中刪除的屬性(如果一個列表將允許出現重復項的話)它還包含可擴展的風格化以實現最大化重用的目的等等
  
    就這些你已經使用了可用於客戶端腳本中的隱藏的文本域來存儲列表框的狀態在回寄期間你使用隱藏文本域的內容來與服務器端項集合重新同步最終結果是一個漂亮的復合控件—允許你在沒有服務器回寄的情況下實現各列表項間的來回移動而當一個回寄真正發生時仍能夠保持這種變化 

  四 取二者最優
  
    前面我沒有提及的一個細節是為什麼我在本文中混合了兩個控件文章一開始我首先向你展示了一個標准ListBox控件的增強版本然後把這個增強控件的兩個實例應用於ListMover控件而沒有使用兩個標准ListBox控件來構建這個ListMover在本文中我沒有涉及的是ListMover控件的屬性部分它們將負責映射添加到EnhancedListBox控件上的屬性通過這種方式我就能夠從包含兩個EnhancedListBox控件的ListMover控件中控制兩個EnhancedListBox控件的增強功能因此你可以看到你擁有結合了兩個控件的最好的功能—你有了一個ListMover控件它允許你在兩個列表或單個列表的各項之間進行項的移動與重排序
  
    其實這裡真正關鍵的地方在於面向Web控件的開發—完全封裝本文中的EnhancedListBox控件包含實現其目標(對它的項進行重排序)的所有代碼當我把兩個這種控件包括在一個ListMover控件中時我可以使用所有伴隨著它們的智能性作為新控件的額外功能包括每一個控件含有的客戶端腳本以及在EnhancedListBox控件中的客戶端到服務器的同步功能因此這個ListMover控件只需注意其自己的功能展示了和EnhancedListBox控件在一起的ListMover控件其中重排序按鈕處於開狀態



From:http://tw.wingwit.com/Article/program/ASP/201311/21733.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.