Creating the Custom Report Item Run-time Component

New: 5 December 2005

The custom report item run-time component is implemented as a Microsoft .NET Framework component using any CLS-compliant language, and is called by the report processor at run time. The properties for the run-time component are set in the design environment with custom report item's corresponding design-time component.

If the report processing engine finds a CustomReportItem element in the report definition at execution time, the run-time component is loaded and passed a CustomReportItem object. The run-time component then uses the properties of the CustomReportItem object to create a standard ReportItem object, which is used by the report processing engine to be rendered as part of the report.

Important

The only report item type currently supported is Image.

One instance of the custom run-time component class is created during each report execution that contains any instances of the corresponding CustomReportItem type. For each matching instance of a CustomReportItem that occurs in the report, the CustomItem property of the run-time component class is set, and the Process method is called.

Important

Since the report server is multi-threaded, the class that implements ICustomReportItem should avoid using static member variables.

The custom report item will not render if an error occurs when the processing engine attempts to instantiate the run-time component. Failures that occur after the run-time component is instantiated (for example, an exception while setting the CustomItem property, calling the Process method, or returning a RenderItem property that is null or has invalid contents) will cause the entire report execution to fail.

Implementing a run-time component

The main class of a custom report item run-time component implements the ICustomReportItem interface. The ICustomReportItem interface is defined as:

namespace Microsoft.ReportingServices.ReportRendering
{
    public interface ICustomReportItem
    {
        Action Action { get; }
        CustomReportItem CustomItem { set; }
        ReportItem RenderItem { get; }

        ChangeType Process();
    }
}

The most important members of the ICustomReportItem implementation are the Process method and the RenderItem property.

Processing and returning a report item

The properties set on the custom report item using the design-time component are passed by the report processing engine to the run-time component at report execution. These properties are accessed via the CustomItem property of the ICustomReportItem implementation. Any CustomReportItem properties that are expressions are evaluated by the report processing engine before being passed to the run-time control.

At report execution time, the report processing engine calls the Process method of your run-time control. You can use the Process method to parse the data contained in the CustomItem property, render an image of the custom report item, and place the rendered image into the RenderItem property. The report processing engine will then display the image contained in the RenderItem property in the report.

The following code example shows an implementation of the Process method:

