Разделы

ПО Софт

Club.CNews: Reports for Silverlight или построитель отчетов c шаблонами и с группировкой

Установка Reports

Библиотека Calabonga.Silverlight.Reports специально упакована в nuget-пакет чтобы можно было с легкостью устанавливать/обновлять/удалять эту библиотеку. Давайте предположим, что Nuget Manager у Вас уже установлен, и тогда можно сразу перейти к установке пакет отчетов. Я создал новый Silverlight-проект чтобы продемонстрировать работу библиотеки. Нажимаем на проекте правую кнопку мыши и запускаем менеджер Nuget:

image

В открывшемся окне менеджера в поле поиска вбиваем “calabonga” и перед нами все пакеты, которые доступны под брендом “calabonga”:

image

На данный момент нам потребуется первый в списке “Silverlight Reporting”. А следом за ним я установлю “Samlpe classes and data” чтобы было “что” печать и группировать.

Кнопка “Печать” и “Предварительный просмотр”

На главную страницу проекта добавлю две кнопки, а перед этим разобью на области сетку. А также добавлю ContentControl для того чтобы в него поместить предварительный просмотр сформированного отчета перед печатью:

   1:  <Grid x:Name="LayoutRoot"
   2:              Background="White">
   3:      <Grid.RowDefinitions>
   4:          <RowDefinition Height="36" />
   5:          <RowDefinition Height="*" />
   6:      </Grid.RowDefinitions>
   7:      <Button Content="Печать"
   8:                      Height="23"
   9:                      HorizontalAlignment="Left"
  10:                      Margin="13,6,0,0"
  11:                      Name="print"
  12:                      VerticalAlignment="Top"
  13:                      Width="75"
  14:                      Click="print_Click" />
  15:      <Button Content="Просмотр"
  16:                      Height="23"
  17:                      HorizontalAlignment="Left"
  18:                      Margin="94,6,0,0"
  19:                      Name="preview"
  20:                      VerticalAlignment="Top"
  21:                      Width="75"
  22:                      Click="preview_Click" />
  23:      <ContentControl Grid.Row="1"
  24:                      VerticalContentAlignment="Stretch"
  25:                      HorizontalContentAlignment="Stretch"
  26:                      Name="previewBox" />
  27:  </Grid>

Разметка простая, давай те теперь создадим шаблон.

Создаем шаблон печати (ItemTemplate)

Добавлю в проект новый Silverlight UserControl. Пусть называется он Report1.xaml:

image

Надо добавить namespace для того чтобы Report стал доступен:

xmlns:clb="http://schemas.calabonga.com"

Я во всех своих библиотеках предпочитаю использовать такой namespace, что не приходилось “бегать, искать” что в какой сборке. Вы можете использовать такой же подход в своих сборках. Как сделать “красивый” namespace уже было описано ранее.

Теперь пришло время подготовить данные для печати. Создадим пару-тройку переменных:

   1:  private List<Person> printData;
   2:  private Report1 report1;

Теперь вернемся в разметку самого шаблона, надо же к нему как-нибудь обращаться и для этого дадим ему имя, пусть зовут его CalaReport:

   1:  <Grid x:Name="LayoutRoot"
   2:              Background="White">
   3:  
   4:      <clb:Report Title="Первый отчет" x:Name="CalaReport">
   5:              
   6:      </clb:Report>
   7:          
   8:  </Grid>

А теперь добавим шаблон (ItemTemplate), который будет “рисовать” Person. Если посмотреть в библиотеку SilverlightSampleData, то можно увидеть свойства класса, которые можно отобразить в шаблоне:

image

