How to: Create Report Designers

In PerformancePoint Dashboard Designer, you can create a report view object by using a wizard template. Then, when you select the object in the workspace, a report designer appears.

To create a report designer extension, you must reference the Microsoft.PerformancePoint.Scorecards.ModelerPlugins DLL and implement the following classes:

The report designer extension described in this topic also implements the Implementing MyReportViewDocument class, but this class is not required for all report extensions.

The code examples that follow create a wizard template and report designer for a report view that reads and displays inbound parameters.

Prerequisites

Before you compile the code examples, ensure you have met the following prerequisites:

Implementing ReportViewEditorControl

The following code example creates a report designer plug-in that lets users define properties for the report. Typically, a report designer provides Editor, Properties, and View tabs that contain Windows Forms controls. This example uses a panel (myReportViewEditorPanel) to host the controls on the Editor tab.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Microsoft.PerformancePoint.Scorecards;
using Microsoft.PerformancePoint.Scorecards.Modeler.Framework.Utilities;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.ReportViews;

namespace MyReportViewPluginClient
{

    // This class creates a Microsoft .NET Framework custom control for the client. 
    // You must derive your report control from the
    // ReportViewEditorControl class that is defined in
    // the Modeler.Framework assembly.
    public class MyReportViewEditorControl : ReportViewEditorControl 
    { 
        private MyReportViewEditorPanel myReportViewEditorPanel;

        // Get the panel that contains the editing controls.
        public MyReportViewEditorControl() 
        { 
            this.myReportViewEditorPanel = new MyReportViewEditorPanel();
            this.myReportViewEditorPanel.Dock = DockStyle.Fill;
            this.Controls.Add(this.myReportViewEditorPanel);
        } 

        // Override the SetSummaryPanel method to customize
        // the Editor tab. The overridden method can be empty. 
        public override void SetSummaryPanel(ReportViewSummaryTab summary)
        {
        }

        public override Guid ReportViewId 
        {
            get { return this.myReportViewEditorPanel.Report.Guid; }
        } 

        // Each report type can have only one instantiation 
        // of its ReportViewEditor control type.
        // When the user clicks the report in the workspace, SetElement 
        // informs your control that a new item is being edited.
        // The "reportView" parameter is the new item that is being edited.
        // Therefore, you must set the custom data fields in your 
        // control that are specific to the report instance.
        public override void SetElement(ReportView reportView, UndoManager undoManager) 
        {
            this.myReportViewEditorPanel.Report = reportView;
        }

        public override CheckBox AppendPageFiltersCheckBox
        {
            get { return new CheckBox(); }
        }

        public override TextBox HeightTextBox
        {
            get { return new TextBox(); }
        }

        public override TextBox WidthTextBox
        {
            get { return new TextBox(); }
        }
    }
}

Implementing UserControl

The following code example creates the controls on the Editor tab in Dashboard Designer, which let users edit properties for the custom report view.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;

using Microsoft.PerformancePoint.Scorecards;
using Microsoft.PerformancePoint.Scorecards.Modeler.Framework.Utilities;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.ReportViews;
using Microsoft.PerformancePoint.Scorecards.ModelerWorkspace;

namespace MyReportViewPluginClient
{
    public class MyReportViewEditorPanel : UserControl
    {
        private ReportView report;

        private TextBox customDataTextBox;
        private Label dataLabel;

        public ReportView Report
        {
            get { return this.report; }
            
            set 
            {
                this.report = value;

                try
                {
                    string documentXml = this.report.CustomData;

                    StringReader stringReader = new StringReader(documentXml);
                    XmlSerializer deserializer = new XmlSerializer(typeof(MyReportViewDocument));
                    MyReportViewDocument myReportViewDocument = (MyReportViewDocument)deserializer.Deserialize(stringReader);
                    stringReader.Close();

                    this.customDataTextBox.Text = myReportViewDocument.MyCustomData;
                }
                catch
                { 
                }
            }
        }

        public MyReportViewEditorPanel()
        {
            InitializeComponent();
            this.customDataTextBox.TextChanged += new EventHandler(customDataTextBox_TextChanged);
        }

        private void customDataTextBox_TextChanged(object sender, EventArgs e)
        {
            if (null == this.report)
            {
                return;
            }

            MyReportViewDocument myReportViewDocument = new MyReportViewDocument();
            myReportViewDocument.MyCustomData = this.customDataTextBox.Text;
            XmlSerializer serializer = new XmlSerializer(typeof(MyReportViewDocument));
            StringBuilder stringBuilder = new StringBuilder();
            StringWriter stringWriter = new StringWriter(stringBuilder);
            serializer.Serialize(stringWriter, myReportViewDocument);
            string documentXml = stringBuilder.ToString().Normalize();
            stringWriter.Close();

            this.report.CustomData = documentXml;

            ScorecardModel.GetInstance().
                FireFirstClassElementChanged
                    (ScorecardModel.InternalWorkspaceItemUpdate, this.report);
        }

