Страница 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), т.е. похоже что изменяется коллекция страниц.
Вы уверены, что больше ничего не меняет отчет?
Включен ли в отчёте режим кэширования?

Спасибо.