用 jQuery DatePicker 在 3 分钟内创建一个 ASP.NET 控件






4.64/5 (17投票s)
介绍了一种使用现有 JavaScript 组件创建 ASP.NET 控件的技术。
引言
无论我们创建什么软件,一个好的实践是使用松散耦合的可重用组件来构建它。在 ASP.NET 中,这意味着创建可重用的控件,而不是在 .aspx 页面中实现所有功能。在本文中,我们将基于 jQuery 插件创建 DatePicker
控件,使用我们的团队一直在开发的 LiveUI 框架。原则上,只有两个问题:第一个是将插件的状态与服务器端控件的属性同步,第二个是通知控件有关客户端事件。正如我们将看到的,这两个问题都可以使用 LiveUI 解决。
背景
LiveUI
由于本文的大多数读者都不熟悉 LiveUI,因此有必要简要解释一下它是什么。 LiveUI 是一个面向富 Internet 应用程序的 Web 框架。它提供了 JavaScript 渲染、状态管理和客户端服务器交互的工具。我们将使用的最重要的 LiveUI 类型是 Js
。简而言之,Js
构建 JavaScript 代码的对象模型,供客户端浏览器执行。例如,我们在 C# 中编写:Js.Call(“alert”, Js.Const(“Hello world”))
,浏览器将执行 alert(“Hello world”)
。
日期选择器
DatePicker
是 jQuery.UI
的一部分。 它看起来不错并提供了一个非常简单的 API。 要创建一个新的 DatePicker,我们应该调用 $(#inputFieldId).datepicker()
,$(#inputFieldId).datepicker(‘getdate’)
来获取选定的日期,以及 $(#inputFieldId).datepicker(‘setdate’)
来设置选定的日期。 我选择此插件是因为它可以完美地说明状态同步问题。 DatePicker
控件将具有 SelectedDate
属性,该属性应与客户端插件的值同步。 控件还将具有 ValueChamged
事件,该事件应在用户选择日期时触发。
控件代码
public class Datepicker : ControlBase
{
public event EventHandler ValueSelected;
public DateTime? Value {
get { return ClientState.GetValue("value"); }
set { ClientState.SetValue("value", value); }
}
public override void OnRender(JsCreationSection section)
{
if (!IsRendering)
return;
var textInput = Js.Call("$", Js.Const("#" + ClientID));
textInput.Call("datepicker", Js.Json(
Js.JsonItem("onSelect", Js.Function(delegate {
var request = CreateMethodInvocationRequest("OnValueSelected");
request.Send();
})
)));
ClientState.Synchronize("value",
() => textInput.Call("datepicker", Js.Const("getDate")),
value => textInput.Call("datepicker",
Js.Const("setDate"), value));
}
public void OnValueSelected()
{
if (ValueSelected != null)
ValueSelected(this, EventArgs.Empty);
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<input type='text' id='{0}'/>", ClientID);
}
}
关注点
public override void OnRender(JsCreationSection section)
{
LiveUI 提供 JavaScript "Sections" 以确保在使用时创建所有 JavaScript 对象。 原理很简单:我们创建 JavaScript 方法,例如 OnRender(JsCreationSection section)
,并且可以在 OnRender(JsInitSection section)
中安全地使用它们。 如果实话实说,"Section" 这个词应该替换为 "Phase" 或 "Stage",除非你提出一个更好的名字:)
if (!IsRendering)
return;
如果页面收到异步 AJAX 请求,那么我们的控件不应产生任何 JavaScript,除非它放置在 UpdatePanel
中。 IsRendering
属性封装了所有必需的检查。
var textInput = Js.Call("$", Js.Const("#" + ClientID));
textInput.Call("datepicker", Js.Json(
Js.JsonItem("onSelect", Js.Function(delegate {...
此代码动态渲染 JavaScript,例如
var texbox = $("#myTextbox");
texbox.datepicker({onSelect : function() {....
var request = CreateMethodInvocationRequest("OnValueSelected");
reque request.Send();
LiveUI 提供了一个请求管理基础结构,允许客户端对象调用服务器端方法。 也就是说,动态生成的 JavaScript 代码实例化一个新请求并将其发送到服务器(使用异步回发,这是默认选项)。 顺便说一下,控件的方法应该是 JSON 可序列化的或属于 JsObject
类型。
ClientState.Synchronize("value",
() => textInput.Call("datepicker", Js.Const("getDate")),
value => textInput.Call("datepicker", Js.Const("setDate"), value));
ClientState
是 LiveUI 基础结构中的一个重要元素。 我们可以将其视为一个字典,用于保存客户端对象中的值。 因此,传递给 Synchronize
方法的两个委托只是告诉 ClientState
如何保持 'value'。
结论
虽然我提供的代码可以在三分钟内实现,但了解正在发生的事情需要更长的时间。 我们的团队意识到了这一点,我们正在努力使 API 更清晰并提供更多示例,但如果没有反馈,我们的努力注定要失败。 因此,无论您喜欢还是不喜欢所提供的解决方案,请告诉我们。