使用 SharpKit 构建客户端网格控件





5.00/5 (12投票s)
使用 SharpKit 在 C# 中构建客户端网格控件的示例代码
引言
此示例代码将向您展示如何使用 SharpKit 编写客户端网格控件。SharpKit 是一种工具,允许您编写 C# 代码并在编译期间将其转换为 JavaScript。此过程可以帮助您更快地编写代码,并减少错误,它还可以帮助您记录代码,以便其他开发人员可以更轻松地使用它。因此,为避免混淆,此处的所有代码都将以 C# 形式显示,但实际上,它是标准 JavaScript 代码,可以在有或没有 SharpKit 的情况下使用。
我们将从学习如何实现 Grid
开始,然后继续使用 Grid
,最后,学习如何优化 DOM 操作以支持旧版浏览器。
实现网格
网格类
[JsType(JsMode.Prototype, Filename = "Grid.js")]
public class Grid : HtmlContext
{
public Grid()
{
Rows = new JsArray<GridRow>();
}
public HtmlElement Element { get; set; }
public HtmlElement GridBody { get; set; }
public JsArray<GridRow> Rows { get; set; }
public void Render()
{
if (Element == null)
return;
Element["_Grid"] = this;
if (GridBody == null || GridBody.nodeName != "TBODY")
{
GridBody = document.createElement("TBODY");
Element.appendChild(GridBody);
}
}
}
这个 Grid
类旨在以下列模式使用
var grid = new Grid { Element = document.getElementById("MyGrid") };
grid.Render();
GridRow 类
grid
类有一个 Rows 集合,其中每一行都是 GridRow
类型。GridRow
是一个 json 类,这意味着它仅用于包含有关该行的数据,在我们的例子中,我们将包含对表格行元素(TR
元素)的引用,以及一个将该行与某些数据对象关联的 Data
属性。
[JsType(JsMode.Json)]
public class GridRow
{
public HtmlElement Element { get; set; }
public object Data { get; set; }
}
GridRow
类旨在以下列模式使用
var row = new GridRow
{ Element = grid.CreateRow(document.getElementById("MyGridRowTemplate")) };
grid.AddRow(row);
添加一行
现在是时候实现一个 AddRow
方法了,它将向我们的 Rows
集合添加一个 GridRow
,并将其附加到 DOM 中。
public void AddRow(GridRow gr)
{
var body = GridBody;
body.appendChild(gr.Element);
gr.Element["_GridRow"] = gr;
Rows.push(gr);
}
从模板创建行元素
public HtmlElement CreateRowElement(HtmlElement template)
{
return template.cloneNode(true);
}
此方法仅克隆一个元素,在我们的例子中,这将是 TR
元素,用于在 grid
中为每一行克隆。
使用网格
现在,我们已准备好使用 grid
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Grid Demo - SharpKitSamples</title>
<link href="Grid.css" rel="stylesheet" type="text/css" />
<script src="res/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Grid.js" type="text/javascript"></script>
<script src="GridDemo.js"></script>
<script>$(Load);</script>
</head>
<body>
<h1>Grid Demo</h1>
<table id="MyGrid" class="Grid">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Phone Number</th>
<th>Description</th>
</tr>
</thead>
<tbody style="display: none">
<tr id="MyGridRowTemplate">
<td class="CellName"></td>
<td class="CellAge"></td>
<td class="CellPhoneNumber"></td>
<td class="CellDescription"></td>
</tr>
</tbody>
</table>
</body>
</html>
此 HTML 文件包含一个用于 grid
的 TABLE
元素,其中包含一些标题和一个行模板。我们可以克隆此行以在 grid
中创建新行。您还可以注意到 $(Load)
代码,它实际上是 jQuery ready 事件,这意味着当 DOM 就绪时,将调用 Load()
函数。
[JsType(JsMode.Global, Filename = "GridDemo.js")]
public class GridDemoClient : jQueryContextBase
{
public static void Load()
{
var list = new JsArray<Contact>();
for (var i = 0; i < 30; i++)
{
var c = new Contact { Name = "MyContact" + i, Age = i,
PhoneNumber = "44557799" + i, Description="This is a contact "+i };
list.push(c);
}
var grid = new Grid { Element = document.getElementById("MyGrid") };
grid.Render();
foreach (var c in list)
{
var row = new GridRow { Element = grid.CreateRow
(document.getElementById("MyGridRowTemplate")), Data = c };
var tr = J(row.Element);
tr.find(".CellName").text(c.Name);
tr.find(".CellPhoneNumber").text(c.PhoneNumber);
tr.find(".CellAge").text(c.Age.ToString());
tr.find(".CellDescription").text(c.Description);
grid.AddRow(row);
}
}
}
在此代码中,我们正在生成 30 个示例联系人,然后我们为它们创建 GridRow
对象,我们还创建从我们的模板克隆的 TR
元素,并将联系人实例的数据绑定到每一行。
实现排序
有了可靠的网格 API,实现排序等功能就很容易了,我们所要做的就是清除网格中的行,对它们进行排序,然后将它们渲染回网格。
public static void SortByName()
{
var rows = Grid.Rows.OrderBy(t => t.Data.As<Contact>().Name);
Grid.DeleteAllRows();
foreach (var row in rows)
Grid.AddRow(row);
}
OrderBy
方法是在一个小实用程序类中实现的自定义扩展方法
[JsType(JsMode.Prototype, Filename = "GridDemo.js")]
static class JsArrayExtensions
{
public static JsArray<T> OrderBy<T>(this JsArray<T> array,
JsFunc<T, object> selector, bool desc)
{
var array2 = array.slice(0);
if (!desc)
array2.sort((x, y) => Compare(selector(x), selector(y)));
else
array2.sort((x, y) => CompareDesc(selector(x), selector(y)));
return array2;
}
static JsNumber Compare(object x, object y)
{
var xx = x.As<int>();
var yy = y.As<int>();
if (xx > yy)
return 1;
if (xx < yy)
return -1;
return 0;
}
}
这是 JavaScript 数组上的简化的 LINQ 排序实现,它使用扩展方法实现,以使代码使用更容易,更易于阅读。它仍然由 SharpKit 转换为纯 JavaScript。
下一步是支持按任何属性排序,并记住我们上次完成的排序,以在 升序
和 降序
排序之间切换。我们还应该更改当前已排序列的外观,以便用户了解 grid
已排序。
static Grid Grid;
static HtmlTableCell LastSortHeader;
static JsString LastSort;
static bool IsLastSortDescending;
public static void SortBy(HtmlTableCell header, JsString pe)
{
J(LastSortHeader).removeClass("Sorted").removeClass("Descending");
IsLastSortDescending = LastSort == pe && !IsLastSortDescending;
LastSort = pe;
LastSortHeader = header;
J(LastSortHeader).addClass("Sorted");
J(LastSortHeader).toggleClass("Descending", IsLastSortDescending);
var rows = Grid.Rows.OrderBy(t => t.Data.As<JsObject>()[pe], IsLastSortDescending);
Grid.DeleteAllRows();
foreach (var row in rows)
Grid.AddRow(row);
}
现在,缺少的就是在单击 grid
标题时调用 SortBy
方法
<table id="MyGrid" class="Grid">
<thead>
<tr>
<th onclick="SortBy(this, 'Name');">Name</th>
<th onclick="SortBy(this, 'Age');">Age</th>
<th onclick="SortBy(this, 'PhoneNumber');">Phone Number</th>
<th onclick="SortBy(this, 'Description');">Description</th>
</tr>
</thead>
<tbody style="display: none">
<tr id="MyGridRowTemplate">
<td class="CellName"></td>
<td class="CellAge"></td>
<td class="CellPhoneNumber"></td>
<td class="CellDescription"></td>
</tr>
</tbody>
</table>
就是这样,简单、直接、快速且高度可定制。
优化网格
旧版浏览器可能会变慢,有时简单的 jQuery 用法会导致像 IE7 这样的浏览器出现严重的性能损失,有时您必须自己动手并实现自己的优化 DOM API。SharpKit 允许我通过实现扩展方法来轻松地执行此操作。它使代码易于阅读和维护。
[JsType(JsMode.Prototype, Filename = "Grid.js")]
static class Extensions
{
public static void AppendChildFast(this HtmlElement el,
HtmlElement newElement, HtmlElement lastChild)
{
if (lastChild != null && SupportsInsertAdjacentElement)
lastChild.insertAdjacentElement("afterEnd", newElement);
else
el.appendChild(newElement);
}
}
现在,我可以像在 HtmlElement
上使用方法一样使用 el.AppendChildFast()
,而实际上,它是一个 static
扩展方法。关于此方法,在 IE7 等旧浏览器中,appendChild()
可能会非常慢,因为浏览器会迭代所有同级节点,直到到达末尾才能添加该元素。此方法获取指向 lastChild
的指针,并使用 insertAdjacentElement
方法添加元素,而无需这种开销。
关注点
总之,编写 JavaScript 代码有时可能会很复杂,使用 SharpKit 允许我们专注于编写代码,然后在之后执行重构和清理。也可以添加 XML 文档并生成帮助文件,以允许其他开发人员轻松集成您的组件。
历史
- 2012 年 1 月 30 日:初始版本