服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#在Winform开发中使用Grid++报表

C#在Winform开发中使用Grid++报表

2022-07-13 09:30伍华聪 C#

这篇文章主要介绍了C#在Winform开发中使用Grid++报表,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

之前一直使用各种报表工具,如RDLC、DevExpress套件的XtraReport报表,在之前一些随笔也有介绍,最近接触锐浪的Grid++报表,做了一些测试例子和辅助类来处理报表内容,觉得还是很不错的,特别是它的作者提供了很多报表的设计模板案例,功能还是非常强大的。试着用来做一些简单的报表,测试下功能,发现常规的二维表、套打、条形码二维码等我关注的功能都有,是一个比较强大的报表控件,本篇随笔主要介绍在Winform开发中使用Grid++报表设计报表模板,以及绑定数据的处理过程。

1、报表模板设计

这个报表系统,报表模板提供了很多案例,我们可以大概浏览下其功能。

C#在Winform开发中使用Grid++报表

它对应在相应的文件目录里面,我们可以逐一查看了解下,感觉提供这么多报表还是很赞的,我们可以参考着来用,非常好。

C#在Winform开发中使用Grid++报表

整个报表主要是基于现有数据进行一个报表的模板设计的,如果要预览效果,我们一般是需要绑定现有的数据,可以从各种数据库提供数据源,然后设计报表模板,进行实时的数据和格式查看及调整。

空白的报表模板大概如下所示,包含页眉页脚,以及明细表格的内容。

C#在Winform开发中使用Grid++报表

根据它的教程,模仿着简单的做了一个报表,也主要是设计报表格式的调整,和数据源的处理的关系,我们做一个两个报表就可以很快上手了。

为了动态的加入我们表格所需要的列,我们可以通过数据库里面的字段进行加入,首先提供数据源,指定我们具体的表即可(如果是自定义的信息,则可以手工添加字段)

C#在Winform开发中使用Grid++报表

这个里面就是配置不同的数据库数据源了

C#在Winform开发中使用Grid++报表

如SQLServer数据库的配置信息如下。

C#在Winform开发中使用Grid++报表

为了方便,我们可以利用案例的Access数据库,也就是Northwind.mdb来测试我们的报表,弄好这些我们指定对应的数据表数据即可。

C#在Winform开发中使用Grid++报表

这里面配置好数据库表信息后,我们就可以用它生成相关的字段和对应的列信息了

C#在Winform开发中使用Grid++报表

修改列的表头,让它符合中文的表头列,如下所示。

C#在Winform开发中使用Grid++报表

我们在页脚出,加入了打印时间,页码的一些系统变量,具体操作就是添加一个综合文本,然后在内容里面插入指定的域内容即可,如下所示

C#在Winform开发中使用Grid++报表

预览报表,我们就可以看到具体的报表格式显示了。

C#在Winform开发中使用Grid++报表

通过上面的操作,感觉生成一个报表还是很方便的,接着我有根据需要做了一个二维码的报表显示,方便打印资产标签。

C#在Winform开发中使用Grid++报表

绑定数据源显示的报表视图如下所示,看起来还是蛮好的。

C#在Winform开发中使用Grid++报表

2、数据绑定

一般我们绑定数据源,有的时候可以直接指定数据库连接,有时候可以绑定具体的数据列表,如DataTable或者List<T>这样的数据源,不同的方式报表控件的代码绑定不同。

直接绑定数据表的路径如下所示。

/// <summary>
  /// 普通连接数据库的例子-打印预览
  /// </summary>
  private void btnNormalDatabase_Click(object sender, EventArgs e)
  {
    Report = new GridppReport();
    string reportPath = Path.Combine(Application.StartupPath, "Reports\\testgrid++.grf");
    string dbPath = Path.Combine(Application.StartupPath, "Data\\NorthWind.mdb");

    //从对应文件中载入报表模板数据
    Report.LoadFromFile(reportPath);
    //设置与数据源的连接串,因为在设计时指定的数据库路径是绝对路径。
    if (Report.DetailGrid != null)
    {
      string connstr = Utility.GetDatabaseConnectionString(dbPath);
      Report.DetailGrid.Recordset.ConnectionString = connstr;
    }

    Report.PrintPreview(true);
  }

而如果需要绑定和数据库无关的动态数据源,那么就需要通过控件的FetchRecord进行处理了,如下代码所示。

Report.FetchRecord += new _IGridppReportEvents_FetchRecordEventHandler(ReportFetchRecord);

通过这样我们增加每一个对应的列单元格信息,如下是随带案例所示

//在C#中一次填入一条记录不能成功,只能使用一次将记录全部填充完的方式
  private void ReportFetchRecord()
  {
    //将全部记录一次填入
    Report.DetailGrid.Recordset.Append();
    FillRecord1();
    Report.DetailGrid.Recordset.Post();

    Report.DetailGrid.Recordset.Append();
    FillRecord2();
    Report.DetailGrid.Recordset.Post();

    Report.DetailGrid.Recordset.Append();
    FillRecord3();
    Report.DetailGrid.Recordset.Post();
  }

  private void FillRecord1()
  {
    C1Field.AsString = "A";
    I1Field.AsInteger = 1;
    F1Field.AsFloat = 1.01;
  }

  private void FillRecord2()
  {
    C1Field.AsString = "B";
    I1Field.AsInteger = 2;
    F1Field.AsFloat = 1.02;
  }

  private void FillRecord3()
  {
    C1Field.AsString = "C";
    I1Field.AsInteger = 3;
    F1Field.AsFloat = 1.03;
  }

