Страница 1 из 2
Render отчёта в отдельном потоке
Добавлено: 06 сен 2017, 11:33
t0pdevice
Отчёты рендерятся через BackgroundWorker без отображения процесса report.Render(false). Используется собственная реализация для отображения процесса формирования отчёта, с таймером и т.д. Все хорошо, отчёты строятся в отдельном потоке и не блокируют работу в приложении.
Но если в отчёте есть страница StiForm, где необходимо выбрать параметры для построения отчёта. После того, как появляется форма и выбираются все параметры, нажимается кнопка "Построить", приложение блокируется, пока отчёт не построится.
Когда есть форма StiForm также в DoWork используется BeginInvoke для report.Render, иначе будет ошибка "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления не из того потока, в котором он был создан." Это только при условии наличия формы в отчете.
Как можно это исправить?
Re: Render отчёта в отдельном потоке
Добавлено: 07 сен 2017, 09:49
Леонид
День добрый!
Внесу свои два цента.
Мы в своё время просто сделали форму отчёта, где есть BackgroundWorker, со всеми методами, которые вы назвали,
а также форма, на которой есть необходимые компоненты (в нашем случае DevExpress), - эта форма и есть необходимые параметры для отчёта.
В сам отчёт мы их не передаём, они попадают в OracleDataAdapter, где прописана stored procedure с binding-переменными, - вот эта процедура и крутится в DoWork().
После выполнения этой процедуры, сразу же (в DoWork()) выполняется .Render(false) и никаких проблем.
Более того, мы тоже используем StiForm, и там иногда рисуем компоненты, но простые, типа введите номер сертификата, количество коробов или что-то, что вводят на складе, т.е. данные, которых нет в базе.
Проблем нет и при этом, даже без BeginInvoke(). Но если используем форму StiForm, то если пользователь уйдёт с формы (OnLeaveForm), то она куда-то пропадает (видимо в Z-дереве) визуально и всё, приходится закрывать отчёт. Никаких Exception и каких-то ошибок мы не наблюдали.
Приложение большое, серьёзное, MDI-интерфейс, каждая форма в своём треде (thread).
Re: Render отчёта в отдельном потоке
Добавлено: 07 сен 2017, 17:08
t0pdevice
У нас тоже большое MDI-приложение с использованием MEF. Для отображения отчётов также используется отдельная форма. У нас есть разного типа отчёты, где-то мы используем StiForm, а где возможностей не хватает, собственные формы с большими входными параметрами и списками.
Вроде пока тестирую решение, со StiForm все хорошо сейчас.
Вопрос, а есть ли события, когда StiForm появляется или закрывается?
Re: Render отчёта в отдельном потоке
Добавлено: 07 сен 2017, 17:44
Леонид
У нас примерно так же. Отчёты тоже разного типа, наследуем от разного типа форм.
Функционала, разумеется недостаточно было изначально, т.к. очень сложные "хотелки" пользователей, поэтому только собственные кастомные формы.
Код: Выделить всё
Вопрос, а есть ли события, когда StiForm появляется или закрывается?
Есть такое. Там два события: LoadForm и ClosedForm в самой StiForm.
Мы иногда в коде использовали не в отчёте, а прямо из кода наших форм примерно так:
Код: Выделить всё
stiReport = new StiReport();
stiReport.Load(reportBody);
// далее так
StiForm form = stiReport.Pages["custom_form_name"]; или StiForm form = stiReport.Pages[0]; // по индексу
// или так (в общем, вы поняли)
foreach (StiPage page in stiReport.Pages)
{
reportInnerForm = (page as StiForm); // save form reference
// events
reportInnerForm.ClosedForm += new EventHandler(reportInnerForm_ClosedForm);
reportInnerForm.LoadForm += new EventHandler(ReportInnerForm_LoadForm);
}
Re: Render отчёта в отдельном потоке
Добавлено: 08 сен 2017, 14:52
t0pdevice
Спасибо, вышло, как хотел.
Использовал:
Код: Выделить всё
report.Pages.OfType<StiForm>().FirstOrDefault()
Re: Render отчёта в отдельном потоке
Добавлено: 14 сен 2017, 09:44
HighAley
Здравствуйте.
Леонид спасибо за помощь.
В нашем продукте можно добавить простые формы с некоторыми событиями и обработчиками.
Если у вас стоит более сложная задача, то иногда лучше создавать свою форму.
Спасибо.
Re: Render отчёта в отдельном потоке
Добавлено: 27 сен 2017, 10:38
t0pdevice
Иногда возникает ошибка:
Код: Выделить всё
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
at Stimulsoft.Report.Engine.StiPostProcessProviderV2.PostProcessPages(StiPagesCollection pages)
at Stimulsoft.Report.Engine.StiRenderProviderV2.Render(StiReport report, StiRenderState state)
at Stimulsoft.Report.Engine.StiReportV2Builder.RenderSingleReport(StiReport masterReport, StiRenderState renderState)
at Stimulsoft.Report.StiReport.RenderReport(StiRenderState renderState)
at Stimulsoft.Report.StiReport.Render(StiRenderState renderState, StiGuiMode guiMode)
at Stimulsoft.Report.StiReport.Render(StiRenderState renderState)
at Stimulsoft.Report.StiReport.Render(Boolean showProgress)
Re: Render отчёта в отдельном потоке
Добавлено: 27 сен 2017, 11:48
Леонид
У нас на практике только OutOfMemory на больших отчётах возникает, но таких ошибок не было.
Вы уверены, что в отчёте, который вы рендерите у вас нигде не меняется какая-либо коллекция, типа List<> и пр.?
Re: Render отчёта в отдельном потоке
Добавлено: 27 сен 2017, 16:05
t0pdevice
Ничего нигде не меняется.
Re: Render отчёта в отдельном потоке
Добавлено: 29 сен 2017, 12:39
Ivan
Здравствуйте.
Ошибка возникает в методе StiPostProcessProviderV2.PostProcessPages(StiPagesCollection pages).
Из циклов в этом методе только перебор страниц отчета foreach (StiPage page in pages), т.е. похоже что изменяется коллекция страниц.
Вы уверены, что больше ничего не меняет отчет?
Включен ли в отчёте режим кэширования?
Спасибо.