EXT.NET-GridPanel

这篇博客详细介绍了如何使用EXT.NET的GridPanel组件,包括页面布局、数据绑定、CRUD操作、查询、排序、分组统计和新建编辑功能。通过实例展示了EXT.NET与ExtJS的列类型对照,并提供了数据库操作代码示例,以及客户端和服务器端的查询、排序、分组和合计功能的实现。此外,还涵盖了新建和编辑窗体的布局和实现过程。
摘要由CSDN通过智能技术生成

概述

前两篇分别介绍了Ext.NET-基础Ext.NET-布局,从本篇开始我们尽量做一些实际工作中用到的例子。

在Ext.NET官方示例中,关于GridPanel的例子是最多的(近百个),篇幅所限,我们这里只介绍一些常用的功能,包括页面布局、新建、编辑、查询、删除、排序、分组、统计等功能。

示例代码下载地址>>>>>

页面总体布局

首先,再来熟悉下前一篇Ext.NET-布局篇中提到的布局技术。

新建WebForm页面,在ASPX文件中加入如下代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
     Inherits="WebFormDemo.GridDemo.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Grid示例</title>
    <link rel="stylesheet" type="text/css" href="../Content/ExtjsExtra.css" />
</head>
<body>
    <ext:ResourceManager runat="server" />
    <ext:Viewport runat="server" Layout="FitLayout">
        <Items>
            <ext:GridPanel runat="server" ID="gridMain">
                <DockedItems>
                    <ext:Toolbar runat="server" Dock="Top">
                        <Items>
                            <ext:Button runat="server" ID="btnAdd" Icon="Add">
                            </ext:Button>
                            <ext:ToolbarSeparator runat="server" />
                            <ext:Button runat="server" ID="btnDelete" Icon="Delete">
                            </ext:Button>
                        </Items>
                    </ext:Toolbar>
                    <ext:PagingToolbar runat="server" Dock="Bottom">
                    </ext:PagingToolbar>
                </DockedItems>
            </ext:GridPanel>
        </Items>
    </ext:Viewport>
</body>
</html>

以上代码在页面中加入了一个铺满整个浏览器窗口的GridPanel控件gridMain;顶端为工具栏,我们打算放一些动作按钮:如新建、删除等;底部未分页工具栏,用于GridPanel的分页;以上代码运行效果如下

页面布局

加入列

上面的代码组织了页面的整体布局,而目前的GridPanel里还没有任何实质性的内容,接下来我们为GridPanel添加需要显示的列。
</DockedItems></ext:GridPanel>之间加入如下代码

<ColumnModel>
    <Columns>
        <ext:RowNumbererColumn runat="server" />
        <ext:Column runat="server" Text="姓名" />
        <ext:NumberColumn runat="server" Text="年龄" />
        <ext:BooleanColumn runat="server" Text="性别" TrueText="男" FalseText="女" />
        <ext:DateColumn runat="server" Text="生日" Format="yyyy-MM-dd" />
        <ext:Column runat="server" Text="民族" />
        <ext:Column runat="server" Text="籍贯" Flex="1" />
        <ext:Column runat="server" Text="备注" Flex="1" Hidden="true" />
    </Columns>
</ColumnModel>

以上代码为GridPanel定义了一个ColumnModel,并定义了ColumnModel所包含的列,需要说明的是

  • <ext:RowNumbererColumn runat="server" /> 行号,将为GridPanel自动生成行号;
  • <ext:Column runat="server" Text="籍贯" Flex="1" />中的Flex="1"指定了此列将占满剩余宽度,多个时自动计算各自宽度,与Ext.NET-布局篇中介绍的Flex一致。

Grid列

Ext.NET与ExtJS中的列类型对照

Ext.NET不仅封装了ExtJS提供的列类型,并加入了一些自己的扩展,如下表