这样处理肯定很麻烦,我们常规做法是弄一个辅助类,来处理DataTable和List<T>等这样类型数据的动态增加操作。

/// <summary>
  /// 绑定实体类集合的例子-打印预览
  /// </summary>
  private void btnBindList_Click(object sender, EventArgs e)
  {
    Report = new GridppReport();
    //从对应文件中载入报表模板数据
    string reportPath = Path.Combine(Application.StartupPath, "Reports\\testList.grf");
    Report.LoadFromFile(reportPath);
    Report.FetchRecord += ReportList_FetchRecord;

    Report.PrintPreview(true);
  }
  /// <summary>
  /// 绑定DataTable的例子-打印预览
  /// </summary>
  private void btnBindDatatable_Click(object sender, EventArgs e)
  {
    Report = new GridppReport();
    //从对应文件中载入报表模板数据
    string reportPath = Path.Combine(Application.StartupPath, "Reports\\testList.grf");
    Report.LoadFromFile(reportPath);
    Report.FetchRecord += ReportList_FetchRecord2;

    Report.PrintPreview(true);
  }

  private void ReportList_FetchRecord()
  {
    List<ProductInfo> list = BLLFactory<Product>.Instance.GetAll();
    GridReportHelper.FillRecordToReport<ProductInfo>(Report, list);
  }
  private void ReportList_FetchRecord2()
  {
    var dataTable = BLLFactory<Product>.Instance.GetAllToDataTable();
    GridReportHelper.FillRecordToReport(Report, dataTable);
  }

其中辅助类GridReportHelper 代码如下所示。

/// <summary>
/// Gird++报表的辅助类
/// </summary>
public class GridReportHelper
{
  private struct MatchFieldPairType
  {
    public IGRField grField;
    public int MatchColumnIndex;
  }

  /// <summary>
  /// 将 DataReader 的数据转储到 Grid++Report 的数据集中
  /// </summary>
  /// <param name="Report">报表对象</param>
  /// <param name="dr">DataReader对象</param>
  public static void FillRecordToReport(IGridppReport Report, IDataReader dr)
  {
    MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dr.FieldCount)];

    //根据字段名称与列名称进行匹配,建立DataReader字段与Grid++Report记录集的字段之间的对应关系
    int MatchFieldCount = 0;
    for (int i = 0; i < dr.FieldCount; ++i)
    {
      foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
      {
        if (string.Compare(fld.RunningDBField, dr.GetName(i), true) == 0)
        {
          MatchFieldPairs[MatchFieldCount].grField = fld;
          MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
          ++MatchFieldCount;
          break;
        }
      }
    }

    // 将 DataReader 中的每一条记录转储到Grid++Report 的数据集中去
    while (dr.Read())
    {
      Report.DetailGrid.Recordset.Append();
      for (int i = 0; i < MatchFieldCount; ++i)
      {
        var columnIndex = MatchFieldPairs[i].MatchColumnIndex;
        if (!dr.IsDBNull(columnIndex))
        {
          MatchFieldPairs[i].grField.Value = dr.GetValue(columnIndex);
        }
      }
      Report.DetailGrid.Recordset.Post();
    }
  }

  /// <summary>
  /// 将 DataTable 的数据转储到 Grid++Report 的数据集中
  /// </summary>
  /// <param name="Report">报表对象</param>
  /// <param name="dt">DataTable对象</param>
  public static void FillRecordToReport(IGridppReport Report, DataTable dt)
  {
    MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dt.Columns.Count)];

    //根据字段名称与列名称进行匹配,建立DataReader字段与Grid++Report记录集的字段之间的对应关系
    int MatchFieldCount = 0;
    for (int i = 0; i < dt.Columns.Count; ++i)
    {
      foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
      {
        if (string.Compare(fld.Name, dt.Columns[i].ColumnName, true) == 0)
        {
          MatchFieldPairs[MatchFieldCount].grField = fld;
          MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
          ++MatchFieldCount;
          break;
        }
      }
    }

    // 将 DataTable 中的每一条记录转储到 Grid++Report 的数据集中去
    foreach (DataRow dr in dt.Rows)
    {
      Report.DetailGrid.Recordset.Append();
      for (int i = 0; i < MatchFieldCount; ++i)
      {
        var columnIndex = MatchFieldPairs[i].MatchColumnIndex;
        if (!dr.IsNull(columnIndex))
        {
          MatchFieldPairs[i].grField.Value = dr[columnIndex];
        }
      }
      Report.DetailGrid.Recordset.Post();
    }
  }

  /// <summary>
  /// List加载数据集
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="Report">报表对象</param>
  /// <param name="list">列表数据</param>
  public static void FillRecordToReport<T>(IGridppReport Report, List<T> list)
  {
    Type type = typeof(T); //反射类型       

    MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, type.GetProperties().Length)];

    //根据字段名称与列名称进行匹配,建立字段与Grid++Report记录集的字段之间的对应关系
    int MatchFieldCount = 0;
    int i = 0;
    MemberInfo[] members = type.GetMembers();
    foreach (MemberInfo memberInfo in members)
    {
      foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
      {
        if (string.Compare(fld.Name, memberInfo.Name, true) == 0)
        {
          MatchFieldPairs[MatchFieldCount].grField = fld;
          MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
          ++MatchFieldCount;
          break;
        }
      }
      ++i;
    }
    
    // 将 DataTable 中的每一条记录转储到 Grid++Report 的数据集中去
    foreach (T t in list)
    {
      Report.DetailGrid.Recordset.Append();
      for (i = 0; i < MatchFieldCount; ++i)
      {
        object objValue = GetPropertyValue(t, MatchFieldPairs[i].grField.Name);
        if (objValue != null)
        {
          MatchFieldPairs[i].grField.Value = objValue;
        }
      }
      Report.DetailGrid.Recordset.Post();
    }
  }

  /// <summary>
  /// 获取对象实例的属性值
  /// </summary>
  /// <param name="obj">对象实例</param>
  /// <param name="name">属性名称</param>
  /// <returns></returns>
  public static object GetPropertyValue(object obj, string name)
  {
    //这个无法获取基类
    //PropertyInfo fieldInfo = obj.GetType().GetProperty(name, bf);
    //return fieldInfo.GetValue(obj, null);

    //下面方法可以获取基类属性
    object result = null;
    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
    {
      if (prop.Name == name)
      {
        result = prop.GetValue(obj);
      }
    }
    return result;
  }
}

