Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

LightSwitch: utilizzare i controlli Telerik per visualizzare, stampare, esportare dati - parte 2

Nel post precedente abbiamo visto come creare uno user control in Silverlight 4 che fa uso di alcuni controlli della suite RadControl for Silverlight di Telerik, da utilizzare in un'applicazione LightSwitch.

Abbiamo sostanzialmente creato il controllo, sostituito la DataGrid di default in LightSwitch, eseguito il data-binding e visto come il tutto venga eseguito alla perfezione, sfruttando le interessanti funzionalità dei controlli citati.

Avevamo anche predisposto dei pulsanti per esportare e stampare i dati, ma queste funzionalità sono da implementare in questo post. Faremo anche di più: dimostreremo che il controllo creato la volta scorsa è riutilizzabile. Partiamo proprio da questo aspetto, creando un nuovo screen di tipo EditableGrid che punta alla collection di Orders:

Una volta che lo Screen Designer, seguiamo le istruzioni descritte la volta scorsa per sostituire la DataGrid di default con il controllo utente personalizzato. Se ora eseguiamo l'applicazione, notiamo come il nuovo screen faccia correttamente uso del controllo:

La ragione di questa riutilizzabilità è dovuta al fatto che la RadGridView supporta, nella proprietà ItemsSource, l'assegnazione di una generica proprietà Value, anzichè ricevere il nome della collection come invece avevamo visto in altri scenari. Indubbiamente questo è un grandissimo vantaggio.

Ora passiamo ad altro e iniziamo a rendere operativi i vari pulsanti. Faccio una premessa: il codice non è poco e non mi dilungherò in spiegazioni perché il codice stesso è stato interamente ripreso dalla pagina degli esempi di Telerik, che offre anche documentazione ufficiale sui controlli. Prima alcune direttive Imports:

Imports System.Collections
Imports System.Collections.Generic
Imports Telerik.Windows.Controls
Imports System.IO
Imports System.Linq
Imports Telerik.Windows.Data
Imports System.Windows
Imports Telerik.Windows.Documents.FormatProviders
Imports Telerik.Windows.Documents.Model
Imports Telerik.Windows.Documents.FormatProviders.Pdf
Imports System.Windows.Printing

Il primo pulsante è quello che si occupa di esportare in Excel. In particolare, decidiamo di sfruttare il formato built-in di esportazione come Csv:

    Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgsHandles Button1.Click
        Dim extension As String = "csv"
        'Ci sono anche altri formati, come Html e Word
        Dim format As ExportFormat = ExportFormat.Csv
 
        Dim dialog As New SaveFileDialog()
        dialog.DefaultExt = extension
        dialog.Filter = String.Format("{1} files (*.{0})|*.{0}|All files (*.*)|*.*", extension, "Excel")
        dialog.FilterIndex = 1
 
        If dialog.ShowDialog() = True Then
            Using stream As IO.Stream = dialog.OpenFile()
                Dim exportOptions As New GridViewExportOptions()
                exportOptions.Format = format
                exportOptions.ShowColumnFooters = True
                exportOptions.ShowColumnHeaders = True
                exportOptions.ShowGroupFooters = True
 
                RadGridView1.Export(stream, exportOptions)
            End Using
        End If
 
    End Sub

