Как правильно высвободить ресурсы после просмотра отчета?

отредактировано 17:40 Раздел: FastReport .NET
Здравствуйте!

Подскажите как правильно высвободить ресурсы после показа отчета?

Пример

Report rpt = new Report();
rpt.Load("Report.frx");
rpt.Show(false); // - тут false, для того, чтобы не ждать "ручного" закрытия окна превью.

и вот тут теперь вопрос как быть?
rpt.Dispose()? - не то

Т.е. как закрыть превью окно и уничтожить объект rpt?

После этого, программа продолжает работать дальше и объект класса Report будет создан заново.

Суть данной задумки в том, чтобы показывать определенные отчеты через определнные интервалы времени полностью в автоматическом режиме длительное время.

Комментарии

  • отредактировано 17:40
    Здравствуйте,

    Попробуйте так:
    rpt.Preview.FindForm().Close();
    rpt.Dispose();
  • отредактировано 17:40
    AlexTZ написал: »
    Здравствуйте,

    Попробуйте так:
    rpt.Preview.FindForm().Close();
    rpt.Dispose();

    Вот так, форма закрывается, нопамять все равно идет вверх.

    А вот если вот так:

    rpt.Preview.FindForm().Close();
    rpt.Dispose();
    rpt = null
    GC.Collect();

    Тогда нормально получается.

    Теперь немного другая ситуация.
    А как сделать чтоб сама форма Preview оставалась всегда открытой, но в неё подгружались разные отчеты?
    Пробовал так: (код не рабочий, просто пример направления мысли)
    class program
    {
    private Report rpt = new Report()
    System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();

    private void Form1_Load(object sender, EventArgs e)
    {
    tmr.Interval = 10000;
    tmr.Tick += new EventHandler(tmr_Tick);
    tmr.Start();
    }

    void tmr_Tick(object sender, EventArgs e)
    {
    tmr.Stop();
    //тут делам показ разных отчетов. в данном примере пока 1
    rep.Load("report.frx");
    //пробовал вместо rep.Load использовать rep.Preview.Load();, но там какой то формат файла должен быть другой...

    rep.Show(rep.Preview.FindForm()); // вот на этом этапе каждые 10 сек (работа таймера) происходит захват памяти.

    tmr.Start();
    }
    }

    как сделать так, чтобы и отчет отобразился в этом же Preview окне и окно не закрывалось и русурсы не тратились?
  • отредактировано 17:40
    Я доработаю код, чтобы можно было делать rep.Show(false) для уже открытой формы превью. Сейчас выдается исключение.
    Ресурсы освободятся после отработки GC.
  • отредактировано 17:40
    AlexTZ написал: »
    Я доработаю код, чтобы можно было делать rep.Show(false) для уже открытой формы превью. Сейчас выдается исключение.
    Ресурсы освободятся после отработки GC.

    Тут вот в чем проблема.
    Как бы немного не стандартное использование отчетности.

    По сути, Preview с кучей подгружаемых отчетов по времени это есть слайды. В этом ключе и предполагается использовать FastReport.
    Но проблема в том, что GC.Collect вызывать нельзя для rep. Так как он будет работать постоянно.... сутками, подгружая в Preview разнгые отчеты и отображая их по циклу.

    Вот. Так что как то в rep.Show(false) надо придумать без захвата памяти ещё. Так как сейчас при каждом подгружении отчета захватывается память..следвоательно минут 15 поработало все это и памяти нет (с 10 секундным интервалом показа).
  • отредактировано 17:40
    Дело в том, что большинство отчетов при выполнении компилируются в сборку. Эта сборка загружается в текущий AppDomain (и выгрузке не подлежит). Таким образом, каждое выполнение отчета съедает примерно 50кб. Если программа будет работать сутками, этот момент надо учитывать. Посмотрите решение в следующем топике:
    http://www.fast-report.com/en/forum/index.php?showtopic=6727
  • отредактировано May 2010
    Я или что то там недопонял, или просто не правиьлно делаю, но вот после того как AppDomain первый раз выгрузится и создастся новый, то при приложение поностью закрывается....

    Не понятно почему.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using FastReport;
    using System.Threading;
    using FastReport.Utils;
    
    namespace Test
    {
        public partial class Form1 : Form
        {
            int reportnumber = 2;
            int domainTTL = 0;
            AppDomain appDomain = null;
            AppDomainSetup appDomainSetup = new AppDomainSetup();
                  
            System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
           
            
    
            public Form1()
            {
                InitializeComponent();
            }
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
                tmr.Interval = 5000;
                tmr.Tick += new EventHandler(tmr_Tick);
                tmr.Start();
               
                appDomainSetup.ShadowCopyFiles = "false";
                appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
                appDomain = AppDomain.CreateDomain("new domain", AppDomain.CurrentDomain.Evidence, appDomainSetup);
            }
    
    
            void tmr_Tick(object sender, EventArgs e)
            {
                tmr.Stop();
    
                Worker worker = (Worker)appDomain.CreateInstanceAndUnwrap(this.GetType().Assembly.FullName, typeof(Worker).FullName);
                if (reportnumber == 0) reportnumber = 2;
                switch (reportnumber)
                {
    
                    case 1:
                        {
                            worker.Print(".\\Reports\\Test2.frx");
                            reportnumber--;
                        }
    
                        break;
    
                    case 2:
                        {
                            worker.Print(".\\Reports\\Test3.frx");
                            reportnumber--;
                        }
    
                        break;
                }
    
                if (domainTTL > 5)
                {
                    AppDomain.Unload(appDomain);
                    appDomain = null;
    
    
                    AppDomainSetup appDomainSetup = new AppDomainSetup();
                    appDomainSetup.ShadowCopyFiles = "false";
                    appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
                    appDomain = AppDomain.CreateDomain("new domain", AppDomain.CurrentDomain.Evidence, appDomainSetup);
    
                    worker = (Worker)appDomain.CreateInstanceAndUnwrap(this.GetType().Assembly.FullName, typeof(Worker).FullName);
                    if (reportnumber == 0) reportnumber = 2;
                    switch (reportnumber)
                    {
    
                        case 1:
                            {
                                worker.Print(".\\Reports\\Test2.frx");
                                reportnumber--;
                            }
    
                            break;
    
                        case 2:
                            {
                                worker.Print(".\\Reports\\Test3.frx");
                                reportnumber--;
                            }
    
                            break;
                    }
    
                    
                    domainTTL = 0;
                  
                }
                domainTTL++;
    
    
                
                tmr.Start();
      GC.Collect();
            }
            
        }
    
        
    
        public class Worker : MarshalByRefObject
        {
            public void Print(string path)
            {
                using (Report report = new Report())
                
                {
                    report.Load(path);
                    Config.ReportSettings.ShowProgress = false;
                    report.Show(false);
                }
            }
        }
    
    
    }
    
  • отредактировано 17:40
    Боюсь, что appdomain в этом случае не подходит.
    Другой способ избежать компиляции отчета (и расхода памяти) - сохранить отчет в виде файла .cs и добавить его в проект. В дизайнере отчета выберите пункт "Файл|Сохранить как...", и выберите тип файла - "Файл C#" или "Файл VB.Net" (это зависит от того, какой язык выбран в самом отчете). С отчетом работать можно так:

    SimpleListReport report = new SimpleListReport();
    report.RegisterData(...);
    report.Show();
  • отредактировано 17:40
    К сожалению и в таком варианте "жор" памяти продолжается (

    Если бы возможно было отдельно выводить окно Preveiw, в нем уже просто показывать разные отчеты, тогда было бы проще, но судя по всему реализовать такое не представляется возможным в текущем коде FR?

    Возможно ли пойти другим путем? Ну скажем делается 1 отчет, на разных листах которого располагается нужные отчетные данные.
    И по таймеру этот отчет листается по циклу?
    Но! Тут необходимо как то так сделать, чтобы в момент когда открывается последующий лист, данные подгружались заново, т.е. чтобы при изменении данных в базе, данные в отчете так же бы менялись. Сейчас работа с БД идет на стадии формирования отчета перед показом как я понял. А возможно ли ещё как то сделать запрос при перелистывании?

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using FastReport;
    using System.Threading;
    using FastReport.Utils;
    
    namespace Test
    {
        public partial class Form1 : Form
        {
            int reportnumber = 2;
          
            Test2 rep = null;
            Test3 rep2 = null;
    
            System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
            System.Windows.Forms.Timer tmr1 = new System.Windows.Forms.Timer();
            
    
            public Form1()
            {
                InitializeComponent();
            }
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
                tmr.Interval = 5000;
                tmr1.Interval = 5000;
                tmr.Tick += new EventHandler(tmr_Tick);
                tmr1.Tick += new EventHandler(tmr1_Tick);
                tmr.Start();
    
            }
    
            void tmr1_Tick(object sender, EventArgs e)
            {
                tmr1.Stop();
    
                tmr.Start();
                
            }
    
    
            void tmr_Tick(object sender, EventArgs e)
            {
                tmr.Stop();
    
                //Worker worker = (Worker)appDomain.CreateInstanceAndUnwrap(this.GetType().Assembly.FullName, typeof(Worker).FullName);// as Worker;
                if (reportnumber == 0) reportnumber = 2;
                switch (reportnumber)
                {
    
                    case 1:
                        {
                            if (rep!=null)
                            {
                                if (rep.Preview != null)
                                {
                                    rep.Preview.FindForm().Close();
                                    rep.Dispose();
                                    rep = null;
                                    GC.Collect();
                                }
                                else
                                {
                                    rep.Dispose();
                                    rep = null;
                                    GC.Collect();
                                
                                }
                               
                            }
                            rep = new Test2();
                            rep.Show(false);
                            tmr1.Start();
                            reportnumber--;
                        }
    
                        break;
    
                    case 2:
                        {
                            if (rep2!=null)
                            {
                                if (rep2.Preview != null)
                                {
                                    rep2.Preview.FindForm().Close();
                                    rep2.Dispose();
                                    rep2 = null;
                                    GC.Collect();
                                }
                                else 
                                
                                {
    
                                    rep2.Dispose();
                                    rep2 = null;
                                    GC.Collect();
                                
                                }
                               
                            }
                            rep2 = new Test3();
                            rep2.Show(false);
                            tmr1.Start();
                            reportnumber--;
                        }
    
                        break;
                }
    
                GC.Collect();
            }
            
        }
    
    }
    
  • отредактировано 17:40
    В общем нашлось решение не совсем прямое )

    Делается 1 файл с кучей отчетных листов и листы меняются по таймеру 1, а по таймеру 2 отчет перегружается (т.о. данные обновляются), и вот так как бы все работает нормально и память не расходуется.

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.