Мой шаблон будет такой:

   1:  <clb:Report.ItemTemplate>
   2:              <DataTemplate>
   3:                  <Grid>
   4:                      <Grid.ColumnDefinitions>
   5:                          <ColumnDefinition />
   6:                          <ColumnDefinition />
   7:                          <ColumnDefinition />
   8:                          <ColumnDefinition />
   9:                          <ColumnDefinition />
  10:                          <ColumnDefinition />
  11:                          <ColumnDefinition />
  12:                      </Grid.ColumnDefinitions>
  13:                      <Border Grid.Column="0"
  14:                                      Style="{StaticResource border}">
  15:                          <TextBlock Text="{Binding Path=[Name]}"
  16:                                               Grid.Column="0" />
  17:                      </Border>
  18:                      <Border Grid.Column="1"
  19:                                      Style="{StaticResource border}">
  20:                          <TextBlock Text="{Binding Path=[Gender]}"
  21:                                               Grid.Column="1" />
  22:                      </Border>
  23:                      <Border Grid.Column="2"
  24:                                      Style="{StaticResource border}">
  25:                          <TextBlock Text="{Binding Path=[IsMember]}"
  26:                                               Grid.Column="2" />
  27:                      </Border>
  28:                      <Border Grid.Column="3"
  29:                                      Style="{StaticResource border}">
  30:                          <TextBlock Text="{Binding Path=[Age]}"
  31:                                               Grid.Column="3" />
  32:                      </Border>
  33:                      <Border Grid.Column="4"
  34:                                      Style="{StaticResource border}">
  35:                          <TextBlock Text="{Binding Path=[Description]}"
  36:                                               Grid.Column="4" />
  37:                      </Border>
  38:                      <Border Grid.Column="5"
  39:                                      Style="{StaticResource border}">
  40:                          <TextBlock Text="{Binding Path=[Weight]}"
  41:                                               Grid.Column="5" />
  42:                      </Border>
  43:                      <Border Grid.Column="6"
  44:                                      Style="{StaticResource border}">
  45:                          <TextBlock Text="{Binding Path=[Country]}"
  46:                                               Grid.Column="6" />
  47:                      </Border>
  48:                  </Grid>
  49:  
  50:              </DataTemplate>
  51:          </clb:Report.ItemTemplate>

Обратите внимание на то, как осуществляется привязка – в квадратных скобках. Просто мне кажется “так красивее” :)

И добавим еще и стили, которые использованы в шаблоне для отображения.

   1:  <UserControl.Resources>
   2:      <Style TargetType="TextBlock"
   3:                      x:Key="header">
   4:          <Setter Property="FontSize"
   5:                          Value="11" />
   6:          <Setter Property="HorizontalAlignment"
   7:                          Value="Center" />
   8:          <Setter Property="FontWeight"
   9:                          Value="Bold" />
  10:      </Style>
  11:      <Style TargetType="Border"
  12:                      x:Key="border">
  13:          <Setter Property="BorderBrush"
  14:                          Value="Gray" />
  15:          <Setter Property="BorderThickness"
  16:                          Value="1" />
  17:          <Setter Property="Margin"
  18:                          Value="1" />
  19:          <Setter Property="Padding"
  20:                          Value="3" />
  21:      </Style>
  22:  </UserControl.Resources>

Напишем код обработки нажатия кнопок, я приведу весь код, чтобы больше к нему не возвращаться, потому что он не измениться:

   1:  public partial class MainPage : UserControl
   2:  {
   3:      private List<Person> printData;
   4:      private Report1 report1;
   5:  
   6:      public MainPage()
   7:      {
   8:          InitializeComponent();
   9:          Loaded += new RoutedEventHandler(MainPage_Loaded);
  10:      }
  11:  
  12:      void MainPage_Loaded(object sender, RoutedEventArgs e)
  13:      {
  14:          report1 = new Report1();
  15:          printData = People.GetPeople();
  16:          report1.CalaReport.ItemsSource = printData;
  17:      }
  18:  
  19:      private void print_Click(object sender, RoutedEventArgs e)
  20:      {
  21:          report1.CalaReport.Print();
  22:      }
  23:  
  24:      private void preview_Click(object sender, RoutedEventArgs e)
  25:      {
  26:          previewBox.Content = report1.CalaReport.GetPreview(previewBox);
  27:      }
  28:  }