Ext.NET类型 ExtJs类型 说明
ActionColumn Ext.grid.column.Action  
BooleanColumn Ext.grid.column.Boolean  
CheckColumn Ext.grid.column.Check  
Column Ext.grid.column.Column  
CommandColumn - Ext.Net扩展
ComponentColumn - Ext.Net扩展
DateColumn Ext.grid.column.Date  
HyperlinkColumn - Ext.Net扩展,3.x新加,参见此处
ImageCommandColumn - Ext.Net扩展
NumberColumn Ext.grid.column.Number  
ProgressBarColumn - Ext.Net扩展
RatingColumn - Ext.Net扩展
RowNumbererColumn Ext.grid.column.RowNumberer  
SummaryColumn - Ext.Net扩展,已过时
TagColumn - Ext.Net扩展
TemplateColumn Ext.grid.column.Template  
TreeColumn Ext.tree.Column  
WidgetColumn Ext.grid.column.Widget Ext.NET3.x新加,参见此处

上表是Ext.NET与ExtJS列类型对照,每种类型的列提供了一些特殊功能,篇幅所限,不一一介绍,可参见链接指向的说明或示例。

数据库及CRUD代码

目前为止,页面布局完成了一大半,实际的工作中,我们的数据一般是存储在数据库中,所以,为了接下来的例子更贴近实际,先来创建数据库,本例中使用MS SQL Server 2012(Developer Edition)。

数据库访问相关的技术不是本文的主要目的,为了使示例代码尽量简单,这里我们使用MS提供的SqlHelper类,详情参见Data Access Application Block for .NET下载地址.

创建数据库

创建名为ExtNetDemo的数据库加入测试数据,并执行如下脚本创建Person表:

CREATE TABLE [dbo].[Person]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(50) NULL, 
    [Age] INT NULL, 
    [Gender] BIT NULL, 
    [Birthdate] DATETIME NULL, 
    [Ethnic] NVARCHAR(50) NULL, 
    [Origo] NVARCHAR(200) NULL, 
    [Remarks] NVARCHAR(1000) NULL
)
INSERT INTO [dbo].[Person] ([Id], [Name], [Age], [Gender], [Birthdate], [Ethnic], [Origo], [Remarks]) 
VALUES (N'f0d1d8bf-31f4-49c1-ac69-898138356b75', N'任盈盈', 18, 0, N'2015-08-08 00:00:00', N'汉族', N'陕西西安', N'备注')
INSERT INTO [dbo].[Person] ([Id], [Name], [Age], [Gender], [Birthdate], [Ethnic], [Origo], [Remarks]) 
VALUES (N'b1fef104-195d-422c-b729-f0c81149b6f0', N'令狐冲', 26, 1, N'2015-05-05 00:00:00', N'回族', N'河北沧州', N'备注说明')
INSERT INTO [dbo].[Person] ([Id], [Name], [Age], [Gender], [Birthdate], [Ethnic], [Origo], [Remarks]) 
VALUES (N'02ddad1a-91f0-4ec3-8d2b-3ed01c6fda6e', N'风清扬', 35, 1, N'1960-02-05 00:00:00', N'汉族', N'陕西渭南', N'大神')

加入实体类

我们继续使用Ext.NET-基础篇中使用的Person类,修改后的代码如下:

using System;
namespace WebFormDemo
{
    public class Person
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public bool Gender { get; set; }
        public DateTime Birthdate { get; set; }
        public string Ethnic { get; set; }
        public string Origo { get; set; }
        public string Remarks { get; set; }
        public string Desc { get; set; }
    }
}

加入CRUD代码

CRUD代码很枯燥,也不是本文重点。建议用成熟的ORM库或代码生成工具来完成,这里为了使例子简单而尽量不引入更多的库。
在ASPX.CS文件中加入如下代码

#region DAL

private readonly string m_connectionString = ConfigurationManager.ConnectionStrings["default"].ConnectionString;

