BACKGROUND

Silverlight is a technology which has been in existence from quite sometime now. The Silverlight Viewer in ActiveReports was introduced to cater the needs of the developers who want to display their reports over the Silverlight platform. Customization has always been a key feature of ActiveReports and this blog article presents another example of one such implementation. In this blog article, we would learn how we can dynamically bind a Page Based Report when working with the silverlight viewer. We are focusing on the Page Based Reports since with Section Based Report, we can simply save the report document in RDF format, and using a service return it to the server, which can later be loaded directly into the Silverlight viewer. However the Page Based Report does not have a native document format which can hold its pages. So we will see how we can workaround it and achieve the desired results.

GETTING STARTED

As we read in the last paragraph, a Page Report cannot be directly streamed over to the server side. So what shall we do in order to load the report in the Silverlight viewer. Fortunately, the Page Based Reports provide Rendering Extensions which can be used to render the report into different formats. One of them is the RdfRenderingExtension. To enable this rendering extension, we need to add the "GrapeCity.ActiveReports.Export.Rdf.v8.dll" to the web project.

IMPLEMENTATION

Let us now see the steps which we need to follow in order to dynamically assign the datasource to the Page Based Report and later send it to the Silverlight viewer.

  • Adding a WCF service to the Web project and Return the report as Byte array First thing we need to do is to add a WCF service to the web project of solution. Here we will define a datasource, assign it to the report and finally write a method which will return the report as a byte array. However before sending the report, we will use the RdfRenderingExtension to export the report to RDF format. Performing this operation will enable us to load the report into the Silverlight viewer on the server side. Please note that the fields in the datasource below are already added to the report so that they can be recognized when the datasource is assigned to the report.This is how the code looks like:

    [ServiceContract(Namespace = "")]  
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  
    public class Service1  
    {  
       [OperationContract]  
       public void DoWork()  
       {  
          return;  
       }  
    
       public DataTable table()  
       {  
          DataTable dt = new DataTable("testtable");  
          dt.Columns.Add("Topic");  
          dt.Columns.Add("TimeGroup");  
          dt.Columns.Add("Time");  
          dt.Columns.Add("Device");  
          dt.Columns.Add("Value");  
    
          dt.Rows.Add(new[] { "topic1", "2005", "Jan", "Device1", "1" });  
          dt.Rows.Add(new[] { "topic2", "2006", "Jan", "Device1", "2" });  
          dt.Rows.Add(new[] { "topic3", "2007", "Jan", "Device1", "3" });  
          dt.Rows.Add(new[] { "topic4", "2008", "Feb", "Device1", "4" });  
          dt.Rows.Add(new[] { "topic5", "2009", "Feb", "Device1", "5" });  
          dt.Rows.Add(new[] { "topic6", "2010", "Feb", "Device1", "6" });  
          dt.Rows.Add(new[] { "topic7", "2011", "Mar", "Device2", "2" });  
          dt.Rows.Add(new[] { "topic8", "2012", "Mar", "Device2", "3" });  
          dt.Rows.Add(new[] { "topic9", "2013", "Mar", "Device2", "4" });  
          return dt;  
       }  
    
       [OperationContract]  
       public byte[] GetReport()  
       {  
          System.IO.FileInfo rptPath = new System.IO.FileInfo(HostingEnvironment.MapPath("~/Sample.rdlx"));  
          GrapeCity.ActiveReports.PageReport pageReport = new GrapeCity.ActiveReports.PageReport(rptPath);  
          GrapeCity.ActiveReports.Export.Rdf.RdfRenderingExtension rdfre = new GrapeCity.ActiveReports.Export.Rdf.RdfRenderingExtension();  
          pageReport.Document.LocateDataSource += new GrapeCity.ActiveReports.LocateDataSourceEventHandler(Document_LocateDataSource);  
          GrapeCity.ActiveReports.Rendering.IO.MemoryStreamProvider msp = new GrapeCity.ActiveReports.Rendering.IO.MemoryStreamProvider();  
          pageReport.Document.Render(rdfre, msp);  
          return (msp.GetPrimaryStream().OpenStream() as MemoryStream).ToArray();  
       }  
    
       void Document_LocateDataSource(object sender, GrapeCity.ActiveReports.LocateDataSourceEventArgs args)  
       {  
          args.Data = table();  
       }  
    }
    
  • Loading the Returned Report in the SilverLight Viewer Now since we have the Stream containing the report, the next step is to read it an load it into the Silverlight viewer. To do this, we will add the service reference to the Silverlight project and create a new ServiceClient. Next we will create an event handler for the GetReportCompleted event of the ServiceClient and use the LoadDocument method of the Silverlight viewer. This is how the code will look:

    private void viewer1_Loaded(object sender, RoutedEventArgs e)  
    {  
       ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();  
       client.GetReportCompleted += new EventHandler<ServiceReference1.GetReportCompletedEventArgs>(client_GetReportCompleted);  
       client.GetReportAsync();  
    }  
    
    void client_GetReportCompleted(object sender, ServiceReference1.GetReportCompletedEventArgs e)  
    {  
       System.IO.MemoryStream stream = new System.IO.MemoryStream(e.Result);  
       stream.Position = 0;  
       GrapeCity.Viewer.Common.StreamDocumentLoader sdl = new GrapeCity.Viewer.Common.StreamDocumentLoader(stream, GrapeCity.Viewer.Common.DocumentFormat.Rdf);  
       viewer1.LoadDocument(sdl);  
    }
    

    So this completes the implementation process. A sample application which implements this functionality can be downloaded using the download icon below.