绑定数据的报表效果如下所示

C#在Winform开发中使用Grid++报表

导出报表为PDF也是比较常规的操作,这个报表控件也可以实现PDF等格式文件的导出,如下所示。

private void btnExportPdf_Click(object sender, EventArgs e)
  {
    List<ProductInfo> list = BLLFactory<Product>.Instance.GetAll();

    //从对应文件中载入报表模板数据
    string reportPath = Path.Combine(Application.StartupPath, "Reports\\testList.grf");
    GridExportHelper helper = new GridExportHelper(reportPath);

    string fileName = "d:\\my.pdf";
    var succeeded = helper.ExportPdf(list, fileName);
    if(succeeded)
    {
      Process.Start(fileName);
    }
  }

C#在Winform开发中使用Grid++报表

以上就是利用这个报表控件做的一些功能测试和辅助类封装,方便使用。希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/wuhuacong/p/10523734.html

延伸 · 阅读

精彩推荐
  • C#轻松学习C#的运算符

    轻松学习C#的运算符

    轻松学习C#的运算符,对C#的运算符感兴趣的朋友可以参考本篇文章,帮助大家更灵活的运用C#的运算符。...

    丿木呈广予口贝5982021-11-03
  • C#利用Aspose.Cells和Excel模板导出统计数据

    利用Aspose.Cells和Excel模板导出统计数据

    这篇文章主要为大家详细介绍了利用Aspose.Cells和Excel模板导出复杂的统计数据,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    蝶恋花雨8262022-03-06
  • C#C#多线程传递参数及任务用法示例

    C#多线程传递参数及任务用法示例

    这篇文章主要介绍了C#多线程传递参数及任务用法,结合简单实例形式分析了C#多线程的使用及相关的参数传递与任务创建等使用技巧,需要的朋友可以参考下...

    smartsmile201210662021-11-25
  • C#C#实现txt定位指定行完整实例

    C#实现txt定位指定行完整实例

    这篇文章主要介绍了C#实现txt定位指定行的方法,涉及C#针对文本文件进行光标定位的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    我心依旧11432021-10-20
  • C#C#两个相同属性的类赋值方法

    C#两个相同属性的类赋值方法

    这篇文章主要介绍了C#两个相同属性的类赋值方法的相关资料,需要的朋友可以参考下...

    Gester.Lin4002021-12-06
  • C#C#实现文件上传以及多文件上传功能

    C#实现文件上传以及多文件上传功能

    这篇文章主要为大家详细介绍了C#实现文件上传以及多文件上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一...

    陈逸子风7052022-01-05
  • C#silverlight实现图片局部放大效果的方法

    silverlight实现图片局部放大效果的方法

    这篇文章主要介绍了silverlight实现图片局部放大效果的方法,结合实例形式分析了silverlight针对图片属性的相关操作技巧,需要的朋友可以参考下...

    菩提树下的杨过4082021-12-29
  • C#利用C#代码实现图片旋转360度

    利用C#代码实现图片旋转360度

    本文介绍利用C#代码实现图片旋转360度,具体实例代码已附上,仅供大家参考,希望对大家有所帮助...

    逆心8382021-12-10