Nano Hash - криптовалюты, майнинг, программирование

Создание отчета RDLC динамически во время выполнения из DataGridView

У меня есть форма AdvancedSearchForm с элементом управления DataGridView dgrData и кнопкой Report в C # Winform. При нажатии кнопки Report я хочу, чтобы форма с элементом управления ReportView отображалась с теми же столбцами, что и в DataGridView, с теми же заголовками столбцов.

Форма с DataGridView и кнопкой

введите описание изображения здесь

Ожидаемый результат при нажатии кнопки «Отчет»:

введите описание изображения здесь

Мой элемент управления DatagridView (dgrData) связан с

  1. SQL
“Select Id, c_Name from Country”
  1. ConnectionString
server=localhost;User Id=root;password=root;Persist Security Info=True;database=country_state

Чтобы загрузить данные в сетку во время выполнения, я готовлю следующий DataAdapter:

DataAdapter dataAdapter = DataAdapter.Current;
// I am passing the SQL statement and the table name to my database which knows the ConnectionString within the LoadData function

DataTable dt0 = dataAdapter.LoadData("select Id, c_Name from `country`", "country");
if (dt0 != null) {
   dgrData.DataSource = dt0;
}

Можно ли вызвать дочернюю форму, содержащую элемент управления reportviewer по умолчанию, который показывает отчет с таблицей, содержащей столбцы, соответствующие datagridview (dgrData) вместе с данными динамически во время выполнения?

Подробные сведения об ожидаемых результатах:

  1. При нажатии кнопки средство просмотра отчетов в целевой форме должно получить
    , связанный с источником данных из значений в DataGridView. Таким образом, элемент управления ReportViewer ничего не знает о данных в отчете, пока пользователь не нажмет кнопку «Отчет» во время выполнения.
  2. Я хочу, чтобы решение не требовало создания отдельного файла RDLC, потому что оно вызывает внешнюю зависимость, чтобы остановить текущий поток и создать файл отчета в конструкторе файлов отчетов, который может быть чрезмерным для пользователей.
  3. Я ничего не знаю о конструкторе RDLC и связанном с ним источнике данных (я готов изучить (^ _ ^), но я не могу заставить мою команду выполнять это требование к обучению) и привязать данные к отчету. Буду признателен за рабочие примеры кодирования, если ваша помощь содержит теорию.
  4. Я знаю, что ReportViewer существует уже довольно давно. Желаю, чтобы пример решения для сопоставления данных 1-1 между сеткой данных и ReportViewer было легче найти для кого-то в будущем на SO.

Примечание. Пожалуйста, дайте мне знать, если с моей стороны потребуются какие-либо дополнительные данные, в комментариях. Чтобы показать текущее решение, мне пришлось создать файл RDLC, в который я должен был поместить строку подключения и SQL во время разработки, чего я хочу избежать в решении, которое я ищу. Я хочу найти решение, в котором файл RDLC создается с помощью некоторого модульного кода, который можно использовать и в других решениях, вместо того, чтобы разрабатывать его для каждой формы, в которой у меня есть DataGrids.


  • Передать DataTable в ReportViewer 01.11.2016
  • позвольте мне попробовать решение на C # и вернуться к этой цепочке. 01.11.2016
  • Я хочу, чтобы решение не требовало создания отдельного RDLC. Решение, которое я опубликовал, основано на существующем отчете. Он не создает столбцы во время выполнения. Если вам нужно создать отчет во время выполнения, вы можете использовать эту идею или этот. 01.11.2016
  • Спасибо @rezaAghaei. Я хочу знать, можете ли вы помочь мне с созданием файла rdlc во время выполнения вместо HTML, как вы показали в другой цепочке. Я видел решения, которые вы предоставили выше, но почему-то мне кажется, что они сложны, и я чувствую, что вещи не должны быть такими сложными. 01.11.2016
  • Если есть способ вообще избежать файлов RDLC или HTML, это было бы даже лучше :) 01.11.2016
  • В качестве другого варианта вы можете распечатать элемент управления DataGridView, используя его метод DrawToBitmap. 01.11.2016
  • Создать динамический отчет rdlc во время выполнения будет непросто. 01.11.2016
  • Также ознакомьтесь с этим сообщением и используйте пример C # из MSDN. Если вам нужно справа налево, примените исправления, которые я опубликовал в ответ на код C #, в противном случае пример C # для слева направо в порядке. 01.11.2016
  • @rezaAghaei, я хотел знать, можете ли вы показать это решение на C #, я считаю, что VB немного сложно читать и переводить. Я еще официально не писал код на этом языке. 01.11.2016
  • Если вы имеете в виду последнюю ссылку, вы можете загрузить версию C # здесь 01.11.2016
  • Я попробовал пример, он показывает предварительный просмотр после расчета сетки. Есть ли способ использовать эту логику для создания файла RDL во время выполнения. Я буду очень признателен, если это можно будет сделать ... 01.11.2016
  • Вы можете использовать идею, которую я использовал для создания html. Это действительно элегантное решение. Воспользуйтесь идеей для создания отчета RDLC. 01.11.2016
  • Я опубликовал ответ, основанный на той же идее использования шаблона t4. Использовать это действительно просто, и он поддерживает динамическое добавление столбцов во время выполнения. 01.11.2016