        private void InitializeComponent()
        {
            this.dataLabel = new System.Windows.Forms.Label();
            this.customDataTextBox = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // dataLabel
            // 
            this.dataLabel.AutoSize = true;
            this.dataLabel.Location = new System.Drawing.Point(19, 15);
            this.dataLabel.Name = "dataLabel";
            this.dataLabel.Size = new System.Drawing.Size(143, 13);
            this.dataLabel.TabIndex = 0;
            this.dataLabel.Text = "Enter your custom data here:";
            // 
            // customDataTextBox
            // 
            this.customDataTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.customDataTextBox.Location = new System.Drawing.Point(22, 31);
            this.customDataTextBox.Multiline = true;
            this.customDataTextBox.Name = "customDataTextBox";
            this.customDataTextBox.Size = new System.Drawing.Size(140, 111);
            this.customDataTextBox.TabIndex = 1;
            // 
            // MyReportViewEditorPanel
            // 
            this.BackColor = System.Drawing.SystemColors.Control;
            this.Controls.Add(this.customDataTextBox);
            this.Controls.Add(this.dataLabel);
            this.Name = "MyReportViewEditorPanel";
            this.Size = new System.Drawing.Size(186, 168);
            this.ResumeLayout(false);
            this.PerformLayout();
        }
    }
}

Implementing ReportViewFactory

The following code example connects your extension to Dashboard Designer.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;

using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.ReportViews;

namespace MyReportViewPluginClient
{
    public class MyReportViewFactory : ReportViewFactory
    {
        public const string MyReportViewFactoryReportName = "MyReportViewWebControl";

        public override ReportViewEditorControl CreateReportViewEditorControl()
        {
            return new MyReportViewEditorControl();
        }

        public override string DisplayName
        {
            get { return "MyReportView DisplayName"; }
        }

        public override Image Image
        {
            get 
            {

                // The image for the report view.
                // Change the image name to reference your custom image.
                Stream imageStream =
                    typeof(MyReportViewFactory).Assembly.
                        GetManifestResourceStream("MyReportViewPluginClient.MyReportView.bmp");

                Image image = Image.FromStream(imageStream);

                imageStream.Close();

                return image;
            }
        }

        public override void Initialize()
        {
        }

        public override string ReportName
        {
            get { return MyReportViewFactory.MyReportViewFactoryReportName; }
        }
    }
}

Implementing TemplateFactory

The following code example adds the custom report view as an available report type in the Select a Report Template dialog box. For more information, see How to: Implement a Template Class Factory.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.PerformancePoint.Scorecards;
using Microsoft.PerformancePoint.Scorecards.Modeler.Framework;
using Microsoft.PerformancePoint.Scorecards.Modeler.Framework.Utilities;
using Microsoft.PerformancePoint.Scorecards.ModelerWorkspace;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.Controls;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.DataSources;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.Properties;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.ReportViews;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.Scorecards;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.Templates;
using Microsoft.PerformancePoint.Scorecards.ModelerPlugins.Utilities;

namespace MyReportViewPluginClient
{
    public class MyReportViewTemplateFactory : TemplateFactory
    {
        
        // Get the identifier for the "MyReportViewTemplateFactory" class.
        // The identifier has identity with THIS FACTORY, but
        // not with the templates that THIS FACTORY creates.
        public override string GetTemplateTypeId()
        {
            return "MyReportViewTemplateFactory";
        }
        
        // Get the class type for the report view template.
        public override Type GetTemplateType()
        {
            return typeof(MyReportViewTemplateFactory);
        }
        
        // Get the available report view templates for 
        // the New Report wizard.
        public override List<TemplateItem> GetTemplateItems()
        {
            List<TemplateItem> items = new List<TemplateItem>();

            TemplateItem item1 = new TemplateItem();

            Stream imageStream =
                typeof(MyReportViewFactory).Assembly.
                    GetManifestResourceStream("MyReportViewPluginClient.MyReportView.bmp");
            Image myReportViewImage = Image.FromStream(imageStream);
            imageStream.Close();

            item1.Name = "My Report View";
            item1.Image = myReportViewImage;
            item1.TemplateId = MyReportViewDocument.MyReportViewDocumentTypeId;
            item1.TemplateTypeId = GetTemplateTypeId();
            
            item1.Description = 
                "<span style='font-size:8.0pt;font-family:\"MS Reference Sans Serif\",\"sans-serif\"'>" +
                "My Report View<hr>An html description of My Report View goes here." +
                "</span>";

            items.Add(item1);

            return items;
        }