Ну а теперь, давайте попробуем напечатать. Ура! Что-то видно на превью, да и на принтер что-то улетело… зажужжал гадина:

image

Надо бы HeaderTemplate и FooterTemplate добавить – для красоты и эстетики:

   1:  <clb:Report.PageHeaderTemplate>
   2:      <DataTemplate>
   3:          <Grid MinHeight="40"
   4:                      Background="Wheat">
   5:              <Grid.ColumnDefinitions>
   6:                  <ColumnDefinition />
   7:                  <ColumnDefinition />
   8:                  <ColumnDefinition />
   9:                  <ColumnDefinition />
  10:                  <ColumnDefinition />
  11:                  <ColumnDefinition />
  12:                  <ColumnDefinition />
  13:                  <ColumnDefinition />
  14:                  <ColumnDefinition />
  15:              </Grid.ColumnDefinitions>
  16:              <Border Grid.Column="0"
  17:                              Style="{StaticResource border}">
  18:                  <TextBlock Text="Имя"
  19:                                          Style="{StaticResource header}" />
  20:              </Border>
  21:              <Border Grid.Column="1"
  22:                              Style="{StaticResource border}">
  23:                  <TextBlock Text="Пол"
  24:                                          Style="{StaticResource header}" />
  25:              </Border>
  26:              <Border Grid.Column="2"
  27:                              Style="{StaticResource border}">
  28:                  <TextBlock Text="Участник"
  29:                                          Style="{StaticResource header}" />
  30:              </Border>
  31:              <Border Grid.Column="3"
  32:                              Style="{StaticResource border}">
  33:                  <TextBlock Text="Возраст"
  34:                                          Style="{StaticResource header}" />
  35:              </Border>
  36:              <Border Grid.Column="4"
  37:                              Style="{StaticResource border}">
  38:                  <TextBlock Text="Описание"
  39:                                          Style="{StaticResource header}" />
  40:              </Border>
  41:              <Border Grid.Column="5"
  42:                              Style="{StaticResource border}">
  43:                  <TextBlock Text="Вес"
  44:                                          Style="{StaticResource header}" />
  45:              </Border>
  46:              <Border Grid.Column="6"
  47:                              Style="{StaticResource border}">
  48:                  <TextBlock  Text="Страна"
  49:                                          Style="{StaticResource header}" />
  50:              </Border>
  51:          </Grid>
  52:      </DataTemplate>
  53:  </clb:Report.PageHeaderTemplate>

и нижняя часть:

   1:  <clb:Report.ReportFooterTemplate>
   2:      <DataTemplate>
   3:          <Grid HorizontalAlignment="Stretch"
   4:                      MinHeight="30"
   5:                      Background="LightGray">
   6:              <TextBlock Text="Этот отчет сгенерирован при помощи 
                                   библиотеки Calabonga.Silverlight.Reports." />
   7:          </Grid>
   8:      </DataTemplate>
   9:  </clb:Report.ReportFooterTemplate>

Нажимаем печать… И!…

Untitled-3

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

Группировка и Агрегирующие функции

Эта библиотека была изначально задумана как “способная группировать и агрегировать данные при печати. Пришло время проверить на что она способна. Перед тем как добавить группировку надо подключить mscorlib.dll:

   1:  xmlns:sys="clr-namespace:System;assembly=mscorlib"

Добавим группировку по стране (Country):

   1:  <clb:Report.Groups>
   2:      <clb:GroupDefinitions>
   3:          <clb:GroupDefinitions.GroupedFields>
   4:              <sys:String>Country</sys:String>
   5:          </clb:GroupDefinitions.GroupedFields>
   6:      </clb:GroupDefinitions>
   7:  </clb:Report.Groups>