Ответы:


1

В качестве опции для динамического создания RDLC отчета во время выполнения вы можете использовать Текстовые шаблоны времени выполнения.

В приведенном ниже примере я создал простой отчет в виде сетки, который можно использовать для динамического создания отчета во время выполнения. Вы можете динамически добавлять столбцы в отчет и устанавливать заголовок, ширину, цвет задней части заголовка для столбца.

В этом примере я заполнил шаблон, используя DataGridView. Но вы можете использовать эту технику в зависимости от любого типа управления или даже использовать ее в веб-формах.

Пример использования - создание и отображение динамического отчета

Для создания и отображения динамического отчета достаточно добавить несколько столбцов в ReportForm, а затем задать данные и отобразить форму.

var f = new ReportForm();
f.ReportColumns = this.dataGridView1.Columns.Cast<DataGridViewColumn>()
                      .Select(x => new ReportColumn(x.DataPropertyName)
                      { Title = x.HeaderText, Width = x.Width }).ToList();
f.ReportData = this.dataGridView1.DataSource;
f.ShowDialog();

введите описание изображения здесь

Путь к решению

Достаточно один раз добавить ReportColumn, DynamicReport.tt и ReportForm в ваше приложение или даже в многоразовую библиотеку, а затем просто использовать, как в примере выше. Выполните следующие шаги, чтобы создать шаблон динамического отчета.

Модель столбца отчета

Создайте модель столбца отчета, содержащую свойства заголовка, выражения, цвета и т. Д. Мы будем использовать это для добавления столбцов в отчет.

using System;
using System.Drawing;
public class ReportColumn
{
    public ReportColumn(string name)
    {
        Name = name;
        Title = name;
        Type = typeof(System.String);
        Width = GetPixelFromInch(1);
        Expression = string.Format("=Fields!{0}.Value", name);
        HeaderBackColor = Color.LightGray;
    }
    public string Name { get; set; }
    public string Title { get; set; }
    public Type Type { get; set; }
    public int Width { get; set; }
    public float WidthInInch
    {
        get { return GetInchFromPixel(Width); }
    }
    public string Expression { get; set; }
    public Color HeaderBackColor { get; set; }
    public string HeaderBackColorInHtml
    {
        get { return ColorTranslator.ToHtml(HeaderBackColor); }
    }
    private int GetPixelFromInch(float inch)
    {
        using (var g = Graphics.FromHwnd(IntPtr.Zero))
            return (int)(g.DpiY * inch);
    }
    private float GetInchFromPixel(int pixel)
    {
        using (var g = Graphics.FromHwnd(IntPtr.Zero))
            return (float)pixel / g.DpiY;
    }
}

Шаблон отчета

Добавьте в проект шаблон времени выполнения (также известный как предварительно обработанный шаблон), назовите его DynamicReport.tt и скопируйте это содержимое в файл:

<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ parameter name="Model" type="System.Collections.Generic.List<ReportColumn>"#>
<?xml version="1.0" encoding="utf-8"?>
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
  <DataSources>
    <DataSource Name="DataSource1">
      <ConnectionProperties>
        <DataProvider>System.Data.DataSet</DataProvider>
        <ConnectString>/* Local Connection */</ConnectString>
      </ConnectionProperties>
      <rd:DataSourceID>e9784bb0-a630-49cc-b7f9-8495aca23a6c</rd:DataSourceID>
    </DataSource>
  </DataSources>
  <DataSets>
    <DataSet Name="DataSet1">
      <Fields>
<#    foreach(ReportColumn column in Model){#>
        <Field Name="<#=column.Name#>">
          <DataField><#=column.Name#></DataField>
          <rd:TypeName><#=column.Type.Name#></rd:TypeName>
        </Field>