Il secodo pulsante da gestire è quello che si occupa di stampare i dati. Questa è una funzionalità indubbiamente fondamentale e grazie ai RadControls, con poco sforzo, si implementa con successo:

    Private Sub PrintBitton_Click(sender As System.Object, e As System.Windows.RoutedEventArgsHandles PrintBitton.Click
        offsetY = 0
        totalHeight = 0
 
        grid = New RadGridView()
        grid.DataContext = RadGridView1.DataContext
        grid.ItemsSource = RadGridView1.ItemsSource
        grid.RowIndicatorVisibility = Visibility.Collapsed
        grid.ShowGroupPanel = False
        grid.CanUserFreezeColumns = False
        grid.IsFilteringAllowed = False
        grid.AutoExpandGroups = True
        grid.AutoGenerateColumns = False
 
        For Each column As GridViewDataColumn In RadGridView1.Columns.OfType(Of GridViewDataColumn)()
            Dim newColumn As New GridViewDataColumn()
            newColumn.DataMemberBinding = New System.Windows.Data.Binding(column.UniqueName)
            grid.Columns.Add(newColumn)
        Next
 
        For Each column As GridViewDataColumn In grid.Columns.OfType(Of GridViewDataColumn)()
            Dim currentColumn As GridViewDataColumn = column
 
            Dim originalColumn As GridViewDataColumn = (From c In RadGridView1.Columns.OfType(Of GridViewDataColumn)() _
             Where c.UniqueName = currentColumn.UniqueName _
             Select c).FirstOrDefault()
            If originalColumn IsNot Nothing Then
                column.Width = originalColumn.ActualWidth
                column.DisplayIndex = originalColumn.DisplayIndex
            End If
        Next
 
        StyleManager.SetTheme(grid, StyleManager.GetTheme(RadGridView1))
 
        grid.SortDescriptors.AddRange(RadGridView1.SortDescriptors)
        grid.GroupDescriptors.AddRange(RadGridView1.GroupDescriptors)
        grid.FilterDescriptors.AddRange(RadGridView1.FilterDescriptors)
 
        ScrollViewer.SetHorizontalScrollBarVisibility(grid, ScrollBarVisibility.Hidden)
        ScrollViewer.SetVerticalScrollBarVisibility(grid, ScrollBarVisibility.Hidden)
 
        Dim doc As New PrintDocument()
 
        canvas = New Canvas()
        canvas.Children.Add(grid)
 
        AddHandler doc.PrintPage, AddressOf Me.doc_PrintPage
        doc.Print("RadGridView print")
    End Sub
 
    Private Sub doc_PrintPage(sender As Object, e As PrintPageEventArgs)
        e.PageVisual = canvas
 
        If totalHeight = 0 Then
            totalHeight = grid.DesiredSize.Height
        End If
 
        canvas.SetTop(grid, -offsetY)
 
        offsetY += e.PrintableArea.Height
        e.HasMorePages = offsetY <= totalHeight
 
    End Sub

Ora viene il turno dell'esportazione in PDF. Questo richiede l'aggiunta di un riferimento a due assembly, Telerik.Windows.Documents e Telerik.Windows.Documents.FormatProviders.Pdf. Ci sono anche altre provider di esportazione, ma ci limitiamo al PDF. Dopodichè, questo è il codice da inserire:

   Private Sub ExportPDFButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgsHandles ExportPDFButton.Click
        Dim dialog As New SaveFileDialog()
        dialog.DefaultExt = "*.pdf"
        dialog.Filter = "Adobe PDF Document (*.pdf)|*.pdf"
 
        If dialog.ShowDialog() = True Then
            Dim document As RadDocument = CreateDocument(RadGridView1)
 
            document.LayoutMode = DocumentLayoutMode.Paged
 
            document.Measure(RadDocument.MAX_DOCUMENT_SIZE)
            document.Arrange(New RectangleF(PointF.Empty, document.DesiredSize))
 
            Dim provider As New PdfFormatProvider()
 
            Using output As Stream = dialog.OpenFile()
                provider.Export(document, output)
            End Using
        End If
 
    End Sub
 
    Private Function CreateDocument(grid As RadGridViewAs RadDocument
        Dim columns As List(Of GridViewBoundColumnBase) = (From c In grid.Columns.OfType(Of GridViewBoundColumnBase)() _
         Order By c.DisplayIndex _
         Select c).ToList()
 
        Dim table As New Table()
 
        Dim document As New RadDocument()
        Dim section As New Section()
        section.Blocks.Add(table)
        document.Sections.Add(section)
 
        If grid.ShowColumnHeaders Then
            Dim headerRow As New TableRow()
 
            If grid.GroupDescriptors.Count() > 0 Then
                Dim indentCell As New TableCell()
                indentCell.PreferredWidth = New TableWidthUnit(grid.GroupDescriptors.Count() * 20)
                indentCell.Background = Colors.Blue
                headerRow.Cells.Add(indentCell)
            End If
 
            For i As Integer = 0 To columns.Count() - 1
                Dim cell As New TableCell()
                cell.Background = Colors.White
                AddCellValue(cell, columns(i).UniqueName)
                cell.PreferredWidth = New TableWidthUnit(CSng(columns(i).ActualWidth))
                headerRow.Cells.Add(cell)
            Next
 
            table.Rows.Add(headerRow)
        End If
 
        If grid.Items.Groups IsNot Nothing Then
            For i As Integer = 0 To grid.Items.Groups.Count() - 1
                AddGroupRow(table, TryCast(grid.Items.Groups(i), QueryableCollectionViewGroup), columns, grid)
            Next
        Else
            AddDataRows(table, grid.Items, columns, grid)
        End If
 
        Return document
    End Function
 
    Private Sub AddDataRows(table As Table, items As IList, columns As IList(Of GridViewBoundColumnBase), grid As RadGridView)
        For i As Integer = 0 To items.Count - 1
            Dim row As New TableRow()
 
            If grid.GroupDescriptors.Count() > 0 Then
                Dim indentCell As New TableCell()
                indentCell.PreferredWidth = New TableWidthUnit(grid.GroupDescriptors.Count() * 20)
                indentCell.Background = Colors.Blue
                row.Cells.Add(indentCell)
            End If
 
            For j As Integer = 0 To columns.Count() - 1
                Dim cell As New TableCell()
 
                Dim value As Object = columns(j).GetValueForItem(items(i))
 
                AddCellValue(cell, If(value IsNot Nothing, value.ToString(), String.Empty))
 
                cell.PreferredWidth = New TableWidthUnit(CSng(columns(j).ActualWidth))
                cell.Background = Colors.White
 
                row.Cells.Add(cell)
            Next
 
            table.Rows.Add(row)
        Next
    End Sub
 
    Private Sub AddGroupRow(table As Table, group As QueryableCollectionViewGroup, columns As IList(Of GridViewBoundColumnBase), grid As RadGridView)
        Dim row As New TableRow()
 
        Dim level As Integer = GetGroupLevel(group)
        If level > 0 Then
            Dim cell As New TableCell()
            cell.PreferredWidth = New TableWidthUnit(level * 20)
            cell.Background = Colors.Gray
            row.Cells.Add(cell)
        End If
 
        Dim aggregatesCell As New TableCell()
        aggregatesCell.Background = Colors.DarkGray
        aggregatesCell.ColumnSpan = columns.Count() + (If(grid.GroupDescriptors.Count() > 0, 1, 0)) - (If(level > 0, 1, 0))
 
        AddCellValue(aggregatesCell, If(group.Key IsNot Nothing, group.Key.ToString(), String.Empty))
 
        For Each result As AggregateResult In group.AggregateResults
            AddCellValue(aggregatesCell, If(result.FormattedValue IsNot Nothing, result.FormattedValue.ToString(), String.Empty))
        Next
 
        row.Cells.Add(aggregatesCell)
 
        table.Rows.Add(row)
 
        If group.HasSubgroups Then
            For i As Integer = 0 To group.Subgroups.Count() - 1
                AddGroupRow(table, TryCast(group.Subgroups(i), QueryableCollectionViewGroup), columns, grid)
            Next
        Else
            For i As Integer = 0 To group.ItemCount - 1
                AddDataRows(table, group.Items, columns, grid)
            Next
        End If
    End Sub
 
    Private Sub AddCellValue(cell As TableCell, value As String)
        Dim paragraph As New Paragraph()
        cell.Blocks.Add(paragraph)
 
        Dim span As New Span()
        span.Text = value
 
        paragraph.Inlines.Add(span)
    End Sub
 
    Private Function GetGroupLevel(group As IGroupAs Integer
        Dim level As Integer = 0
 
        Dim parent As IGroup = group.ParentGroup
 
        While parent IsNot Nothing
            level += 1
            parent = parent.ParentGroup
        End While
 
        Return level
    End Function

Le varie proprietà Background possono essere sostituite con dei colori diversi. Ora mandiamo in esecuzione l'applicazione e giochiamo coi vari pulsanti. Ad esempio, l'esportazione come CSV genera il seguente output:

Mentre questo è il risultato dell'esportazione in PDF:

In più, come dicevamo la volta scorsa, con questo sistema è possibile esportare dati anche se l'applicazione gira come Web client, perchè il tutto non si basa sugli elevati privilegi delle out-of-browser.

In sintesi:

  • la suite di Telerik è fenomenale, ma è solo un esempio. Potete usare anche controlli di altri produttori, ma soprattutto controlli open source e free
  • LightSwitch è estendibile, permette l'uso di controlli compositi anche complessi
  • quello che in LightSwitch non c'è, si può aggiungere senza grossi sforzi. Un po' di XAML, un po' di codice.

Alessandro

Print | posted on martedì 19 aprile 2011 01:04 | Filed Under [ Silverlight e Windows Phone Visual Studio LightSwitch ]

Powered by:
Powered By Subtext Powered By ASP.NET