alexvw
Всем привет,
Я смог придумать рабочее решение; однако, если у кого-то есть лучшее, остальные из нас, безусловно, будут признательны, чтобы узнать об этом.
Случай:
Заполните rdlc из xml-файла, содержащего 1-n дочерних объектов, имеющих как статические, так и динамические данные.
Примерная Структура
<?xml version="1.0" encoding="ISO-8859-1"?>
<SetDTE>
<DTE version="1.0" > <!-- Children {1-n} (node of interest) -->
<Documento ID="MiPE76266617-720">
<Encabezado> <!-- static data = single group -->
...
</Encabezado>
<Detalle> <!-- dynamic data = 0-n groups -->
...
</Detalle>
<Detalle>
...
</Detalle>
</DTE>
<DTE version="1.0" >
<Documento ID="MiPE76266617-2495">
<Encabezado> <!-- static data = single group -->
...
</Encabezado>
<Detalle> <!-- dynamic data = 0-n groups -->
...
</Detalle>
</DTE>
</SetDTE>
Сначала я попытался заполнить его с помощью стандартного отчета множеством таблиц данных, сгенерированных набором данных, загруженным из исходного xml-файла:
string xmlSource = System.IO.File.ReadAllText(DTEPath);
DataSet dsXML = new DTE(xmlSource);
Где
ТЕРМИНАЛЬНОЕ ОБОРУДОВАНИЕ это настраиваемый класс, наследующий от DataSet, который использует свой метод ReadXml для заполнения объекта. Затем я извлекаю необходимые таблицы из источника и добавляю их в базу:
base.Tables.Add(dsXML.Tables["Documento"] == null ? new Documento() : dsXML.Tables["Documento"].Copy());
Где
Мы это настраиваемый класс, который наследуется от datatable, цель которого состоит в том, чтобы обеспечить согласованную структуру, если источник не имеет ожидаемого узла. Такой подход допустим, но только для xml-файлов с одним узлом "интереса".
Когда вы сталкиваетесь с xml-файлами с несколькими узлами "интереса", стандартный отчет не сокращает его. Я попытался применить элемент управления списком или вложенные матрицы, но они не только требуют одного источника данных, но и детализируют строки, допускающие только статические данные.
Временное решение я нашел, было:
один) Объедините все статические таблицы данных в одну с помощью установки соответствующих первичных ключей (метод, который я проигнорировал и смог реализовать благодаря
эта должность).
б) Создание и применение вложенных отчетов для обработки динамических областей.
Процедура:
1) Создайте базовый отчет, включающий таблицу(табликс), которая должна быть настроена так, чтобы иметь столько строк группы, сколько необходимо. В этом случае основная группа и дочерняя группа; я расширил одну строку/столбец, оставленные в табликсе, чтобы охватить всю область тела отчета.
2) В эту единственную ячейку добавлены все необходимые текстовые поля, прямоугольники, линии и т. д. для выделения статических данных, то есть данных, которые имеют уникальные значения для каждой строки группы. (Прямоугольники, которые я добавил, являются заполнителями для необходимых вложенных отчетов)
3) Построил вложенные отчеты (мне нужно было два) и обязательно добавил к ним необходимый входной параметр и фильтр. В этом случае каждый вложенный отчет имеет источник данных и соответствующую таблицу для размещения его значений.
4) Добавил вложенные отчеты к основному; каждый внутри своего назначенного прямоугольника.
5) код:
один) Форма размещения (winform); должна связывать обработчик событий, необходимый для обработки вложенного отчета(ов):
private void FrmMain_Load(object sender, EventArgs e)
{
.... //unrelated code
RepVwer.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(SetSubDataSource);
}
б) Основная пустота: которая получает данные, настраивает элемент управления ReportViewer и запускает визуализацию отчета:
private void LoadXmlDTE(string DTEPath)
{
try
{
DataSet dsXML = new DTE(System.IO.File.ReadAllText(DTEPath));
RepVwer.ProcessingMode = ProcessingMode.Local;
RepVwer.LocalReport.ReportEmbeddedResource = "DTEViewer.rdlc.EncabezadoDTE.rdlc";
RepVwer.LocalReport.DataSources.Clear();
//Datos estáticos por documento
DataTable auxData = GenerateStaticGlobalData(dsXML);
RepVwer.LocalReport.DataSources.Add(new ReportDataSource("Global", auxData));
//Datos dinámicos por documento {Sub-Reportes}
_detalle = dsXML.Tables[6];
_referencia = dsXML.Tables[7];
this.RepVwer.RefreshReport();
//... irrelevant code
}
catch (Exception ex)
{
MessageBox.Show(this, "...", "...", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
с) Метод GenerateStaticGlobalData-это метод, отвечающий за объединение всех статических таблиц данных в одну, которая будет основным источником данных отчета:
private DataTable GenerateStaticGlobalData(DataSet dsXML)
{
DataTable auxData = dsXML.Tables[0].Copy();
auxData.PrimaryKey = new DataColumn[] { auxData.Columns["Documento_Id"] }; //Documento_Id {0}
dsXML.Tables[1].PrimaryKey = new DataColumn[] { dsXML.Tables[1].Columns["Documento_Id"] };
auxData.Merge(dsXML.Tables[1]);
auxData.PrimaryKey = new DataColumn[] { auxData.Columns["Encabezado_Id"] }; //Encabezado_Id {4}
for (int i = 2; i < 6; i++)
{
dsXML.Tables[i].PrimaryKey = new DataColumn[] { dsXML.Tables[i].Columns["Encabezado_Id"] };
auxData.Merge(dsXML.Tables[i]);
}
return auxData; //output
}
Примечание Я был в состоянии использовать
для оператор в приведенном выше коде, потому что мой класс DTE организовал эти таблицы данных в таком порядке.
д) Давайте не будем забывать о том, что обработчик событий назначает источник(ы) данных для вложенного отчета(ов):
public void SetSubDataSource(object sender, SubreportProcessingEventArgs e)
{
e.DataSources.Add(new ReportDataSource("Detalle", _detalle));
e.DataSources.Add(new ReportDataSource("Referencias", _referencia));
}
Вот и все; теперь у меня есть отчет (с двумя интегрированными вложенными отчетами), который может быть представлен на экране, как и ожидалось клиентом; то есть документ на страницу, который они могут либо экспортировать, либо распечатать по желанию.
Надеюсь, это может быть полезно для кого-то еще.
Еще раз спасибо всем, кто нашел время прочитать мой вопрос, а теперь и мой собственный ответ.