<#    }#>
      </Fields>
      <Query>
        <DataSourceName>DataSource1</DataSourceName>
        <CommandText>/* Local Query */</CommandText>
      </Query>
      <rd:DataSetInfo>
        <rd:DataSetName />
        <rd:TableName />
        <rd:ObjectDataSourceType />
      </rd:DataSetInfo>
    </DataSet>
  </DataSets>
  <Body>
    <ReportItems>
      <Tablix Name="Tablix1">
        <TablixBody>
          <TablixColumns>
<#    foreach(ReportColumn column in Model){#>
            <TablixColumn>
              <Width><#=column.WidthInInch#>in</Width>
            </TablixColumn>
<#    }#>
          </TablixColumns>
          <TablixRows>
            <TablixRow>
              <Height>0.25in</Height>
              <TablixCells>
<#    foreach(ReportColumn column in Model){#>
                <TablixCell>
                  <CellContents>
                    <Textbox Name="<#=column.Name#>TextBox">
                      <CanGrow>true</CanGrow>
                      <KeepTogether>true</KeepTogether>
                      <Paragraphs>
                        <Paragraph>
                          <TextRuns>
                            <TextRun>
                              <Value><#=column.Title#></Value>
                              <Style />
                            </TextRun>
                          </TextRuns>
                          <Style />
                        </Paragraph>
                      </Paragraphs>
                      <rd:DefaultName><#=column.Name#>TextBox</rd:DefaultName>
                      <Style>
                        <Border>
                          <Color>LightGrey</Color>
                          <Style>Solid</Style>
                        </Border>
                        <BackgroundColor><#=column.HeaderBackColorInHtml#></BackgroundColor>
                        <PaddingLeft>2pt</PaddingLeft>
                        <PaddingRight>2pt</PaddingRight>
                        <PaddingTop>2pt</PaddingTop>
                        <PaddingBottom>2pt</PaddingBottom>
                      </Style>
                    </Textbox>
                  </CellContents>
                </TablixCell>
<#    }#>
              </TablixCells>
            </TablixRow>
            <TablixRow>
              <Height>0.25in</Height>
              <TablixCells>
<#    foreach(ReportColumn column in Model){#>
                <TablixCell>
                  <CellContents>
                    <Textbox Name="<#=column.Name#>">
                      <CanGrow>true</CanGrow>
                      <KeepTogether>true</KeepTogether>
                      <Paragraphs>
                        <Paragraph>
                          <TextRuns>
                            <TextRun>
                              <Value><#=column.Expression#></Value>
                              <Style />
                            </TextRun>
                          </TextRuns>
                          <Style />
                        </Paragraph>
                      </Paragraphs>
                      <rd:DefaultName><#=column.Name#></rd:DefaultName>
                      <Style>
                        <Border>
                          <Color>LightGrey</Color>
                          <Style>Solid</Style>
                        </Border>
                        <PaddingLeft>2pt</PaddingLeft>
                        <PaddingRight>2pt</PaddingRight>
                        <PaddingTop>2pt</PaddingTop>
                        <PaddingBottom>2pt</PaddingBottom>
                      </Style>
                    </Textbox>
                  </CellContents>
                </TablixCell>
<#    }#>
              </TablixCells>
            </TablixRow>
          </TablixRows>
        </TablixBody>
        <TablixColumnHierarchy>
          <TablixMembers>
<#    foreach(ReportColumn column in Model){#>
            <TablixMember />
<#    }#>
          </TablixMembers>
        </TablixColumnHierarchy>
        <TablixRowHierarchy>
          <TablixMembers>
            <TablixMember>
              <KeepWithGroup>After</KeepWithGroup>
            </TablixMember>
            <TablixMember>
              <Group Name="Details" />
            </TablixMember>
          </TablixMembers>
        </TablixRowHierarchy>
        <DataSetName>DataSet1</DataSetName>
        <Top>0.15625in</Top>
        <Left>0.125in</Left>
        <Height>0.5in</Height>
        <Width>2in</Width>
        <Style>
          <Border>
            <Style>None</Style>
          </Border>
        </Style>
      </Tablix>
    </ReportItems>
    <Height>0.82292in</Height>
    <Style />
  </Body>
  <Width>6.5in</Width>
  <Page>
    <LeftMargin>1in</LeftMargin>
    <RightMargin>1in</RightMargin>
    <TopMargin>1in</TopMargin>
    <BottomMargin>1in</BottomMargin>
    <Style />
  </Page>
  <rd:ReportID>60987c40-62b1-463b-b670-f3fa81914e33</rd:ReportID>
  <rd:ReportUnitType>Inch</rd:ReportUnitType>
