ASP.NET 2.0中callback的一些變化+使用示例(上)
轉自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1761990
可能你覺得callback很弱,AJAX才夠強。其實網上大多數callback的示例代碼都是不太正確的(包括MSDN)。這裏提供了一種不同的使用callback的方法。只用很少的javascript就實現了一個聯級下拉清單。你會發現:羽量級的callback其實也很好用。
在這裏我有兩個DropDownList,ddlCategory和ddlProduct。要求ddlCategory變化後ddlProduct無刷新的填充新的專案。
要使用Callback首先要繼承ICallbackEventHandler介面:
public partial class Callback : Page, ICallbackEventHandler 或:
<%@ Implements Interface="System.Web.UI.ICallbackEventHandler" %>
正式版的ICallbackEventHandler要實現以下兩個方法:
string GetCallbackResult ()
void RaiseCallbackEvent (string eventArgument)
eventArgument現在改為由RaiseCallbackEvent接收,而不是由GetCallbackResult直接接受了。目的是為了讓你可以在RaiseCallbackEvent中做一些初始化操作,這點在編寫支援callback的控制項時特別有用,有興趣的話你可以參考GridView和DetailView中RaiseCallbackEvent的代碼。在這裏我只使用最簡單的方式,把eventArgument存到一個私有成員中: private string _callbackEventArgument;
protected virtual void RaiseCallbackEvent(string eventArgument)
{
this._callbackEventArgument = eventArgument;
}
在用戶端觸發callback需要使用到GetCallbackEventReference,正式版中的GetCallbackEventReference位於Page.ClientScript下。ClientScript是2.0中Page的一個新增成員,專門用於處理用戶端教本(javascript),它是一個實例化的ClientScriptManager。
<script type="text/javascript">
function CallServer(arg, context)
{
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
}
function ReceiveServerData(result, context)
{
...
}
</script>
protected void Page_Load(object sender, EventArgs e)
{
ddlCategory.Attributes.Add("onchange", "CallServer(....)");
}
f在這裏我使用了一個javascript函數CallServer來包裝callback的觸發,當然你也可把它直接掛到onchange或其他用戶端事件上。不過用一個函數來包裝的話,可以很方便的在callback前後做一些其他操作,下面我就會用到。
不知道你有沒有發覺,我們傳給callback兩個參數:arg和context,但是RaiseCallbackEvent只得到一個(arg),另一個參數context會給原封不動的傳給ReceiveServerDate。這個context到底有什麼用呢?甚至連MSDN裏的代碼也沒有很正確的使用這個參數。可能你覺得callback很弱,只傳入一個string(arg)傳出一個string(result),還要編寫大量的javascript代碼才能實現想要的功能。其實,只要正確使用上面那個context參數就可以用很少的javascript實現很理想的功能。
首先,我們拆分一下arg,把我們要調用的服務端方法放進去:
ddlCategory.Attributes.Add("onchange", "CallServer('FillProduct|'+this.value, ...)");
然後用反射在伺服器端調用這個方法(FillProduct):
public string GetCallbackResult()
{
string[] parts = _callbackEventArgument.Split('|');
return this.GetType().GetMethod(parts[0]).Invoke(this, new objcet[]{parts[1]}) ;
}
我們來看看FillProduct會返回些什麼:
public string FillProduct(string categoryID)
{
ddlCategory.SelectedValue = categoryID;
ddlProduct.DataBind();
StringWriter writer1 = new StringWriter(CultureInfo.InvariantCulture);
HtmlTextWriter writer2 = new HtmlTextWriter(writer1);
ddlProduct.RenderControl(writer2);
writer2.Flush();
writer2.Close();
return writer1.ToString();
}
你可以看到,我把需要更新的ddlProduct整個重新Render後傳回來了,也就是說要用新生成的ddlProduct的HTML替換原來的ddlProduct的HTML。怎麼做到這一點呢?context參數要出馬了:
<script type="text/javascript">
function CallServer(arg, context)
{
context.innerHTML = "Loading";
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
}
function ReceiveServerData(result, context)
{
context.innerHTML = result;
}
</script>
.....
<asp:DropDownList ID="ddlCategory" runat="server" DataSourceID="SqlDataSource1"
DataTextField="CategoryName" DataValueField="CategoryID" AppendDataBoundItems="True" >
<asp:ListItem Value="">- Select Category -</asp:ListItem>
</asp:DropDownList>
<span id="_span1">
<asp:DropDownList ID="ddlProduct" runat="server" DataSourceID="SqlDataSource2"
DataTextField="ProductName" AppendDataBoundItems="True">
<asp:ListItem Value="">- Select Product -</asp:ListItem>
</asp:DropDownList>
</span>
protected void Page_Load(object sender, EventArgs e)
{
ddlCategory.Attributes.Add("onchange", "CallServer('FillProduct|'+this.value, _span1)");
}
原來我把要更新的ddlProduct放在_span1裏,context就是用來傳遞這個_span1的。只要用新生成的HTML填充這個_span1,ddlProduct的更新就OK了。這樣我們就很輕鬆的完成了一個無刷新的聯級下拉清單。
需要注意的是,要在頁面提交(postback)後取得這個ddlProduct的值,需要使用 Request.Form[ddlProduct.UniqueID] 因為viewstate並沒有被更新。
更新:或者可以把ddlProduct的EnableViewState改為False,然後就可以用ddlProduct.SelectedValue取值了。但是這樣做在複雜的頁面中可能會引起一些錯誤,要更具具體情況謹慎處理。
ASP.NET 2.0中callback的一些變化+使用示例(上)
ASP.NET 2.0中callback的一些變化+使用示例(中)
ASP.NET 2.0中callback的一些變化+使用示例(下)
留言列表