private IEnumerable<Person> GetPersonList(string where, string orderBy,
    IEnumerable<SqlParameter> paras, int pageIndex, int pageSize)
{
    where = String.IsNullOrEmpty(where) ? "1=1" : where;
    orderBy = String.IsNullOrEmpty(orderBy) ? "Id desc" : orderBy;
    pageIndex = pageIndex > 0 ? pageIndex : 1;
    pageSize = pageSize > 0 ? pageSize : 20;
    int _rowStart = (pageIndex - 1) * pageSize + 1;
    int _rowEnd = pageIndex * pageSize;
    List<Person> result = new List<Person>();
    String sql =
        String.Format("SELECT * FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY {0} ) AS RowNumber,* FROM [" +
            "Person ] WHERE {1}) T WHERE T.RowNumber BETWEEN {2} AND {3} ",
        orderBy, where, _rowStart, _rowEnd);
    var ds = SqlHelper.ExecuteDataset(m_connectionString, System.Data.CommandType.Text, sql, paras.ToArray());

    if (ds != null && ds.Tables.Count > 0 &&
        ds.Tables[0].Columns.Count > 0 && ds.Tables[0].Rows.Count > 0)
    {
        foreach (DataRow row in ds.Tables[0].Rows)
        {
            Person p = new Person();
            p.Age = row.Field<int>("Age");
            p.Birthdate = row.Field<DateTime>("Birthdate");
            p.Ethnic = row.Field<string>("Ethnic");
            p.Gender = row.Field<bool>("Gender");
            p.Id = row.Field<Guid>("Id");
            p.Name = row.Field<string>("Name");
            p.Origo = row.Field<string>("Origo");
            p.Remarks = row.Field<string>("Remarks");
            result.Add(p);
        }
    }

    return result;
}

public int GetRecordCount(string where, IEnumerable<SqlParameter> paras)
{
    int _result = 0;
    where = String.IsNullOrEmpty(where) ? "1=1" : where;
    string _sql = "SELECT COUNT(1) FROM [Person] ";
    if (!String.IsNullOrWhiteSpace(where))
    {
        _sql += " WHERE " + where;
    }
    Object _obj = SqlHelper.ExecuteScalar(m_connectionString, CommandType.Text, _sql, paras.ToArray());
    if (!Object.Equals(null, _obj) && !Object.Equals(DBNull.Value, _obj))
    {
        Int32.TryParse(_obj.ToString(), out _result);
    }
    return _result;
}

public bool Insert(Person p)
{
    if (p == null)
    {
        return false;
    }
    p.Id = Guid.NewGuid();
    StringBuilder _sb = new StringBuilder();
    _sb.Append("INSERT INTO [Person] ");
    _sb.Append("([Id],[Name],[Age],[Gender],[Birthdate],[Ethnic],[Origo],[Remarks])");
    _sb.Append(" VALUES ");
    _sb.Append("(@Id,@Name,@Age,@Gender,@Birthdate,@Ethnic,@Origo,@Remarks)");

    SqlParameter[] _paras = {
            new SqlParameter("@Id", p.Id),
            new SqlParameter("@Name", p.Name),
            new SqlParameter("@Age", p.Age),
            new SqlParameter("@Gender", p.Gender),
            new SqlParameter("@Birthdate", p.Birthdate),
            new SqlParameter("@Ethnic", p.Ethnic),
            new SqlParameter("@Origo", p.Origo),
            new SqlParameter("@Remarks", p.Remarks)
            };
    int _rowsAffected = 0;

    _rowsAffected = SqlHelper.ExecuteNonQuery(m_connectionString,
        CommandType.Text, _sb.ToString(), _paras);

    return _rowsAffected > 0;
}

public bool Update(Person p)
{
    if (p == null)
    {
        return false;
    }

    StringBuilder _sb = new StringBuilder();
    _sb.Append("UPDATE [Person] SET ");
    _sb.Append("[Id]=@Id,[Name]=@Name,[Age]=Age,[Gender]=@Gender,");
    _sb.Append("[Birthdate]=@Birthdate,[Ethnic]=@Ethnic,[Origo]=@Origo,[Remarks]=@Remarks ");
    _sb.Append(" WHERE [Id]=@Id");

    SqlParameter[] _paras = {
            new SqlParameter("@Id", p.Id),
            new SqlParameter("@Name", p.Name),
            new SqlParameter("@Age", p.Age),
            new SqlParameter("@Gender", p.Gender),
            new SqlParameter("@Birthdate", p.Birthdate),
            new SqlParameter("@Ethnic", p.Ethnic),
            new SqlParameter("@Origo", p.Origo),
            new SqlParameter("@Remarks", p.Remarks)
            };
    int _rowsAffected = 0;

    _rowsAffected = SqlHelper.ExecuteNonQuery(m_connectionString,
        CommandType.Text, _sb.ToString(), _paras);

    return _rowsAffected > 0;
}

