Crystal Reports on the web

Looking at the huge number of links, my code snippets and samples that I've accumulated during my journey with Crystal Reports and Report Server (RAS), I've realized that something should be done with all that. So, for all who are struggling with similar problems I've faced while pursuing that elusive goal of putting Crystal Reports on the web, I will put as much information here as I can ...

Friday, June 25, 2004

Filters in document

Try this...

foreach (FilterItem fld in _reportClientDocument.DataDefinition.RecordFilter.FilterItems)
{
Trace.Write("FilterItem name: "+ fld.ComputeText());
}

Create Field object in RAS

To add field onto report, create a field object first ..


private Field ConvertFieldStringToFieldClass(string fieldString)
{
// get the period index
char period = '.';
int periodIndex = fieldString.IndexOf(period);
// parse out table and field name
string tableName = fieldString.Substring(1, periodIndex-1);
string fieldName = fieldString.Substring(periodIndex+1, fieldString.Length-(periodIndex+2));
Tables tables = _reportClientDocument.DatabaseController.Database.Tables;
int tableIndex = tables.FindByAlias(tableName);
CrystalDecisions.ReportAppServer.DataDefModel.Table table =
(CrystalDecisions.ReportAppServer.DataDefModel.Table)tables[tableIndex];

Fields fields = table.DataFields;
int fieldIndex = fields.Find(fieldName, CrFieldDisplayNameTypeEnum.crFieldDisplayNameName,
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleEnglishUS);
Field field = (Field)fields[fieldIndex];
return field;
}


Tuesday, June 22, 2004

Saving a report on the server

If you have sufficient permissions, of course, you can save a report by calling SaveAs method belonging to ReportClientDocument object:
//
// Saves report on RAS Server into adhoc folder.
// If third parameter is 1, it will overwrite exisiting report.
//

private void SaveReportOnServer(string newReportName)
{
object parentFolderPath;
parentFolderPath = "c:\\reports\\";
_reportClientDocument.SaveAs(newReportName, ref parentFolderPath , 1);
}

Richard Dudley's blog

More links...

Monday, June 21, 2004

Currently Used Database fields on the report

Similar problem is how to retrieve all fields that are used on the report:

//'---------------------------------------------------------
//
// GetCurrentlyUsedDatabaseFields
//

// ICollection
// Get all used db fields from the report.
//

//'---------------------------------------------------------
private ICollection GetCurrentlyUsedDatabaseFields()
{
SortedList sortedlist = new SortedList();
string strShortFieldName;
Fields fields = _reportClientDocument.DataDefinition.ResultFields;
foreach(Field field in fields)
{
if(field.Kind == CrFieldKindEnum.crFieldKindDBField)
{
char period = '.';
int periodIndex = field.FormulaForm.IndexOf(period);
// parse out table and field name
strShortFieldName = field.FormulaForm.Substring(periodIndex+1, field.FormulaForm.Length-(periodIndex+2));
sortedlist.Add(field.FormulaForm, strShortFieldName);
}
}
return sortedlist;
}

Friday, June 18, 2004

ArrayList, Hashtable and SortedList

I was looking for something that will allow me to databind listbox (and dropdown box later) to the data retrieved from a report; in particular, list of all database fields available, like the Field Explorer Database Fiedls list in Crystal Designer.
Initially, I've used ArrayList. That's a nice usefull collection, but problem is you can't achieve "separation of content and presentation". Both value and text for listItems are the same. You end up having something like this:



Not really user friendly, isn't it?

Ok, so I've looked at the available collections in .NET, and there is a better one called hashtable. It's a key-value collection of pair, and you can specify databinding of key and value portion.

lstAvailableDatabaseFields.DataSource = GetAvailableDatabaseFields();
lstAvailableDatabaseFields.DataTextField="value";
lstAvailableDatabaseFields.DataValueField ="key";
lstAvailableDatabaseFields.DataBind();

And, another problem arises - it's not sorted, and it's NOT sortable. To get my list of fields nicely sorted, I had to use different collection - SortedList. It's a combination of ArrayList and HashTable, so exactly suited for my purpose...
Here is the code:

public SortedList GetAvailableDatabaseFields()
{
string strShortFieldName;
SortedList sortedList = new SortedList();

Tables tables = _reportClientDocument.DatabaseController.Database.Tables;
foreach(CrystalDecisions.ReportAppServer.DataDefModel.Table table in tables)
{
foreach(Field field in table.DataFields)
{
char period = '.';
int periodIndex = field.FormulaForm.IndexOf(period);
// parse out table and field name
strShortFieldName = field.FormulaForm.Substring(periodIndex+1, field.FormulaForm.Length-(periodIndex+2));
sortedList.Add(field.FormulaForm, strShortFieldName);
}
}
return sortedList;
}

private void lstAvailableDatabaseFields_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
lstAvailableDatabaseFields.DataSource = GetAvailableDatabaseFields();
lstAvailableDatabaseFields.DataTextField = "value";
lstAvailableDatabaseFields.DataValueField ="key";
lstAvailableDatabaseFields.DataBind();
}
}



Nice, isn't it?

Tuesday, June 15, 2004

How to find whether field exists in ResultFields collection

Finally...
Assume that we have fieldString already, and reportClientDocument object:
string fieldString;
ReportClientDocument _reportClientDocument;

// fieldString value will look like 'tablename.fieldname',
// so we should split it if we want just field name
char period = '.';
int periodIndex = fieldString.IndexOf(period);

string tableName = fieldString.Substring(1, periodIndex-1);
string fieldName = fieldString.Substring(periodIndex+1, fieldString.Length-(periodIndex+2));

int fldIndex = _reportClientDocument.DataDefinition.ResultFields.Find(fieldName, CrystalDecisions.ReportAppServer.DataDefModel.CrFieldDisplayNameTypeEnum.crFieldDisplayNameName, CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleUserDefault);
if (fldIndex == -1)
{
// do something if not found
}
else
{
// do something if found... or do nothing...
}

If you want full qualified name, use crFieldDisplayNameLong instead of crFieldDisplayNameName, and full fieldString ...

Monday, June 14, 2004

Let's start