Как стать автором
Обновить

FastReport.NET. Строим «хитрый» отчет.

Многие слышали о FastReport, многие используют его для своих приложений. Мое первое знакомство с ним состоялось в далеком 2002 году. Delphi + FastReport, что еще нужно для создания отчетов. Скорость построения отчетов и простота проектирования. Но иногда отчет нужен не просто «выбери все из БД по определенным критериям и отобрази», а более изощренный. Например, есть несколько бендов и их нужно выводить в отчет на основании каких-то условий. В FastReport.vcl для этого была отличная возможность — OnManualBuild. Подписавшись на него в коде можно было сделать что-то типа такого:

If (x = 1)
then Report.Engine.ShowBand(TfrxBand(Page.FindObject('Header1')))
else Report.Engine.ShowBand(TfrxBand(Page.FindObject('Header2')));


Просто и удобно.

Но время не стоит на месте и вот я уже для разработки использую VS от мелкософта и C#.
FastReport не стоит на месте и выпускает FastReport Studio. И тут меня ждет разочарование, это ActiveX и о каком либо «ручном» управлении построения отчетов приходится забыть (вернее все же что-то можно сделать, но это скорее «танец с бубном»). Но FastReport помнит о нас :) и выпускает FastReport.NET. Я тут же «хватаюсь» за него и обнаруживаю, что про ManualBuild команда разработчиков забыла. Немного переписки с тех.поддержкой и это событие реализовано. Теперь мы можем делать все, что могли в Delphi и даже больше.

На небольшом примере я хочу показать простоту построения отчета.
Предположим у нас есть в отчете несколько пар бендов (шапка и данные), и мы хотим в каком-то произвольном порядке вывести все это в отчет.

Для начала создадим несколько вспомогательных классов.

Класс, который будет содержать имя параметра и значение (аналог FieldName и FieldValue ).

#region PrintStruct

public class PrintStruct
{
public string NameParam
{
get;
set;
}

public string ValueParam
{
get;
set;
}

public PrintStruct()
{

}

public PrintStruct(string nameParam, string valueParam)
{
this.NameParam = nameParam;
this.ValueParam = valueParam;
}
}

#endregion

#region PrintStructList

public class PrintStructList : List {
public PrintStructList()
{
}

public PrintStructList(int capacity) : base(capacity)
{
}

public PrintStructList(IEnumerable collection) : base(collection)
{
}
}

#endregion


Класс, который будет содержать информацию о бенде (имя, тип «шапка или данные», список значений).

#region PrintBand

public class PrintBand
{
public bool IsHeader
{
get;
set;
}

public string NameBand
{
get;
set;
}

public PrintStructList Values
{
get;
set;
}

public PrintBand()
{

}

public PrintBand(bool isHeader, string nameBand, PrintStructList values)
{
this.IsHeader = isHeader;
this.NameBand = nameBand;
this.Values = values;
}
}

#endregion

#region PrintBandList

public class PrintBandList : List {
public PrintBandList()
{
}

public PrintBandList(int capacity) : base(capacity)
{
}

public PrintBandList(IEnumerable collection) : base(collection)
{
}
}

#endregion


И, наконец, основной класс, к которому и будет обращаться FastReport.

#region PrintInfo

public class PrintInfo
{
public static PrintBandList GetInfoForPrint()
{
var res = new PrintBandList();

// Добавляем Шапку
var printBand = new PrintBand
{
IsHeader = true,
NameBand = "Header1",
Values = new PrintStructList
{
new PrintStruct("Col1", "№ "),
new PrintStruct("Col2", "Знач 1"),
new PrintStruct("Col3", " Знач 2")
}
};
res.Add(printBand);

// Добавляем данные
printBand = new PrintBand
{
IsHeader = false,
NameBand = "Data1",
Values = new PrintStructList
{
new PrintStruct("Par1", "1 "),
new PrintStruct("Par2", "111"),
new PrintStruct("Par3", "111111")
}
};
res.Add(printBand);

printBand = new PrintBand
{
IsHeader = false,
NameBand = "Data1",
Values = new PrintStructList
{
new PrintStruct("Par1", "2 "),
new PrintStruct("Par2", "222"),
new PrintStruct("Par3", "222222")
}
};
res.Add(printBand);

// Добавляем Шапку

printBand = new PrintBand
{
IsHeader = true,
NameBand = "Header2",
Values = new PrintStructList
{
new PrintStruct("Col1", "№ "),
new PrintStruct("Col2", "Знач 1"),
new PrintStruct("Col3", " Знач 2"),
new PrintStruct("Col4", " Знач 3")

}
};
res.Add(printBand);

// Добавляем данные

printBand = new PrintBand
{
IsHeader = false,
NameBand = "Data2",
Values = new PrintStructList
{
new PrintStruct("Par1", "1 "),
new PrintStruct("Par2", "11"),
new PrintStruct("Par3", "111"),
new PrintStruct("Par4", "111111")
}
};

res.Add(printBand);

// повторяем сколько нам нужно :)

return res;
}
}

#endregion


Все, данные у нас есть, осталось их только вызвать в отчете и отобразить.
Для это в коде отчета пишем следующее:

private void Page1_ManualBuild(object sender, EventArgs e)
{
PrintBandList bandlist = ClassTest.PrintInfo.GetInfoForPrint();

for (int i = 0; i < bandlist.Count; i++)
{
for (int j = 0; j < bandlist[i].Values.Count; j++)
{
Report.SetParameterValue(bandlist[i].Values[j].NameParam, bandlist[i].Values[j].ValueParam);
}

if (bandlist[i].IsHeader)
{
DataHeaderBand band = Report.FindObject(bandlist[i].NameBand) as DataHeaderBand;
Engine.ShowBand(band);
}
else
{
DataBand band = Report.FindObject(bandlist[i].NameBand) as DataBand;
Engine.ShowBand(band);
}
}
}


Вот все. Только осталось запомнить несколько моментов: чтобы использовать свой класс нужно в дизайнере добавить ссылку (reference) на свою dll, управлять выводом можно только для DataHeaderBand и DataBand (шапки и подвалы отчета и страниц выводятся всегда).
Надеюсь эта небольшая статейка поможет упростить процесс создания «нелинейных» отчетов.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.