public bool Delete(IEnumerable<Guid> ids)
{
    if (ids == null || ids.Count() < 1)
    {
        return false;
    }

    string sql = "DELETE FROM [Person] WHERE ";
    string where = String.Empty;
    foreach (var key in ids)
    {
        if (String.IsNullOrEmpty(where))
        {
            where = String.Format(" [Id]='{0}' ", key);
        }
        else
        {
            where += String.Format(" OR [Id]='{0}' ", key);
        }
    }
    sql += where;
    int _rowsAffected = 0;
    _rowsAffected = SqlHelper.ExecuteNonQuery(m_connectionString, CommandType.Text, sql);

    return _rowsAffected > 0;
}

#endregion

加入Store

GridPanel必须与Store结合使用才能显示数据,这通常令Ext.NET新手感到不习惯,可以理解为Store为GridPanel提供了数据源,可参见ExtJs API中关于 GridPanel Store的说明

Store通常也用在TreePanel、ComboBox中,当然,Store也可独立存在做其它使用。Store对多个实体对象进行封装,并在客户端缓存;Store通过Proxy加载数据,并提供了对实体对象集合的排序、查询等功能。

关于Store的详细说明参见 Ext.data.Store

为GridPanel加入Store可以使用两种方式:

  • GridPanel的StoreID属性指定一个外部定义的Store的ID;
  • 在GridPanel中定义,如<Store>此处定义真实的Store</Store>

定义Store

本例中我们使用后者,在<ext:GridPanel runat="server">...</ext:GridPanel>中加入如下代码:

<Store>
    <ext:Store runat="server" ID="storeMain">
        <Model>
            <ext:Model runat="server" IDProperty="Id">
                <Fields>
                    <ext:ModelField Name="Id" />
                    <ext:ModelField Name="Name" Type="String" />
                    <ext:ModelField Name="Age" Type="Int" />
                    <ext:ModelField Name="Gender" Type="Boolean" />
                    <ext:ModelField Name="Birthdate" Type="Date" />
                    <ext:ModelField Name="Ethnic" />
                    <ext:ModelField Name="Origo" />
                    <ext:ModelField Name="Remarks" />
                </Fields>
            </ext:Model>
        </Model>
    </ext:Store>
</Store>

如上,Store中的Model定义了一个实体类型,与我们在服务器端的Person类相似,不过此处的Model存在于客户端浏览器中。

  • <ext:Model runat="server" IDProperty="Id">中的IDProperty="Id"指明了Model中的主键,默认值为"id"
  • <Fields></Fields>中定义了实体的字段;
  • 其中Type="Boolean"等指明了字段的数据类型,可选项有AutoBooleanDateFloatIntObjectString,默认为Auto

详细说明请参考:
1. Ext.data.Store
2. Ext.data.Model
3. Ext.data.field.Field

为Column指定DataIndex

上面我们为GridPanel定义好了Store,那么,如何使GridPanel中显示的列与Store.Model中定义的Field对应上呢?也就是说,如何为GridPanel指定每列要显示的内容呢?
答案是为Columns中的每一列设置DataIndex属性,修改前面指定的<Columns></Columns>中的每列Column的DataIndex属性,如下

<ColumnModel>
    <Columns>
        <ext:RowNumbererColumn runat="server" />
        <ext:Column runat="server" Text="姓名" DataIndex="Name" />
        <ext:NumberColumn runat="server" Text="年龄" DataIndex="Age"/>
        <ext:BooleanColumn runat="server" Text="性别" TrueText="男" 
            FalseTex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值