Render отчёта в отдельном потоке
Render отчёта в отдельном потоке
Отчёты рендерятся через BackgroundWorker без отображения процесса report.Render(false). Используется собственная реализация для отображения процесса формирования отчёта, с таймером и т.д. Все хорошо, отчёты строятся в отдельном потоке и не блокируют работу в приложении.
Но если в отчёте есть страница StiForm, где необходимо выбрать параметры для построения отчёта. После того, как появляется форма и выбираются все параметры, нажимается кнопка "Построить", приложение блокируется, пока отчёт не построится.
Когда есть форма StiForm также в DoWork используется BeginInvoke для report.Render, иначе будет ошибка "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления не из того потока, в котором он был создан." Это только при условии наличия формы в отчете.
Как можно это исправить?
Но если в отчёте есть страница StiForm, где необходимо выбрать параметры для построения отчёта. После того, как появляется форма и выбираются все параметры, нажимается кнопка "Построить", приложение блокируется, пока отчёт не построится.
Когда есть форма StiForm также в DoWork используется BeginInvoke для report.Render, иначе будет ошибка "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления не из того потока, в котором он был создан." Это только при условии наличия формы в отчете.
Как можно это исправить?
Re: Render отчёта в отдельном потоке
День добрый!
Внесу свои два цента.
Мы в своё время просто сделали форму отчёта, где есть BackgroundWorker, со всеми методами, которые вы назвали,
а также форма, на которой есть необходимые компоненты (в нашем случае DevExpress), - эта форма и есть необходимые параметры для отчёта.
В сам отчёт мы их не передаём, они попадают в OracleDataAdapter, где прописана stored procedure с binding-переменными, - вот эта процедура и крутится в DoWork().
После выполнения этой процедуры, сразу же (в DoWork()) выполняется .Render(false) и никаких проблем.
Более того, мы тоже используем StiForm, и там иногда рисуем компоненты, но простые, типа введите номер сертификата, количество коробов или что-то, что вводят на складе, т.е. данные, которых нет в базе.
Проблем нет и при этом, даже без BeginInvoke(). Но если используем форму StiForm, то если пользователь уйдёт с формы (OnLeaveForm), то она куда-то пропадает (видимо в Z-дереве) визуально и всё, приходится закрывать отчёт. Никаких Exception и каких-то ошибок мы не наблюдали.
Приложение большое, серьёзное, MDI-интерфейс, каждая форма в своём треде (thread).
Внесу свои два цента.
Мы в своё время просто сделали форму отчёта, где есть BackgroundWorker, со всеми методами, которые вы назвали,
а также форма, на которой есть необходимые компоненты (в нашем случае DevExpress), - эта форма и есть необходимые параметры для отчёта.
В сам отчёт мы их не передаём, они попадают в OracleDataAdapter, где прописана stored procedure с binding-переменными, - вот эта процедура и крутится в DoWork().
После выполнения этой процедуры, сразу же (в DoWork()) выполняется .Render(false) и никаких проблем.
Более того, мы тоже используем StiForm, и там иногда рисуем компоненты, но простые, типа введите номер сертификата, количество коробов или что-то, что вводят на складе, т.е. данные, которых нет в базе.
Проблем нет и при этом, даже без BeginInvoke(). Но если используем форму StiForm, то если пользователь уйдёт с формы (OnLeaveForm), то она куда-то пропадает (видимо в Z-дереве) визуально и всё, приходится закрывать отчёт. Никаких Exception и каких-то ошибок мы не наблюдали.
Приложение большое, серьёзное, MDI-интерфейс, каждая форма в своём треде (thread).
Re: Render отчёта в отдельном потоке
У нас тоже большое MDI-приложение с использованием MEF. Для отображения отчётов также используется отдельная форма. У нас есть разного типа отчёты, где-то мы используем StiForm, а где возможностей не хватает, собственные формы с большими входными параметрами и списками.
Вроде пока тестирую решение, со StiForm все хорошо сейчас.
Вопрос, а есть ли события, когда StiForm появляется или закрывается?
Вроде пока тестирую решение, со StiForm все хорошо сейчас.
Вопрос, а есть ли события, когда StiForm появляется или закрывается?
Re: Render отчёта в отдельном потоке
У нас примерно так же. Отчёты тоже разного типа, наследуем от разного типа форм.
Функционала, разумеется недостаточно было изначально, т.к. очень сложные "хотелки" пользователей, поэтому только собственные кастомные формы.
Есть такое. Там два события: LoadForm и ClosedForm в самой StiForm.
Мы иногда в коде использовали не в отчёте, а прямо из кода наших форм примерно так:
Функционала, разумеется недостаточно было изначально, т.к. очень сложные "хотелки" пользователей, поэтому только собственные кастомные формы.
Код: Выделить всё
Вопрос, а есть ли события, когда 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 отчёта в отдельном потоке
Спасибо, вышло, как хотел.
Использовал:
Использовал:
Код: Выделить всё
report.Pages.OfType<StiForm>().FirstOrDefault()
Re: Render отчёта в отдельном потоке
Здравствуйте.
Леонид спасибо за помощь.
В нашем продукте можно добавить простые формы с некоторыми событиями и обработчиками.
Если у вас стоит более сложная задача, то иногда лучше создавать свою форму.
Спасибо.
Леонид спасибо за помощь.
В нашем продукте можно добавить простые формы с некоторыми событиями и обработчиками.
Если у вас стоит более сложная задача, то иногда лучше создавать свою форму.
Спасибо.
Re: Render отчёта в отдельном потоке
Иногда возникает ошибка:
Код: Выделить всё
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 отчёта в отдельном потоке
У нас на практике только OutOfMemory на больших отчётах возникает, но таких ошибок не было.
Вы уверены, что в отчёте, который вы рендерите у вас нигде не меняется какая-либо коллекция, типа List<> и пр.?
Вы уверены, что в отчёте, который вы рендерите у вас нигде не меняется какая-либо коллекция, типа List<> и пр.?
Re: Render отчёта в отдельном потоке
Ничего нигде не меняется.
Re: Render отчёта в отдельном потоке
Здравствуйте.
Ошибка возникает в методе StiPostProcessProviderV2.PostProcessPages(StiPagesCollection pages).
Из циклов в этом методе только перебор страниц отчета foreach (StiPage page in pages), т.е. похоже что изменяется коллекция страниц.
Вы уверены, что больше ничего не меняет отчет?
Включен ли в отчёте режим кэширования?
Спасибо.
Ошибка возникает в методе StiPostProcessProviderV2.PostProcessPages(StiPagesCollection pages).
Из циклов в этом методе только перебор страниц отчета foreach (StiPage page in pages), т.е. похоже что изменяется коллекция страниц.
Вы уверены, что больше ничего не меняет отчет?
Включен ли в отчёте режим кэширования?
Спасибо.