Определение поля по которому группировать происходит в четвертой строке. Можно добавить сколь угодно параметров группировки (конечно же в разумных пределах). А добавлю-ка я сразу еще и по половому признаку группировку поместив строку:

   1:  <sys:String>Gender</sys:String>

Между 4 и 5 строками. Теперь раз добавлена группировка следует добавить и шаблоны для группировки (Header и Footer), иначе прилетит ошибка. Шаблон группировки выглядит так:

   1:  <clb:Report.GroupHeaderTemplate>
   2:      <DataTemplate>
   3:          <Border BorderBrush="Black"
   4:                          BorderThickness="1"
   5:                          Background="Silver"
   6:                          MinHeight="40">
   7:              <StackPanel Orientation="Horizontal">
   8:                  <TextBlock Text="{Binding Path=[Country]}"
   9:                                          Margin="30,0,20,0"
  10:                                          Style="{StaticResource header}" />
  11:                  <TextBlock Text="{Binding Path=[Gender]}"
  12:                                          Margin="30,0,20,0"
  13:                                          Style="{StaticResource header}" />
  14:                  <TextBlock Text="{Binding Path=[Weight]}"
  15:                                          Margin="30,0,20,0"
  16:                                          Style="{StaticResource header}" />
  17:                  <TextBlock Text="{Binding Path=[Age]}"
  18:                                          Margin="30,0,20,0"
  19:                                          Style="{StaticResource header}" />
  20:              </StackPanel>
  21:          </Border>
  22:      </DataTemplate>
  23:  </clb:Report.GroupHeaderTemplate>
  24:  <clb:Report.GroupFooterTemplate>
  25:              <DataTemplate>
  26:                  <Border BorderBrush="Black"
  27:                                  BorderThickness="1"
  28:                                  Background="Gainsboro"
  29:                                  MinHeight="30">
  30:                      <StackPanel Orientation="Horizontal">
  31:                          <TextBlock Text="Итого вес:"
  32:                                               Margin="0,0,20,0" />
  33:                          <TextBlock Text="{Binding Path=[Weight]}"
  34:                                               Style="{StaticResource header}"
  35:                                               Margin="0,0,60,0" />
  36:                          <TextBlock Text="Возраст средний:"
  37:                                               Margin="0,0,20,0" />
  38:                          <TextBlock Text="{Binding Path=[Age]}"
  39:                                               Style="{StaticResource header}" />
  40:                      </StackPanel>
  41:                  </Border>
  42:              </DataTemplate>
  43:          </clb:Report.GroupFooterTemplate>

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

   1:  <clb:GroupDefinitions.Aggregations>
   2:      <clb:AggregateFieldDefinition Field="Weight">
   3:          <clb:AggregateFieldDefinition.AggregateFunctions>
   4:              <clb:AggregateFunctionDefinition Function="Sum" />
   5:          </clb:AggregateFieldDefinition.AggregateFunctions>
   6:      </clb:AggregateFieldDefinition>
   7:      <clb:AggregateFieldDefinition Field="Age">
   8:          <clb:AggregateFieldDefinition.AggregateFunctions>
   9:              <clb:AggregateFunctionDefinition Function="Average" />
  10:          </clb:AggregateFieldDefinition.AggregateFunctions>
  11:      </clb:AggregateFieldDefinition>
  12:  </clb:GroupDefinitions.Aggregations>

Компилируем… Запускаем…. Нажимаем предварительный просмотр… И… вуаля:

image

Шаблоны подготовленные мной конечно оставляют желать лучшего по части эстетического вида, но как бы там не было отчет на бумаге.

Какая CRM подойдет вашей компании? Тест
Цифровизация

Так же хотелось бы добавить, что существуют еще и другие варианты шаблонов. А так же достаточное количество событий.

image

Надеюсь, что контрол будет востребован. На этом всё. Пишите комментарии.