ObjectDisposedException след затваряне на приложението на Timer

Работя върху мрежово приложение. Първо исках да накарам DataGridView да опреснява данните си всяка секунда. Моята реализация:

public partial class Form1 : Form
{
    BindingList<Wifi> Networks = new BindingList<Wifi>();
    System.Timers.Timer NetworksRefreshThread;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        NetshScanner netshScanner = new NetshScanner();
        NetworksRefreshThread = new System.Timers.Timer(1000);

        dataGridView1.DataSource = Networks;
        NetworksRefreshThread.Elapsed += delegate
        {         
            BindingList<Wifi> tmp = new BindingList<Wifi>(netshScanner.StartAndParseOutput());

                this.Invoke((MethodInvoker)delegate
                {
                    Networks.Clear();
                    foreach (Wifi net in tmp)
                    {
                        Networks.Add(net);
                    }

                });

        };
    }

След като затворя формуляра, получавам ObjectDisposedException вътре в this.Invoke. Някакъв съвет?


person ContentPenalty    schedule 08.08.2014    source източник
comment
Спирате ли таймера да работи при затваряне на формуляра?   -  person DavidG    schedule 08.08.2014
comment
Добавих NetworksRefreshThread.Close() в събитието Form1_FormClosing, но все пак същото. Бих добавил, че това изключение не винаги се появява.   -  person ContentPenalty    schedule 08.08.2014
comment
Това ще помогне   -  person Sriram Sakthivel    schedule 08.08.2014


Отговори (1)


Това, което вероятно се случва, е, че таймерът е задействан и в момента е зает с обновяване на вашия DataGridView. Това се случва в отделна тема. След това, когато затваряте формуляра, GUI нишката започва да унищожава своите обекти. След това таймерът приключва с извличането на новите си данни, но няма останал обект, който да ги постави.

За да разрешите това. Добавете булево значение към вашия клас, наречено „Актуализиране“ или нещо подобно. След това задайте стойността му, когато актуализирате, на true.

NetworksRefreshThread.Elapsed += delegate
{    
    Updating = true;     
    BindingList<Wifi> tmp = new BindingList<Wifi>(netshScanner.StartAndParseOutput());

        this.Invoke((MethodInvoker)delegate
        {
            Networks.Clear();
            foreach (Wifi net in tmp)
            {
                Networks.Add(net);
            }

        });
    Updating = false;
};

Сега създайте нов метод, който свързвате със събитието за затваряне на формуляр. В този метод направете Thread.Sleep(), докато таймерът се актуализира:

while (Updating) Thread.Sleep(100);
person Bart van der Drift    schedule 08.08.2014
comment
Но нещата за актуализиране се извършват в нишката на GUI, затова използвах this.Invoke((MethodInvoker)delegate). Вътре в таймера получавам данните за променливата tmp и ги давам на нишката на GUI за актуализиране. - person ContentPenalty; 08.08.2014
comment
Е, вие ОПИТВАТЕ да накарате GUI нишката да го направи... но GUI нишката вече не е там, след като затворите формуляра. - person Bart van der Drift; 08.08.2014
comment
Изглежда, че това е проблемът, но когато промених кода с Update boolean, приложението замръзва, когато се появи ситуацията. - person ContentPenalty; 08.08.2014