Creating the Custom Report Item Design-Time Component

New: 5 December 2005

A custom report item design-time component is a control that can be used in the Visual Studio Report Designer environment. The custom report item design-time component provides an activated design surface that can accept drag-and-drop operations, integration with the Visual Studio property browser, and the ability to provide custom property editors.

With a custom report item design-time component, the user can place a custom report item on a report in the design environment, set custom data properties on the custom report item, and then save the custom report item as part of the report project.

The properties set using the design-time component in the development environment are serialized and de-serialized by the host design environment and then stored as elements in the Report Definition Language (RDL) file. When the report is executed by the report processor, the properties set using the design-time component are passed by the report processor to a custom report item run-time component, which renders the custom report item and passes it back to the report processor.

Note

The custom report item design-time component is implemented as a Microsoft .NET Framework component. This document will describe implementation details specific to the custom report item design-time component. For complete documentation on developing components using the .NET Framework, see "Components in Visual Studio" on msdn.microsoft.com.

Implementing a Design-Time Component

The main class of a custom report item design-time component is inherited from the Microsoft.ReportDesigner.CustomReportItemDesigner class. In addition to the standard attributes used for a .NET Framework control, your component class should define a CustomReportItem attribute. This attribute must correspond to the name of the custom report item as it is defined in the reportserver.config file. For a list of .NET Framework attributes, see Attributes in the .NET Framework SDK documentation.

The following code snippet shows attributes being applied to a custom report item design-time control:

namespace PolygonsCRI
{
    [LocalizedName("Polygons")]
    [Editor(typeof(CustomEditor), typeof(ComponentEditor))]
        [ToolboxBitmap(typeof(PolygonsDesigner),"Polygons.ico")]
        [CustomReportItem("Polygons")]