public ChangeType Process()
{
    int dpi = 96;
    int imageWidth = (int)(m_CustomReportItem.Width.ToInches() * dpi);
    int imageHeight = (int)(m_CustomReportItem.Height.ToInches() * dpi);
    Bitmap image = new Bitmap(imageWidth, imageHeight);
    Graphics graphics = Graphics.FromImage(image);
    Color backgroundColor = ((ReportColor)m_CustomReportItem.Style["BackgroundColor"]).ToColor();
    if (backgroundColor == Color.Transparent)
        backgroundColor = Color.White;
    graphics.Clear(backgroundColor);
    int maxX = (int)LookupCustomProperty(m_CustomReportItem.CustomProperties, "poly:MaxX", 100);
    int maxY = (int)LookupCustomProperty(m_CustomReportItem.CustomProperties, "poly:MaxY", 100);
    int minX = (int)LookupCustomProperty(m_CustomReportItem.CustomProperties, "poly:MinX", 0);
    int minY = (int)LookupCustomProperty(m_CustomReportItem.CustomProperties, "poly:MinY", 0);
    float scaleX = imageWidth / (float)(maxX - minX);
    float scaleY = imageHeight / (float)(maxY - minY);
    string proportional = 
(string)LookupCustomProperty(m_CustomReportItem.CustomProperties, 
"poly:Proportional", bool.FalseString);
    if ((string)proportional == bool.TrueString)
    {
        if (scaleX > scaleY)
            scaleX = scaleY;
        else
            scaleY = scaleX;
    }
    string transString =
 (string)LookupCustomProperty(m_CustomReportItem.CustomProperties,
 "poly:Translucent", "Opaque");
    int translucency = 255;
    switch (transString)
    {
        case "Opaque": translucency = 255; break;
        case "Translucent": translucency = 128; break;
        case "Transparent": translucency = 32; break;
    }
    DataMemberCollection shapes =
 m_CustomReportItem.CustomData.DataRowGroupings[0];
    m_ImageMap = new ImageMapAreasCollection();
    int row = 0;
    for (int i = 0; i < shapes.Count; i++)
    {
        DataMember shape = shapes[i];
        string colorname = (string)LookupCustomProperty(shape.CustomProperties, "poly:Color",
 "Black");
        ReportColor rptColor = new ReportColor(colorname);
        Color color = Color.FromArgb(translucency, rptColor.ToColor());
        Brush brush = new SolidBrush(color);
        DataMemberCollection points = shape.Children[0];
        string hyperlink = (string)LookupCustomProperty(shape.CustomProperties, "poly:Hyperlink",
 "");
        ImageMapArea imageMapArea = new ImageMapArea();
        float[] coordinates = new float[points.Count * 2];
        Point[] drawpoints;
        drawpoints = new Point[points.Count];
        for (int j = 0; j < points.Count; j++)
        {
            DataCell point = m_CustomReportItem.CustomData.DataCells[row, 0];
            int x = 0;
            int y = 0;
            for (int val = 0; val < point.DataValues.Count; val++)
            {
                string name = point.DataValues[val].Name;
                object value = point.DataValues[val].Value;
                int intvalue = 0;
                if (value.GetType() == typeof(int))
                {
                    intvalue = (int)value;
                }
                else if (value.GetType() == typeof(double))
                {
                    intvalue = (int)((double)value);
                }
                if (name == "X")
                    x = (int)((intvalue - minX) * scaleX);
                else if (name == "Y")
                    y = (int)((intvalue - minY) * scaleY);
            }
            drawpoints[j] = new Point(x, y);
            coordinates[j * 2] = 100 * x / imageWidth;
            coordinates[j * 2 + 1] = 100 * y / imageHeight;
            row = row + 1;
        }
        if (hyperlink != "")
        {
            imageMapArea.SetCoordinates(ImageMapArea.ImageMapAreaShape.Polygon, 
coordinates);
            Action action = new Action();
            action.SetHyperlinkAction(hyperlink);
            if (imageMapArea.ActionInfo == null)
                imageMapArea.ActionInfo = new ActionInfo();
            if (imageMapArea.ActionInfo.Actions == null)
                imageMapArea.ActionInfo.Actions = new ActionCollection();
            imageMapArea.ActionInfo.Actions.Add(action);
            m_ImageMap.Add(imageMapArea);
        }
        graphics.FillPolygon(brush, drawpoints);
    }
    m_PolygonImage = new Microsoft.ReportingServices.ReportRendering.Image(
   m_CustomReportItem.Name, m_CustomReportItem.ID);
    System.IO.MemoryStream stream = new System.IO.MemoryStream();
    image.Save(stream, ImageFormat.Bmp);
    m_PolygonImage.ImageData = new byte[stream.Length];
    stream.Seek(0, System.IO.SeekOrigin.Begin);
    stream.Read(m_PolygonImage.ImageData, 0, (int)stream.Length);
    
    m_PolygonImage.MIMEType = "image/bmp";
    
    if (m_ImageMap.Count > 0)
        m_PolygonImage.ImageMap = m_ImageMap;

   return ChangeType.None;
}

RenderItem property restrictions

If the custom report item in the report is placed in the page header or footer or in a detail group, or it has a RepeatWith property defined, the RenderItem may not be a data region.

All custom report items must have identical shared property values as the first instance of the custom control, such as name, position, size, and shared style properties. Non-shared property values may vary per instance. The UniqueName property must be unique across all instances of the same custom report item.

The following properties of CustomReportItem will override the corresponding properties of RenderItem: Top, Left, Hidden, Bookmark, and Label.

See Also

Concepts

Custom Report Item Architecture
Creating the Custom Report Item Design-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