65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (17投票s)

2009年12月14日

CPOL

3分钟阅读

viewsIcon

127160

downloadIcon

8022

介绍了一种使用现有 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”)

日期选择器

DatePickerjQuery.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 更清晰并提供更多示例,但如果没有反馈,我们的努力注定要失败。 因此,无论您喜欢还是不喜欢所提供的解决方案,请告诉我们。

© . All rights reserved.