    public class PolygonsDesigner : CustomReportItemDesigner
    {
...

Initializing the Component

User-specified properties for a custom report item are passed using a Microsoft.ReportDesigner.CustomData class. Your implementation of the CustomReportItemDesigner class should override the InitializeNewComponent method to instantiate a new instance of your component's CustomData class and set it to default values.

The code snippet below shows an example of a custom report item design-time component class overriding the CustomReportItemDesigner.InitializeNewComponent method to initialize the component's CustomData class:

public override void InitializeNewComponent()
   {
      CustomData = new CustomData();
         CustomData.DataRowGroupings = new DataRowGroupings();
         // Shape grouping
         CustomData.DataRowGroupings.DataGroupings = new
            List<DataGrouping>(1);
         CustomData.DataRowGroupings.DataGroupings.Add(
            new DataGrouping());
         CustomData.DataRowGroupings.DataGroupings[0].Grouping = 
            new Grouping();
         CustomData.DataRowGroupings.DataGroupings[0].Grouping.Name = 
            Name + "_Shape";
         CustomData.DataRowGroupings.DataGroupings[0].Grouping.GroupExpressions = new GroupExpressions();
         CustomData.DataRowGroupings.DataGroupings[0].Grouping.GroupExpressions.Add(new Expression());
         // Point grouping
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings = new List<DataGrouping>(1);
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings.Add(new DataGrouping());
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings[0].Grouping = new Grouping();
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings[0].Grouping.Name = Name + "_Point";
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings[0].Grouping.GroupExpressions = new GroupExpressions();
         CustomData.DataRowGroupings.DataGroupings[0].DataGroupings[0].Grouping.GroupExpressions.Add(new Expression());
         // Static column
         CustomData.DataColumnGroupings = new DataColumnGroupings();
         CustomData.DataColumnGroupings.DataGroupings = new List<DataGrouping>(1);
         CustomData.DataColumnGroupings.DataGroupings.Add(new DataGrouping());
         CustomData.DataColumnGroupings.DataGroupings[0].Static = true;
         // Points
         CustomData.DataRows = new List<DataRow>(1);
         CustomData.DataRows.Add(new DataRow());
         CustomData.DataRows[0].Add(new DataCell());
         CustomData.DataRows[0][0].Add(new DataValue("X",""));
         CustomData.DataRows[0][0].Add(new DataValue("Y",""));
      }

Modifying Component Properties

CustomData properties can be modified in the design environment in several ways. Any properties exposed by the design-time component that are marked with the BrowsableAttribute attribute can be modified by using the Visual Studio property browser. In addition, properties can be modified by dragging and dropping items onto the custom report item's design surface, or by right-clicking on the control in the design environment and selecting Properties from the shortcut menu to display a custom properties window.

The following code example shows a Microsoft.ReportDesigner.CustomData property with the BrowsableAttribute attribute applied:

[Browsable(true), Category("Data")]
public string DataSetName
{
      get
      {
         return CustomData.DataSetName;
      }
      set
      {
         CustomData.DataSetName = value;
      }
   }

You can provide your design-time component with a custom properties editor dialog box. The custom property editor implementation should inherit from the ComponentEditor class, and instantiate an instance of a dialog box which can be used for property editing.

The following example shows an implementation of a class that inherits from ComponentEditor and displays a custom property editor dialog box:

internal sealed class CustomEditor : ComponentEditor
{
   public override bool EditComponent(
      ITypeDescriptorContext context, object component)
    {
     PolygonsDesigner designer = (PolygonsDesigner)component;
     PolygonProperties dialog = new PolygonProperties();
     dialog.m_designerComponent = designer;
     DialogResult result = dialog.ShowDialog();
     if (result == DialogResult.OK)
     {
        designer.Invalidate();
        designer.ChangeService().OnComponentChanged(designer, null, null, null);
        return true;
     }
     else
        return false;
    }
}

Your custom property editor dialog box can invoke the Report Designer Expression Editor. In the following example, the Expression Editor is invoked when the user selects the first element in the combo box:

private void EditableCombo_SelectedIndexChanged(object sender, 
    EventArgs e)
{
   ComboBox combo = (ComboBox)sender;
   if (combo.SelectedIndex == 0 && m_launchEditor)
   {
      m_launchEditor = false;
      ExpressionEditor editor = new ExpressionEditor();
      string newValue;
      newValue = (string)editor.EditValue(null, m_designerComponent.Site, m_oldComboValue);
      combo.Items[0] = newValue;
   }
}

Using Designer Verbs

A designer verb is a menu command linked to an event handler. You can add designer verbs that will appear in a component's shortcut menu when your custom report item run-time control is being used in the design environment. The list of available designer verbs is returned from your run-time component using the Verbs property in the CustomReportItemDesigner class. This property is a DesignerVerbCollection object.

The following code example shows a designer verb and an event handler being added to the DesignerVerbCollection, as well as the event handler code:

public override DesignerVerbCollection Verbs
{
    get
    {
        if (m_verbs == null)
        {
            m_verbs = new DesignerVerbCollection();
            m_verbs.Add(new DesignerVerb("Proportional Scaling", new EventHandler(OnProportionalScaling)));
         m_verbs[0].Checked = (GetCustomProperty("poly:Proportional") == bool.TrueString);
        }

        return m_verbs;
    }
}

private void OnProportionalScaling(object sender, EventArgs e)
{
   bool proportional = !
        (GetCustomProperty("poly:Proportional") == bool.TrueString);
   m_verbs[0].Checked = proportional;
   SetCustomProperty("poly:Proportional", proportional.ToString());
   ChangeService().OnComponentChanged(this, null, null, null);
   Invalidate();
}

Using Adornments

Custom report item classes can optionally implement an Microsoft.ReportDesigner.Design.Adornment class. An adornment allows the custom report item control to provide areas outside of the main rectangle of the design surface. These areas can handle user interface events, such as mouse clicks and drag-and-drop operations. The Adornment class defined in the Reporting Services Microsoft.ReportDesigner namespace is a pass-through implementation of the Adorner class found in Windows Forms. For complete documentation on the Adorner class, see Behavior Service Overview. For sample code that implements an Microsoft.ReportDesigner.Design.Adornment class, please see Custom Report Item Sample.

For more information about programming and using Windows Forms in Visual Studio, see these topics in the MSDN Library:

  • Design-Time Attributes for Components
  • Components in Visual Studio
  • Walkthrough: Creating a Windows Forms Control that Takes Advantage of Visual Studio Design-Time Features

See Also

Concepts

Custom Report Item Architecture
Creating the Custom Report Item Run-time Component
Custom Report Item Class Libraries
Deploying a Custom Report Item

Other Resources

Custom Report Item Sample

Help and Information

Getting SQL Server 2005 Assistance