具有重复行标题和换行的 RDLC
RDLC with repeated row headings and row wrap
我正在 Visual Studio 的报表生成器中构建一个 RDLC 子报表。它需要水平显示数据,重复 headers 行,并在用完 space 时换行(每行 10 项)。可以有 n
个项目(Id)。另请注意,Length
必须显示在项目之间。另请注意,每一行的行标题都重复。这是一个示例:
所以对于一个子报表,它可能是 30 "items"(如上图所示),而另一个可以有 52、20、14 等
数据存储在SQL服务器上是这样的:
Count
: 30
例如
Weight
:120000,19000,20000,20000,19000,...
- CSV
Length
:196,54,54,174,60,...
- 英寸的 CSV
(我没有设计 table;会使用 one-to-many 而不是将数据作为 CSV 存储在列中。)
我找到了这个示例:Show data Horizontally in rdlc report,但它没有显示行 headers、重复它们或包装项目。
如何创建显示上述示例中数据的 RDLC?谢谢。
以下是众多解决方案中的一个;这只是一种方法。但它最终修复了报告。包裹物品变成了no-go;据我所知,这是不可能的。所以我决定在子报表中每行最多 10 个项目。
我首先处理数据,如上所示,这些数据是来自数据库的 CSV 值。不理想,但可行。
// Split the CSV data into lists.
var weightList = dataModel.Weight.Split(',')
// Add thousands separator to weight
.Select(x => int.Parse(x).ToString("##,###"))
.ToList();
var lengthList = dataModel.Length.Split(',').ToList();
reportData.RowModelList = new List<RowModel>();
// Loop for 10 at a time
for (var i = 0; i < weightList.Count; i=i+10)
{
var weightListTen = new List<string>();
// Get an array of 10 weight items
var weightArrayItems = weightList.Skip(i).Take(10).ToArray();
// Important: we need to add 10 elements per row,
// even if the item is blank string. This makes life
// easier in RDLC as we won't have to tangle with
// out-of-bound array errors. The below issue can
// be encountered on the last row.
for (var k = 0; k < 10; k++)
{
weightListTen.Add(weightArrayItems.Length - 1 < k ? "" : weightArrayItems[k]);
}
var lengthListTen = new List<string>();
// Get an array of 9 length items
var lengthArrayItems = lengthList.Skip(i).Take(9).ToArray();
// Same as weight: loop and add fully 10 items
// per row (i variable), so to avoid array out-of-bound
// errors in VBA.
for (var l = 0; l < 10; l++)
{
lengthListTen.Add(lengthArrayItems.Length - 1 < l ? "" : FeetAndInches(int.Parse(lengthArrayItems[l])));
}
// Similar issue as above being addressed here, but
// with a slightly different approach. We need the
// Id property array for this row and we want to
// ensure we have 10 records, even if the item
// only has a blank string.
var idList = new List<string>();
var diff = (i + 10) - weightList.Count;
for (var j = i+1; j <= weightList.Count + diff ; j++)
{
idList.Add(j <= weightList.Count ? j.ToString() : "");
}
// Instantiate a new row.
var rowModel = new RowModel
{
Weight = weightListTen.ToArray(),
Length = lengthListTen.ToArray(),
Id = idList.Select(x => x.ToString()).ToArray()
};
reportData.RowModelList.Add(rowModel);
}
// Helper for getting feet/inches
private static string FeetAndInches(int inches)
{
return inches / 12 + "' " + inches%12 + "\"";
}
这是处理 RDLC 渲染的 Renderer
class:
public class Renderer
{
private readonly int _id;
private ReportDataSource _dataSourceMain;
private ReportDataSource _dataSourceRows;
public Renderer(int id)
{
_id = id;
}
public async Task<byte[]> RenderPdfAsync()
{
var report = await DataService.GetReportDataAsync(_id);
Warning[] warnings;
string[] streamIds;
var mimeType = string.Empty;
var encoding = string.Empty;
var extension = string.Empty;
using (var report = new LocalReport())
{
report.ShowDetailedSubreportMessages = true;
report.EnableExternalImages = true;
report.ReportEmbeddedResource = "Renderer.Templates.Pdf.rdlc";
var dsMain = new List<DataModel> { report };
_dataSourceMain = new ReportDataSource("dsMain", dsMain);
_dataSourceRows = new ReportDataSource("dsRows", permit.RowModelList);
report.DataSources.Add(_dataSourceMain);
report.DataSources.Add(_dataSourceRows);
report.SubreportProcessing += SetSubDataSource;
report.Refresh();
var result = report.Render("PDF", null, out mimeType, out encoding, out extension, out streamIds, out warnings);
if (warnings.Any())
{
Logger.Log(LogLevel.Error, null, "Report Processing Messages: " + string.Join(", *", warnings.Select(x => new
{x.Message, x.Code, x.ObjectName, x.ObjectType, x.Severity})));
}
return result;
}
}
private void SetSubDataSource(object sender, SubreportProcessingEventArgs e)
{
e.DataSources.Clear();
e.DataSources.Add(_dataSourceMain);
e.DataSources.Add(_dataSourceRows);
}
}
子报表 RDLC 使用绑定到 dsRows
的 Tablix,然后跨 ID
、Weight
和 Length
行引用数组元素。 Tablix 已删除其 header 行,左侧有一列,其中输入文本框控件的那 3 行 header 的静态值。
然后header信息栏右边有10栏;这些显示该行的数组元素。在每个单元格中,表达式获取相应的数组值:第一个 Weight
列中的 =Fields!Weight.Value(0)
,最后一个列中的 =Fields!Weight.Value(9)
。
有很多更好的方法可以更早地assemblefor
循环中的数据(例如,将多个循环合并为一个);但它正在运行,我们将在时间允许的情况下访问它以重构并提高效率。
希望这对其他人有帮助。
我正在 Visual Studio 的报表生成器中构建一个 RDLC 子报表。它需要水平显示数据,重复 headers 行,并在用完 space 时换行(每行 10 项)。可以有 n
个项目(Id)。另请注意,Length
必须显示在项目之间。另请注意,每一行的行标题都重复。这是一个示例:
所以对于一个子报表,它可能是 30 "items"(如上图所示),而另一个可以有 52、20、14 等
数据存储在SQL服务器上是这样的:
Count
:30
例如Weight
:120000,19000,20000,20000,19000,...
- CSVLength
:196,54,54,174,60,...
- 英寸的 CSV
(我没有设计 table;会使用 one-to-many 而不是将数据作为 CSV 存储在列中。)
我找到了这个示例:Show data Horizontally in rdlc report,但它没有显示行 headers、重复它们或包装项目。
如何创建显示上述示例中数据的 RDLC?谢谢。
以下是众多解决方案中的一个;这只是一种方法。但它最终修复了报告。包裹物品变成了no-go;据我所知,这是不可能的。所以我决定在子报表中每行最多 10 个项目。
我首先处理数据,如上所示,这些数据是来自数据库的 CSV 值。不理想,但可行。
// Split the CSV data into lists.
var weightList = dataModel.Weight.Split(',')
// Add thousands separator to weight
.Select(x => int.Parse(x).ToString("##,###"))
.ToList();
var lengthList = dataModel.Length.Split(',').ToList();
reportData.RowModelList = new List<RowModel>();
// Loop for 10 at a time
for (var i = 0; i < weightList.Count; i=i+10)
{
var weightListTen = new List<string>();
// Get an array of 10 weight items
var weightArrayItems = weightList.Skip(i).Take(10).ToArray();
// Important: we need to add 10 elements per row,
// even if the item is blank string. This makes life
// easier in RDLC as we won't have to tangle with
// out-of-bound array errors. The below issue can
// be encountered on the last row.
for (var k = 0; k < 10; k++)
{
weightListTen.Add(weightArrayItems.Length - 1 < k ? "" : weightArrayItems[k]);
}
var lengthListTen = new List<string>();
// Get an array of 9 length items
var lengthArrayItems = lengthList.Skip(i).Take(9).ToArray();
// Same as weight: loop and add fully 10 items
// per row (i variable), so to avoid array out-of-bound
// errors in VBA.
for (var l = 0; l < 10; l++)
{
lengthListTen.Add(lengthArrayItems.Length - 1 < l ? "" : FeetAndInches(int.Parse(lengthArrayItems[l])));
}
// Similar issue as above being addressed here, but
// with a slightly different approach. We need the
// Id property array for this row and we want to
// ensure we have 10 records, even if the item
// only has a blank string.
var idList = new List<string>();
var diff = (i + 10) - weightList.Count;
for (var j = i+1; j <= weightList.Count + diff ; j++)
{
idList.Add(j <= weightList.Count ? j.ToString() : "");
}
// Instantiate a new row.
var rowModel = new RowModel
{
Weight = weightListTen.ToArray(),
Length = lengthListTen.ToArray(),
Id = idList.Select(x => x.ToString()).ToArray()
};
reportData.RowModelList.Add(rowModel);
}
// Helper for getting feet/inches
private static string FeetAndInches(int inches)
{
return inches / 12 + "' " + inches%12 + "\"";
}
这是处理 RDLC 渲染的 Renderer
class:
public class Renderer
{
private readonly int _id;
private ReportDataSource _dataSourceMain;
private ReportDataSource _dataSourceRows;
public Renderer(int id)
{
_id = id;
}
public async Task<byte[]> RenderPdfAsync()
{
var report = await DataService.GetReportDataAsync(_id);
Warning[] warnings;
string[] streamIds;
var mimeType = string.Empty;
var encoding = string.Empty;
var extension = string.Empty;
using (var report = new LocalReport())
{
report.ShowDetailedSubreportMessages = true;
report.EnableExternalImages = true;
report.ReportEmbeddedResource = "Renderer.Templates.Pdf.rdlc";
var dsMain = new List<DataModel> { report };
_dataSourceMain = new ReportDataSource("dsMain", dsMain);
_dataSourceRows = new ReportDataSource("dsRows", permit.RowModelList);
report.DataSources.Add(_dataSourceMain);
report.DataSources.Add(_dataSourceRows);
report.SubreportProcessing += SetSubDataSource;
report.Refresh();
var result = report.Render("PDF", null, out mimeType, out encoding, out extension, out streamIds, out warnings);
if (warnings.Any())
{
Logger.Log(LogLevel.Error, null, "Report Processing Messages: " + string.Join(", *", warnings.Select(x => new
{x.Message, x.Code, x.ObjectName, x.ObjectType, x.Severity})));
}
return result;
}
}
private void SetSubDataSource(object sender, SubreportProcessingEventArgs e)
{
e.DataSources.Clear();
e.DataSources.Add(_dataSourceMain);
e.DataSources.Add(_dataSourceRows);
}
}
子报表 RDLC 使用绑定到 dsRows
的 Tablix,然后跨 ID
、Weight
和 Length
行引用数组元素。 Tablix 已删除其 header 行,左侧有一列,其中输入文本框控件的那 3 行 header 的静态值。
然后header信息栏右边有10栏;这些显示该行的数组元素。在每个单元格中,表达式获取相应的数组值:第一个 Weight
列中的 =Fields!Weight.Value(0)
,最后一个列中的 =Fields!Weight.Value(9)
。
有很多更好的方法可以更早地assemblefor
循环中的数据(例如,将多个循环合并为一个);但它正在运行,我们将在时间允许的情况下访问它以重构并提高效率。
希望这对其他人有帮助。