I have SAP Crystal Reports for Microsoft Visual Studio version 13.0.14.1720. I am trying to display a report in a C# Windows Forms application. The report is failing now with an ArgumentOutOfRangeException. The stack trace is below:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at CrystalDecisions.Shared.PageRender.draw_FieldObjectInstance(FieldObjectInstance fieldObject, Graphics g)
at CrystalDecisions.Shared.PageRender.draw_ReportObjectInstance(ReportObjectInstance instance, Graphics g, Rectangle clipRect)
at CrystalDecisions.Shared.PageRender.draw_SectionInstance(SectionInstance section, Graphics g, Rectangle clipRect)
at CrystalDecisions.Shared.PageRender.Render(PageObject page, Graphics g, Graphics device_g)
at CrystalDecisions.Windows.Forms.PageControl.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.UserControl.WndProc(Message& m)
at CrystalDecisions.Windows.Forms.PageControl.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
I ran this in Visual Studio 2015 and stopped execution on the error. The error is happening on this field:
Field name: #SiteError2
ObjectName: SiteError11
Size: 120x221
OffsetInSection: 5528x0
SectionKind: GroupFooter
Section: GroupFooterSection2
Looking at the report definition, this field is on a group footer. This field is grabbing the maximum value of a running total of errors. The running total evaluates every record and resets on change of the group.
If there is at least 1 error, the field is supposed to display an asterisk. Otherwise, it is blank. Therefore the Display String has the following formula:
iif(CurrentFieldValue > 0, "*", "")
If I change the definition of the Display String formula to use anything other than "" when the value is <= 0, then there is no error. For example, the following Display String, the error does not occur:
iif(CurrentFieldValue > 0, "*", "N")
The display string is the same as other columns in the same group footer that perform a running total on other columns. In fact, there are several fields on the group footer that are identical to this one.
I tried removing and recreating the field from scratch. The same error occurs.
I tried changing the report options for "Convert Database NULL Values to Default" and "Convert Other NULL Values to Default", but the error still occurs.
I also tried upgrading the report format from an older version to the newest one.
The report column definition is below. The fields on the group header are calculating the maximum of the _Error columns below. These columns are defined as integers.
<xs:element name="DRSiteAnalystSummary_Column_1_Error" type="xs:int" minOccurs="0" />
<xs:element name="DRSiteAnalystSummary_Column_2_Error" type="xs:int" minOccurs="0" />
<xs:element name="DRSiteAnalystSummary_Column_3_Error" type="xs:int" minOccurs="0" />
I ran JetBrains dotPeek on the CrystalDecisions.Shared.dll in the GAC. Decompiling the PageRender.draw_FieldObjectInstance method, I see a few array index references. This one stands out to me:
private void draw_FieldObjectInstance(FieldObjectInstance fieldObject, Graphics g)
{
...
if (fieldObject.IsFieldNumeric)
{
fieldObjectInstance = (NumericFieldObjectInstance) fieldObject;
num7 = (int) g.MeasureString(fieldObjectInstance.PrefixReserve, font, this.m_layout, stringFormat).Width;
SizeF sizeF2 = g.MeasureString(fieldObjectInstance.SuffixReserve, font, this.m_layout, stringFormat);
num8 = (int) sizeF2.Width;
sizeF2 = g.MeasureString(fieldObjectInstance.FixedLeftReserve, font, this.m_layout, stringFormat);
num9 = (int) sizeF2.Width;
sizeF1 = g.MeasureString(fieldObjectInstance.FixedRightReserve, font, this.m_layout, stringFormat);
num10 = (int) sizeF1.Width;
if (!fieldObjectInstance.AllowClipping)
{
sizeF1 = g.MeasureString((string) fieldObject.TextLines[0], font, this.m_layout, stringFormat);
if ((int) sizeF1.Width + num7 + num8 + num9 + num10 > width)
{
flag2 = true;
alignment = Alignment.LeftAlign;
int num11 = width;
sizeF1 = g.MeasureString('#'.ToString(), font, this.m_layout, stringFormat);
int num12 = (int) sizeF1.Width;
int count = num11 / num12;
**fieldObject.TextLines[0] = (object) new string('#', count);**
}
}
}
The code above appears to be assuming there is a text line. At the point the error occurs, the TextLines property has a length of 0. IsFieldNumeric is true and fieldObjectInstance.AllowClipping is false, so it looks like this code will be run and fail.
In Visual Studio, I set a breakpoint down in CrystalDecisions.Shared.PageRender.draw_ReportObjectInstance before it called into CrystalDecisions.Shared.PageRender.draw_FieldObjectInstance. I examined every field instance on the report. Every numeric object had the AllowClipping set to true except for this field.
The field was numeric (IsNumeric was true), and AllowClipping was false. That means it would hit the index reference assumption in the draw_FieldObjectInstance code I listed in my question above.
I have no explanation why this field was different. Maybe someone created it in a different version of Crystal Reports for Visual Studio. Changing the AllowClipping to true for this field bypassed the issue.
Unfortunately, the option was not visible on the Format Editor for the field. The Numeric tab was not even visible. Here is how I set the "Allow Field Clipping" option to true:
On the Common I entered the same display string as in my question and pressed OK:
iif(CurrentFieldValue > 0, "*", "")
The Numeric tab immediately disappeared. Apparently adding the display string made Crystal Reports no longer treat the field as a numeric field.
When I tested the report, the error no longer occurred.
This feels like a bug in Crystal Reports. I was not able to see or change a hidden setting for "Allow Field Clipping" on this report field, but the value of this setting was causing an error.