轉帖|其它|編輯:郝浩|2009-03-11 10:30:08.000|閱讀 738 次
概述:.net中開發復合控件
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
如果當前是升序用戶選擇了降序或者當前是降序用戶選擇了升序時,都意味這用戶選擇的改變,所以還需要一種機制來記錄用戶的選擇,這個功能由SortOrderValue 實現,但是這里還容易忽略一個問題就是“默認”的排序方式,如果用戶在使用該控件時沒有在布局代碼里明確指出是升序還是降序,那就需要在Sorter里給出一種默認的排序方式,這個功能有FlipSortOrder屬性完成。
FlipSortOrder屬性主要用于默認排序,如下請看其代碼:
bool _flipSortOrder = false;
public bool FlipSortOrder { get { return _flipSortOrder; } set { _flipSortOrder = value; } }
從這里似乎還可不到它是怎么實現的,在后面介紹SortOrderValue時讀者可以看到它用了“?”運算符進行比較來實現的。
SelectedSortOrder屬性用于生成排序方式(包括按照哪一例),
public string SelectedSortOrder
{ get { return SortColumnValue + " " + SortOrderValue.Trim();} }
例如我們給SortColumnValue傳遞Author,給SortOrderValue傳遞Asc則SelectedSortOrder的值相當于 (Select * from Community_ContentPage Order By) Author Asc
在這里,需要在SortColumnValue和SortOrderValue之間加入空格,這就是SortColumnValue和SortOrderValue直接由一個“+ " " +”的原因。
SortColumnValue屬性設置為列的值,它的值就是前面說的Date Created、View Count、Rating、Title、Date Commented、Date Updated、Author、Default和Topic的任意一個。
public string SortColumnValue {
get {
if (ViewState["SortColumn"] == null)
return _items[0].Value;
else
return (string)ViewState["SortColumn"];
}
set { ViewState["SortColumn"] = value; }
}
讀者可以看到,對于SortColumnValue它的取值為_items[0].Value,這里的items[0]和你布局Sorter的使用有關,例如按照如下的使用方式:
<community:Sorter id="Sorter" align="right" runat="Server">
<ListItem Text="Default Order" value="Default" />
<ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
<ListItem Text="Popularity" value="ViewCount"/>
</community:Sorter>
那么_items[0].Value就是“Default Order”‘如果使用方式如下
<community:Sorter id="Sorter" align="right" runat="Server">
<ListItem Text=" Title " value="Default" />
<ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text=" Default Order " value="Title"/>
<ListItem Text="Popularity" value="ViewCount"/>
</community:Sorter>
那么_items[0].Value就是“Title”。當頁面回傳時使用ViewState記住用戶的選擇。這里Sorter并沒有類似DropDownList的Selected屬性,所以不能夠直接設置被選擇的選項。
SortOrderValue屬性設置為排序的值,它的值是asc或者desc之一。
public string SortOrderValue {
get {
if (ViewState["SortOrder"] == null)
return _flipSortOrder ? "asc" : "desc";
else
return (string)ViewState["SortOrder"];
}
set { ViewState["SortOrder"] = value; }
}
請看這里的“默認”設置,頁面在加載時,SortOrder將為空,前面可以看到_ flipSortOrder的值是false,所以return _flipSortOrder ? "asc" : "des
該文章轉載自1024k:
c"返回的是降序,這就是我們為什么瀏覽頁面時頁面降序顯示的原因。
讀者可以將_ flipSortOrder的值是true,那么當你瀏覽所有區域時,默認將是按照升序進行排序。
,如果SortOrder不為空,SortOrderValue是怎么知道回傳改變的呢?在LoadPostData里有如下代碼:
public bool LoadPostData(String postDataKey, NameValueCollection values)
{ string newSortOrderValue = values[SortOrderHelperID];
if (newSortColumnValue != SortColumnValue || newSortOrderValue != SortOrderValue)
{… SortOrderValue = newSortOrderValue; … }
正如你所看到的,當用戶選擇不同的排序時,LoadPostData會將新值賦值給SortOrderValue,這降導致SortOrderValue的值的改變,然后將用新值生成SQL預計。
SortColumnOptionHelper和SortOrderOptionHelper都是用于檢索選項ListItem的值,它們的區別僅僅是值的不同,SortColumnOptionHelper值是Date Created、View Count、Rating等不固定的,而SortOrderOptionHelper則是Asc或者Desc,但是本質上處理是一樣的,代碼如下:
private string SortColumnOptionHelper(ListItem item) {
if (String.Compare(item.Value, SortColumnValue) == 0)
return String.Format("<option value=\"{0}\" selected=\"selected\">{1}</option>", item.Value, item.Text);
else
return String.Format("<option value=\"{0}\">{1}</option>", item.Value, item.Text);
}
這里請注意如下事項:
(1)Format用于格式化數據,在上面代碼里Format需要格式化兩個變量:item.Value和item.Text,這樣在使用Format格式化時,使用{0}表示第一個參數item.Value,用{0}表示第二個參數item.Text。
(2)對于轉移符號需要使用“\”,例如"<option value=\"{0}\" selected=\"selected\">{1}</option>",我們希望它的輸出類似如下:<option value=”myitemvalue” selected=”selected">myitemText</option>,但是對于引號如果直接寫會被系統直接使用不會輸出,所以使用“\””就可以輸出引號。
private string SortOrderOptionHelper(string itemText, string itemValue) {
if (String.Compare(itemValue, SortOrderValue) == 0)
return String.Format("<option value=\"{0}\" selected=\"selected\">{1}</option>", itemValue, itemText);
else
return String.Format("<option value=\"{0}\">{1}</option>", itemValue, itemText);
}
SortOrderOptionHelper和SortColumnOptionHelper功能類似,后面會介紹。
SortColumnHelperID屬性和SortOrderHelperID屬性用于返回SortColumn/SortOrder下拉框的值,這里sc是SortColumn的縮寫,so是SortOrder的縮寫,如下:
private string SortColumnHelperID
{ get { return UniqueID + "_sc"; } }
private string SortOrderHelperID
{ get { return UniqueID + "_so"; } }
OnChangeHelper用于獲取對客戶端腳本函數的引用,調用該函數將使服務器發送回該頁。該方法還將一個參數傳遞到在服務器上執行回發處理的服務器控件。這里的參數this表示返回到原控件。
private string OnChangeHelper {
get { return "javascript:" + Page.GetPostBackEventReference(this); } }
在后面代碼里可以看到對如下一句代碼
writer.AddAttribute(HtmlTextWriterAttribute.Onchange, OnChangeHelper);
這就告訴系統,當選項發生改變觸發OnChange時,就調用OnChangerHelper腳本,系統通過在頁面生成類似如下腳本
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<script language="javascript">
<!--
function __doPostBack(eventTarget, eventArgument) {
var theform;
if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1) {
theform = document.forms["Form1"];
}
else {
theform = document.Form1;
}
theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// -->
而現在要控件當用戶選擇不同選項時觸發回發就要調用該教本,通過OnChangeHelper返回給客戶端的HTML代碼類似如下:
<select name="sorts_sc" onchange="javascript:__doPostBack('sorts','')">
<select name="sorts_so" onchange="javascript:__doPostBack('sorts','')">
那么如何理解GetPostBackEventReference(this)里面的this參數呢?
This參數指出具體處理返回到該控件本身。例如我在使用該控件的代碼類似如下:
<sort:Sorter runat="server" id="mysorts">
<ListItem Text="Default Order" value="Default" />
<ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
<ListItem Text="Popularity" value="ViewCount"/>
<ListItem Text="Topic" value="Topic" />
</sort:Sorter>
那么它生成的HTML代碼就類似為:
<select name="sorts_sc" onchange="javascript:__doPostBack('mysorts','')">
<select name="sorts_so" onchange="javascript:__doPostBack('mysorts','')">
具體有控件本身處理。
在Sorter里用LoadPostData驗證用戶的選擇由沒有更改,如果更則返回true,否則返回false。
public bool LoadPostData(String postDataKey, NameValueCollection values) {
string newSortColumnValue = values[SortColumnHelperID];
string newSortOrderValue = values[SortOrderHelperID];
if (newSortColumnValue != SortColumnValue || newSortOrderValue != SortOrderValue) {
SortColumnValue = newSortColumnValue;
SortOrderValue = newSortOrderValue;
return true;
} else
return false;
}
請看下面示意圖5-56,
我在選擇排序時,開始使用Title進行排序,當我再次選擇按照Date排序時,此時數據回發到服務器,原來的SortColumnValue的值為Title,而newSortColumnValue的值為Date,這樣
if (newSortColumnValue != SortColumnValue || newSortOrderValue != SortOrderValue) {...}
將返回true,ASP.NET頁框架將自動跟蹤LoadPostDate返回值的控件,對于返回值為true的,則調用RaisePostDataChangedEvent,在Sorter類里就通過在RaisePostDataChangedEvent里調用OnOrderChanged函數實現頁面更新排序。 代碼如下:
public void RaisePostDataChangedEvent() {
OnOrderChanged(EventArgs.Empty);
}
在OnOrderChanged函數里調用orderChanged事件,如下:
public virtual void OnOrderChanged(EventArgs e) {
if (OrderChanged != null)
OrderChanged(this, e);
&nb
該文章轉載自1024k:
sp; }
這樣,我們就可以實現Order改變時的排序。例如在Photo模塊里使用OrderChanged代碼如下:
if (objSorter != null)
objSorter.OrderChanged += new EventHandler(ContentList_OrderChanged);
可以看到,具體的排序由ContentList_OrderChanged完成,后面我們會介紹ContentList_OrderChanged的實現。
將控件注冊為需要回發處理的控件。請注意這里選擇的是OnPreRender。
protected override void OnPreRender(EventArgs e) {
Page.RegisterRequiresPostBack(this);
}
Render判斷有沒有選現,如果沒有選項則項目不顯示該控件。請注意所謂的不顯示該控件就是不調用基類的base.Render()。
protected override void Render(HtmlTextWriter writer) {
if (_items.Count > 0)
base.Render(writer); }
RenderContents方法將呈現SortColumn和SortOrder這兩個下拉框控件。但是具體則是由RenderSortColumn和RenderSortOrder實現。
protected override void RenderContents(HtmlTextWriter writer) {
// 打開tr標記
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
RenderSortColumn(writer);
RenderSortOrder(writer);
writer.RenderEndTag();
}
上面調用的RenderSortColumn和 RenderSortOrder方法代碼如下:
private void RenderSortColumn(HtmlTextWriter writer) {
//獲取SectionInfo信息
SectionInfo objSectionInfo = (SectionInfo)Context.Items["SectionInfo"];
//如果Topic不可用,則從下拉框里移除該選項
ListItem deleteItem;
if (!objSectionInfo.EnableTopics) {
deleteItem = _items.FindByValue( "Topic" );
if (deleteItem != null)
_items.Remove(deleteItem);
}
//如果Rating不可用,則從下拉框里移除該選項
if (!objSectionInfo.EnableRatings) {
deleteItem = _items.FindByValue( "Rating" );
if (deleteItem != null)
_items.Remove(deleteItem);
}
//打開單元格
writer.RenderBeginTag(HtmlTextWriterTag.Td);
//打開select
//這里就使用了SortColumnHelperID以便name的唯一性
writer.AddAttribute(HtmlTextWriterAttribute.Name, SortColumnHelperID);
writer.AddAttribute(HtmlTextWriterAttribute.Onchange, OnChangeHelper);
writer.RenderBeginTag(HtmlTextWriterTag.Select);
// 顯示每一個Item
//讀者可以看到,對于每一個option,分別輸出
foreach (ListItem item in _items) {
writer.Write(SortColumnOptionHelper(item)); }
//關閉Select
writer.RenderEndTag();
//關閉單元個
writer.RenderEndTag();
}
private void RenderSortOrder(HtmlTextWriter writer) {
//打開單元格
writer.RenderBeginTag(HtmlTextWriterTag.Td);
// 打開select
//同樣這里使用了SortOrderHelperID以保證唯一性
writer.AddAttribute(HtmlTextWriterAttribute.Name, SortOrderHelperID);
writer.AddAttribute(HtmlTextWriterAttribute.Onchange, OnChangeHelper);
writer.RenderBeginTag(HtmlTextWriterTag.Select);
//呈現Ascending/Descending
if (_flipSortOrder) {
writer.WriteLine(SortOrderOptionHelper(_ascendingText, "asc"));
writer.WriteLine(SortOrderOptionHelper(_descendingText, "desc"));
} else {
writer.WriteLine(SortOrderOptionHelper(_descendingText, "desc"));
writer.WriteLine(SortOrderOptionHelper(_ascendingText, "asc"));
}
// 關閉 select
writer.RenderEndTag();
// 關閉單元格
writer.RenderEndTag();
}
如果控件 A 在頁上的其控件標記中有嵌套控件,頁分析器會將那些控件的實例添加到 A 的 Controls 集合。這通過調用 A 的 AddSubParsedObject 方法來實現。每個控件從 Control 繼承此方法,默認實現只不過將子控件插入到控件層次結構樹中。通過重寫 AddSubParsedObject 方法,控件可以重寫默認的分析邏輯
在Sorter里當分析特定類型的子控件時,它只會將類型為ListItem的對象添加到集合,而忽略其它對象。
protected override void AddParsedSubObject(Object obj) {
if (obj is ListItem) {
_items.Add((ListItem)obj);
}
}
Sort的構造函數調用基類,并生成table標記,因為他是基于表的
public Sorter() : base(HtmlTextWriterTag.Table) { }
Sorter類里的SorterControlBuilder從ControlBuilder派生,它重寫GetChildControlType方法,使得Sorter標記之間只有為ListItem或者是asp:ListItem時才添加子控件。
還要注意一下,在代碼里不管是ListItem還是asp:ListItem,它返回的都是ListItem,這樣可以放置asp:但被忽略被解析。
public class SorterControlBuilder : ControlBuilder {
public override Type GetChildControlType(String tagName, IDictionary attributes)
{
if (String.Compare(tagName, "ListItem", true) == 0 || String.Compare(tagName, "asp:ListItem", true) == 0)
該文章轉載自1024k:
> { return typeof(ListItem); }
return null;
}
}
}
下面我們給出該控件的基本使用模式
<sort:Sorter runat="server" id="sorts">
<ListItem Text="Default Order" value="Default" />
<ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
<ListItem Text="Popularity" value="ViewCount"/>
<ListItem Text="Topic" value="Topic" />
</sort:Sorter>
同時給出了由基本使用模式生成的HTML代碼,在HTML里,讀者必須明白它不僅僅生成了HTML的select元素,還包括table、tr、td和javascript腳本等
<table id="sorts">
<tr>
<td><select name="sorts_sc" onchange="javascript:__doPostBack('sorts','')">
<option value="Default" selected="selected">Default Order</option><option value="DateCreated">Date Posted</option><option value="Title">Title</option><option value="ViewCount">Popularity</option><option value="Topic">Topic</option>
</select></td><td><select name="sorts_so" onchange="javascript:__doPostBack('sorts','')">
<option value="desc" selected="selected">Descending</option>
<option value="asc">Ascending</option>
</select></td>
</tr>
</table></TD>
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<script language="javascript">
<!--
function __doPostBack(eventTarget, eventArgument) {
var theform;
if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1) {
theform = document.forms["Form1"];
}
else {
theform = document.Form1;
}
theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// -->
</script>
在后面我們將進一步介紹使用客戶端腳本的控件
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:個人博客