        // Create a report by using the template 
        // that is specified in the item parameter.
        public override void CreateTemplateItem(TemplateItem item)
        {
            if (item.TemplateId == MyReportViewDocument.MyReportViewDocumentTypeId)
            {
                AddToWorkspace(CreateMyReportViewDocument());
            }
            else
            {
                GeneralUtilities.ShowMessageBox("Template not supported.");
            }
        }

        private static void AddToWorkspace(ReportView reportView)
        {
            if (null != reportView)
            {
                ScorecardModel.GetInstance().ReportViewsInWorkspace.Add(reportView);
                
                MainForm.GetInstance().
                    OpenWorkspaceItem
                    (typeof(ReportView), ReportViewsWorkspaceItemFactory.ReportViewsGuid, reportView.Guid, true);

                ScorecardModel.GetInstance().
                    FireFirstClassElementChanged
                    (ScorecardModel.InternalWorkspaceItemUpdate, ScorecardModel.GetInstance().GetElement(reportView.Guid) as FirstClassElement);
            }
        }

        private static void EnsureElementIsOpenedInWorkspace(object sender, TabbedSelectElementWizardPage.GuidSelectionEventArgs e)
        {
            if (e.Guid != Guid.Empty && ScorecardModel.GetInstance().DataSourcesInWorkspace != null)
            {
                if (!ScorecardModel.GetInstance().DataSourcesInWorkspace.Contains(e.Guid))
                {
                    MainForm.GetInstance().OpenWorkspaceItem(typeof(DataSource), DataSourcesWorkspaceItemFactory.DataSourcesGuid, e.Guid, false);
                }
            }
        }
        
        // Create a MyReportViewDocument instance that is 
        // wrapped by a ReportView instance.
        private static ReportView CreateMyReportViewDocument()
        {

            // This example does not have a wizard, so just 
            // create an empty report view.
            MyReportViewDocument myReportViewDocument = new MyReportViewDocument();
            myReportViewDocument.MyCustomData =
                "The MyReportViewTemplateFactory.CreateMyReportViewDocument() method chose not " +
                "to insert any data, except for this message.";

            XmlSerializer serializer = new XmlSerializer(typeof(MyReportViewDocument));
            StringBuilder stringBuilder = new StringBuilder();
            StringWriter stringWriter = new StringWriter(stringBuilder);
            serializer.Serialize(stringWriter, myReportViewDocument);
            string documentXml = stringBuilder.ToString().Normalize();
            stringWriter.Close();

            ReportView reportView = new ReportView();
            reportView.CustomData = documentXml;
            reportView.Guid = Guid.NewGuid();
            reportView.TypeName = MyReportViewFactory.MyReportViewFactoryReportName;
            reportView.InitBeginPoints();
            reportView.EndPoints = new EndPointCollection();
            reportView.EndPoints.Add(new EndPoint("PageUniqueName", "Page"));

            // If MyReportView had a wizard, the following code
            // would show the wizard form, use the form to set 
            // the state of reportView, and then dispose of 
            // the wizard form.
            //MyWizardForm form = new MyWizardForm();
            //Application.DoEvents();
            //form.Start(MainForm.GetInstance());
            //reportView = progressPage.ReportView;
            //if (null != reportView)
            //    createElementPage.SetElement(reportView);
            //form.Dispose();

            return reportView;
        }
    }
}

Implementing MyReportViewDocument

The following code example creates a data carrier class that stores user-defined data for each MyReportView report that the user creates. The MyReportViewDocument class supports this specific example and may not apply to your extension. Notice that this class is used by both Dashboard Designer and the server. Its contents are serialized to XML and stored as part of the report view information. The server loads this class from the stored XML and uses the report viewer extension to render the view.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

using Microsoft.PerformancePoint.Scorecards;

namespace MyReportViewPluginClient
{
    public class MyReportViewDocument
    {
        public const string MyReportViewDocumentTypeId = "MyReportViewDocumentTypeId";

        private string myCustomData = null;

        public string MyCustomData
        {
            get { return this.myCustomData; }
            set { this.myCustomData = value; }
        }

        public MyReportViewDocument()
        {
        }
    }
}

See Also

Tasks

How to: Install Report Designer Extensions

Concepts

How to: Create Report Viewers

Other Resources

Reports