轉(zhuǎn)帖|其它|編輯:郝浩|2009-03-11 10:30:08.000|閱讀 738 次
概述:.net中開發(fā)復(fù)合控件
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
如果當(dāng)前是升序用戶選擇了降序或者當(dāng)前是降序用戶選擇了升序時,都意味這用戶選擇的改變,所以還需要一種機(jī)制來記錄用戶的選擇,這個功能由SortOrderValue 實現(xiàn),但是這里還容易忽略一個問題就是“默認(rèn)”的排序方式,如果用戶在使用該控件時沒有在布局代碼里明確指出是升序還是降序,那就需要在Sorter里給出一種默認(rèn)的排序方式,這個功能有FlipSortOrder屬性完成。
FlipSortOrder屬性主要用于默認(rèn)排序,如下請看其代碼:
bool _flipSortOrder = false;
public bool FlipSortOrder { get { return _flipSortOrder; } set { _flipSortOrder = value; } }
從這里似乎還可不到它是怎么實現(xiàn)的,在后面介紹SortOrderValue時讀者可以看到它用了“?”運算符進(jìn)行比較來實現(xiàn)的。
SelectedSortOrder屬性用于生成排序方式(包括按照哪一例),
public string SelectedSortOrder
{ get { return SortColumnValue + " " + SortOrderValue.Trim();} }
例如我們給SortColumnValue傳遞Author,給SortOrderValue傳遞Asc則SelectedSortOrder的值相當(dāng)于 (Select * from Community_ContentPage Order By) Author Asc
在這里,需要在SortColumnValue和SortOrderValue之間加入空格,這就是SortColumnValue和SortOrderValue直接由一個“+ " " +”的原因。
SortColumnValue屬性設(shè)置為列的值,它的值就是前面說的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的使用有關(guān),例如按照如下的使用方式:
<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”。當(dāng)頁面回傳時使用ViewState記住用戶的選擇。這里Sorter并沒有類似DropDownList的Selected屬性,所以不能夠直接設(shè)置被選擇的選項。
SortOrderValue屬性設(shè)置為排序的值,它的值是asc或者desc之一。
public string SortOrderValue {
get {
if (ViewState["SortOrder"] == null)
return _flipSortOrder ? "asc" : "desc";
else
return (string)ViewState["SortOrder"];
}
set { ViewState["SortOrder"] = value; }
}
請看這里的“默認(rèn)”設(shè)置,頁面在加載時,SortOrder將為空,前面可以看到_ flipSortOrder的值是false,所以return _flipSortOrder ? "asc" : "des
該文章轉(zhuǎn)載自1024k:
c"返回的是降序,這就是我們?yōu)槭裁礊g覽頁面時頁面降序顯示的原因。
讀者可以將_ flipSortOrder的值是true,那么當(dāng)你瀏覽所有區(qū)域時,默認(rèn)將是按照升序進(jìn)行排序。
,如果SortOrder不為空,SortOrderValue是怎么知道回傳改變的呢?在LoadPostData里有如下代碼:
public bool LoadPostData(String postDataKey, NameValueCollection values)
{ string newSortOrderValue = values[SortOrderHelperID];
if (newSortColumnValue != SortColumnValue || newSortOrderValue != SortOrderValue)
{… SortOrderValue = newSortOrderValue; … }
正如你所看到的,當(dāng)用戶選擇不同的排序時,LoadPostData會將新值賦值給SortOrderValue,這降導(dǎo)致SortOrderValue的值的改變,然后將用新值生成SQL預(yù)計。
SortColumnOptionHelper和SortOrderOptionHelper都是用于檢索選項ListItem的值,它們的區(qū)別僅僅是值的不同,SortColumnOptionHelper值是Date Created、View Count、Rating等不固定的,而SortOrderOptionHelper則是Asc或者Desc,但是本質(zhì)上處理是一樣的,代碼如下:
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用于格式化數(shù)據(jù),在上面代碼里Format需要格式化兩個變量:item.Value和item.Text,這樣在使用Format格式化時,使用{0}表示第一個參數(shù)item.Value,用{0}表示第二個參數(shù)item.Text。
(2)對于轉(zhuǎn)移符號需要使用“\”,例如"<option value=\"{0}\" selected=\"selected\">{1}</option>",我們希望它的輸出類似如下:<option value=”myitemvalue” selected=”selected">myitemText</option>,但是對于引號如果直接寫會被系統(tǒng)直接使用不會輸出,所以使用“\””就可以輸出引號。
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用于獲取對客戶端腳本函數(shù)的引用,調(diào)用該函數(shù)將使服務(wù)器發(fā)送回該頁。該方法還將一個參數(shù)傳遞到在服務(wù)器上執(zhí)行回發(fā)處理的服務(wù)器控件。這里的參數(shù)this表示返回到原控件。
private string OnChangeHelper {
get { return "javascript:" + Page.GetPostBackEventReference(this); } }
在后面代碼里可以看到對如下一句代碼
writer.AddAttribute(HtmlTextWriterAttribute.Onchange, OnChangeHelper);
這就告訴系統(tǒng),當(dāng)選項發(fā)生改變觸發(fā)OnChange時,就調(diào)用OnChangerHelper腳本,系統(tǒng)通過在頁面生成類似如下腳本
<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();
}
// -->
而現(xiàn)在要控件當(dāng)用戶選擇不同選項時觸發(fā)回發(fā)就要調(diào)用該教本,通過OnChangeHelper返回給客戶端的HTML代碼類似如下:
<select name="sorts_sc" onchange="javascript:__doPostBack('sorts','')">
<select name="sorts_so" onchange="javascript:__doPostBack('sorts','')">
那么如何理解GetPostBackEventReference(this)里面的this參數(shù)呢?
This參數(shù)指出具體處理返回到該控件本身。例如我在使用該控件的代碼類似如下:
<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進(jìn)行排序,當(dāng)我再次選擇按照Date排序時,此時數(shù)據(jù)回發(fā)到服務(wù)器,原來的SortColumnValue的值為Title,而newSortColumnValue的值為Date,這樣
if (newSortColumnValue != SortColumnValue || newSortOrderValue != SortOrderValue) {...}
將返回true,ASP.NET頁框架將自動跟蹤LoadPostDate返回值的控件,對于返回值為true的,則調(diào)用RaisePostDataChangedEvent,在Sorter類里就通過在RaisePostDataChangedEvent里調(diào)用OnOrderChanged函數(shù)實現(xiàn)頁面更新排序。 代碼如下:
public void RaisePostDataChangedEvent() {
OnOrderChanged(EventArgs.Empty);
}
在OnOrderChanged函數(shù)里調(diào)用orderChanged事件,如下:
public virtual void OnOrderChanged(EventArgs e) {
if (OrderChanged != null)
OrderChanged(this, e);
&nb
該文章轉(zhuǎn)載自1024k:
sp; }
這樣,我們就可以實現(xiàn)Order改變時的排序。例如在Photo模塊里使用OrderChanged代碼如下:
if (objSorter != null)
objSorter.OrderChanged += new EventHandler(ContentList_OrderChanged);
可以看到,具體的排序由ContentList_OrderChanged完成,后面我們會介紹ContentList_OrderChanged的實現(xiàn)。
將控件注冊為需要回發(fā)處理的控件。請注意這里選擇的是OnPreRender。
protected override void OnPreRender(EventArgs e) {
Page.RegisterRequiresPostBack(this);
}
Render判斷有沒有選現(xiàn),如果沒有選項則項目不顯示該控件。請注意所謂的不顯示該控件就是不調(diào)用基類的base.Render()。
protected override void Render(HtmlTextWriter writer) {
if (_items.Count > 0)
base.Render(writer); }
RenderContents方法將呈現(xiàn)SortColumn和SortOrder這兩個下拉框控件。但是具體則是由RenderSortColumn和RenderSortOrder實現(xiàn)。
protected override void RenderContents(HtmlTextWriter writer) {
// 打開tr標(biāo)記
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
RenderSortColumn(writer);
RenderSortOrder(writer);
writer.RenderEndTag();
}
上面調(diào)用的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)); }
//關(guān)閉Select
writer.RenderEndTag();
//關(guān)閉單元個
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);
//呈現(xiàn)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"));
}
// 關(guān)閉 select
writer.RenderEndTag();
// 關(guān)閉單元格
writer.RenderEndTag();
}
如果控件 A 在頁上的其控件標(biāo)記中有嵌套控件,頁分析器會將那些控件的實例添加到 A 的 Controls 集合。這通過調(diào)用 A 的 AddSubParsedObject 方法來實現(xiàn)。每個控件從 Control 繼承此方法,默認(rèn)實現(xiàn)只不過將子控件插入到控件層次結(jié)構(gòu)樹中。通過重寫 AddSubParsedObject 方法,控件可以重寫默認(rèn)的分析邏輯
在Sorter里當(dāng)分析特定類型的子控件時,它只會將類型為ListItem的對象添加到集合,而忽略其它對象。
protected override void AddParsedSubObject(Object obj) {
if (obj is ListItem) {
_items.Add((ListItem)obj);
}
}
Sort的構(gòu)造函數(shù)調(diào)用基類,并生成table標(biāo)記,因為他是基于表的
public Sorter() : base(HtmlTextWriterTag.Table) { }
Sorter類里的SorterControlBuilder從ControlBuilder派生,它重寫GetChildControlType方法,使得Sorter標(biāo)記之間只有為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)
該文章轉(zhuǎn)載自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>
在后面我們將進(jìn)一步介紹使用客戶端腳本的控件
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:個人博客