</Report>

Форма отчета

Добавьте Form в проект, добавьте ReportViewer элемент управления в форму и поместите этот код в класс:

public partial class ReportForm : Form
{
    public ReportForm()
    {
        InitializeComponent();
        ReportColumns  = new List<ReportColumn>();
        this.Load+=new EventHandler(ReportForm_Load);
    }

    public List<ReportColumn> ReportColumns { get; set; }
    public Object ReportData { get; set; }

    private void ReportForm_Load(object sender, EventArgs e)
    {
        var report = new DynamicReport();
        report.Session = new Dictionary<string, object>();
        report.Session["Model"] = this.ReportColumns;
        report.Initialize();
        var rds = new Microsoft.Reporting.WinForms.ReportDataSource("DataSet1", this.ReportData);
        this.reportViewer1.LocalReport.DataSources.Clear();
        this.reportViewer1.LocalReport.DataSources.Add(rds);
        var reportContent = System.Text.Encoding.UTF8.GetBytes(report.TransformText());
        using (var stream = new System.IO.MemoryStream(reportContent))
        {
            this.reportViewer1.LocalReport.LoadReportDefinition(stream);
        }
        this.reportViewer1.RefreshReport();
    }
}

Примечание

Вы можете просто расширить модель ReportColumn, а также DynamicReport.tt. Я создал шаблон, используя существующий отчет, я просто использовал несколько тегов кода t4, чтобы сделать его динамическим.

Пример

Вы можете клонировать или скачать рабочий пример:

01.11.2016
  • спасибо, похоже, это точно имитирует DataGrid и на данный момент решает проблему. Я хотел знать, есть ли у шаблона препроцессора гибкость, чтобы он отображался в более индивидуальном формате. В частности, в тех случаях, когда нам нужно объединить строки и столбцы в соответствии с нашими требованиями к отчетности. 02.11.2016
  • Можем ли мы установить разную ширину сетки для разных столбцов в этом типе шаблона препроцессора для данных, которые у нас есть в сетке? 02.11.2016
  • Показанный выше файл .tt выглядит как XML, не могли бы вы показать его реализацию в HTML. . . 02.11.2016
  • Мне нужна помощь со следующими строками ‹br/› f.ReportColumns = this.dgrData.Columns.Cast ‹DataGridViewColumn› () .Select (x = ›new ReportColumn (x.DataPropertyName) {Title = x.HeaderText, Width = x .Width}). ToList (); 02.11.2016
  • не могли бы вы преобразовать это в код без лямбда-выражения, пожалуйста 02.11.2016
  • Так работает t4: файл tt работает как шаблон. Он преобразует все строки в Writer.Write("...") методы и смешивает C# код, который мы использовали в tt. Затем в результате создается класс C#, который имеет несколько методов, например TransformText, который создает для нас строковый вывод. Каким-то образом это работает как страницы ASP.NET, в которых вы смешиваете текст и блоки кода C #, или как Razor. Класс C # создается в tt файле в растворе, и его нельзя трогать. Внесите любые изменения в tt файл, тогда класс C # изменится. Чтобы узнать больше о шаблонах T4, см. Связанный документ от Microsoft. 02.11.2016
  • Отчет RDLC на самом деле представляет собой XML-файл, который используется механизмом отчетов для визуализации. Это не имеет ничего общего с HTML. RDLC, который вы видите в файле T4, не является волшебным, я создал простой табличный отчет, а затем использовал его XML в файле T4. Затем вместо жестко закодированных столбцов я создал их, используя те foreach циклы, которые вы видите в файле T4. Чтобы добавить другие элементы, такие как заголовок или нижний колонтитул, или несколько меток для даты, времени и т. Д., Вы должны использовать ту же идею, создать отчет и преобразовать его в такой шаблон T4. 02.11.2016
  • Вы можете добавлять столбцы разной ширины в ReportColumns. Может отличаться от DataGridView столбцов. Но вы должны предоставить данные для этого столбца. Например, вы можете использовать его так: f.ReportColumns.Add(new ReportColumn("A"));f.ReportColumns.Add(new ReportColumn("B")); тогда вы можете передать List, элементы которого содержат свойства A и B. Например, DataTable, который создается следующим образом: var dt = new DataTable(); dt.Columns.Add("A"); dt.Columns.Add("B"); dt.Rows.Add("1");dt.Rows.Add("2");, тогда, если вы установите f.ReportData = dt, он покажет отчет с этими данными. 02.11.2016
  • о, замечательно. Я также разобрался, как работает лямбда-функция. Для моего собственного кода я изменил блок выше на: List ‹ReportColumn› lstRepCmn = new List ‹ReportColumn› (); foreach (DataGridViewColumn c в dgrData.Columns) {if (c.Visible) {ReportColumn r = new ReportColumn (c.DataPropertyName) {Title = c.HeaderText, Width = c.Width}; lstRepCmn.Add (r); }} f.ReportColumns = lstRepCmn; 02.11.2016
  • Использование Linq необязательно, но необходимо, и вам не следует избегать использования linq. Код, который я использовал, эквивалентен простому циклу foreach. var list = new List<ReportColumn>(); foreach(DataGridViewRow x in dataGridView1.Rows){ list.Add(new ReportColumn(x.DataPropertyName) { Title = x.HeaderText, Width = x.Width });} Тогда f.ReportColumns = list;. 02.11.2016
  • Да, отлично. Linq действительно полезен. 02.11.2016
  • Спасибо @RezaAghaei, я свяжусь с вами по этому поводу, если у меня возникнут еще какие-то сомнения. Большое спасибо за терпение в решении этой проблемы и за помощь в управлении reportViewer. 02.11.2016
  • Я вижу из кода, что это в конечном итоге создает синтаксис файла RDL во время выполнения, который может быть загружен в средство просмотра отчетов. Есть ли способ увидеть сгенерированный код синтаксиса RDL? 02.11.2016
  • переменная reportContent - это строка, содержащая формат RDLC. Сохраните его в *.rdlc файл, затем вы можете просто открыть его в Visual Studio. 02.11.2016
  • Создание динамических отчетов во время выполнения - непростая задача, и я считаю, что в реальной среде / проекте мой ответ - это всего лишь отправная точка. Но действительно элегантное и полезное решение. Если вы поняли идею, это будет полезно для вас во многих случаях, когда вам нужно создавать шаблоны, например, шаблон электронной почты, который содержит продукты, купленные клиентом. Идея блестящая, ИМО! 02.11.2016
  • Кроме того, HTML ответ, который я опубликовал здесь, является действительно хорошей отправной точкой для тех, кто хочет создавать выходные данные HTML, но большинство пользователей этого не делает. я не имею никакого представления о шаблонах времени выполнения T4 и не знаю, как это работает, и поскольку ответ почему-то длинный, ответом пренебрегают; но это действительно полезно. 02.11.2016
  • Спасибо за замечание о переменной reportContent. Я также рассмотрю HTML-часть. Спасибо за ваше руководство. 02.11.2016
  • Дайте мне знать, если у вас возникнут вопросы по поводу связанного сообщения или если вы сочтете его полезным :) 02.11.2016
  • можем ли мы получить отсюда скелет RDL? Я получил XML-файл, сгенерированный из содержимого отчета с использованием кода string RDLCCode = System.Text.Encoding.UTF8.GetString(reportContent);, но могу ли получить схему дизайна? 02.11.2016
  • Сначала вы должны заполнить шаблон моделью и (ReportColumns) и инициализировать его, затем вы можете написать var reportContent = System.Text.Encoding.UTF8.GetBytes(report.TransformText());, затем System.IO.File.WriteAllText(@"d:\report1.rdlc", reportContent ); 02.11.2016
  • Вы можете показать мне, какие изменения мне нужно сделать. Мне кажется, что назначение модели и сериализация reportContent происходят в одном файле - ReportForm.cs. Однако я не знаю, как получить скелет RDL из этого 02.11.2016
  • Я думаю, что если вы вставите все приведенные выше комментарии в один исчерпывающий обучающий ответ, он будет весить столько же, сколько и сам ответ (^_^) 02.11.2016
  • Ты прав. Но ответ достаточно длинный, и он делает ответ слишком длинным, большинство пользователей в настоящее время не читают ответ, если я сделаю его более длинным, вероятно, это уменьшит вероятность того, что ответ будет прочитан. Insteaf вы можете проголосовать за комментарии, которые, по вашему мнению, более полезны для их появления. 02.11.2016
  • Я разместил отдельный вопрос для поиска ответов о создании отчета RDL по этой ссылке: stackoverflow.com/questions/40395159/. 03.11.2016
  • Я нашел этот пост действительно полезным! Я просто подумал, может ли Реза Агаей помочь мне включить группировку и сортировку? Я разместил новый связанный вопрос здесь 14.10.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..