Сведения о вопросе

ЧОВИД

14:46, 26th August, 2020

Теги

.net   vb.net   winforms    

Не удается получить доступ к удаленному объекту - как это исправить?

Просмотров: 463   Ответов: 11

В проекте VB.NET WinForms я получаю исключение

Невозможно получить доступ к удаленному объекту

при закрытии формы. Это происходит очень редко, и я не могу воссоздать его по требованию. Стек trace выглядит следующим образом:

Cannot access a disposed object. Object name: 'dbiSchedule'.
  at System.Windows.Forms.Control.CreateHandle()
  at System.Windows.Forms.Control.get_Handle()
  at System.Windows.Forms.Control.PointToScreen(Point p)
  at Dbi.WinControl.Schedule.dbiSchedule.a(Boolean A_0)
  at Dbi.WinControl.Schedule.dbiSchedule.a(Object A_0, EventArgs A_1)
  at System.Windows.Forms.Timer.OnTick(EventArgs e)
  at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

dbiSchedule - это управление расписанием от Dbi-tech. В форме есть таймер, который обновляет расписание на экране каждые несколько минут.

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


Hej и! Спасибо за все ответы. Мы останавливаем таймер на событии FormClosing и проверяем свойство IsDisposed в компоненте расписания, прежде чем использовать его в событии Timer Tick, но это не помогает.

Это действительно раздражающая проблема, потому что если кто - то действительно придумал решение, которое сработало-я не смогу подтвердить решение, потому что я не могу воссоздать проблему вручную.



  Сведения об ответе

lourence

17:14, 14th August, 2020

Попробуйте проверить свойство IsDisposed перед доступом к элементу управления. Вы также можете проверить его на событии FormClosing, предполагая, что вы используете событие FormClosed.

Мы действительно останавливаем таймер на FormClosing событие, и мы действительно проверяем IsDisposed недвижимость по расписанию компонент перед использованием его в таймере Тиковое событие, но это не помогает.

Вызов GC.Collect перед проверкой IsDisposed может помочь, но будьте осторожны с этим. Читайте эту статью Рико Мариани "когда звонить GC.Collect()".


  Сведения об ответе

PROGA

08:03, 26th August, 2020

Похоже на проблему с потоками.
Гипотеза: возможно, у вас есть основной поток и поток таймера, обращающийся к этому элементу управления. Основной поток завершает работу-вызывая Control.Dispose(), чтобы указать, что я закончил с этим элементом управления, и я больше не буду делать никаких вызовов к этому. Однако поток таймера все еще активен - контекстный переключатель к этому потоку, где он может вызывать методы на том же элементе управления. Теперь контроль говорит, что я избавился (уже отказался от своих ресурсов) и больше не буду работать. ObjectDisposed исключение.

Как решить эту проблему : в потоке таймера перед вызовом методов / свойств элемента управления выполните проверку с помощью

if ControlObject.IsDisposed then return; // or do whatever - but don't call control methods

OR остановите поток таймера BEFORE, избавляющийся от объекта.


  Сведения об ответе

repe

09:37, 13th August, 2020

мы действительно проверяем свойство IsDisposed на компонент расписания перед его использованием в таймере тикает событие но это не так помощь.

Если я правильно понимаю, что stack trace-это не ваш таймер, а проблема в самом элементе управления - это могут быть те, кто не убирает должным образом.

Вы явно вызываете Dispose на их контроль?


  Сведения об ответе

fo_I_K

04:51, 17th August, 2020

Остановка таймера не означает, что он не будет вызван снова, в зависимости от того, когда вы остановите таймер, timer_tick все еще может стоять в очереди в цикле сообщений для формы. Что произойдет, так это то, что вы получите еще один тик, который вы, возможно, не ожидали. То, что вы можете сделать, это в вашем timer_tick, проверьте свойство Enabled вашего таймера перед выполнением метода Timer_Tick.


  Сведения об ответе

appple

21:06, 1st October, 2020

У меня была та же проблема, и я решил ее с помощью логического флага, который устанавливается, когда форма закрывается (свойство System.Timers.Timer не имеет свойства IsDisposed). Везде на форме я запускал таймер, я должен был проверить этот флаг. Если он был установлен, то не запускайте таймер. Вот в чем причина:

причина:

Я останавливался и избавлялся от таймера в виде события закрытия. Я запускал таймер в событии Timer_Elapsed(). Если бы я закрыл форму в середине события Timer_Elapsed(), таймер немедленно был бы удален событием Form_Closing(). Это произойдет до того, как событие Timer_Elapsed() завершится и, что более важно, до того, как оно попадет в эту строку кода:

_timer.Start()

Как только эта строка была выполнена, ObjectDisposedException() будет брошен с ошибкой, о которой Вы упомянули.

решение:

Private Sub myForm_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
    ' set the form closing flag so the timer doesn't fire even after the form is closed.
    _formIsClosing = True
    _timer.Stop()
    _timer.Dispose()
End Sub

Вот таймер прошедшего события:

Private Sub Timer_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timer.Elapsed
    ' Don't want the timer stepping on itself (ie. the time interval elapses before the first call is done processing)
    _timer.Stop()

    ' do work here

    ' Only start the timer if the form is open. Without this check, the timer will run even if the form is closed.
    If Not _formIsClosing Then
        _timer.Interval = _refreshInterval
        _timer.Start() ' ObjectDisposedException() is thrown here unless you check the _formIsClosing flag.
    End If
End Sub

Интересно знать, что даже если бы он бросил ObjectDisposedException при попытке запустить таймер, таймер все равно запустился бы, заставляя его работать даже тогда, когда форма была закрыта (поток остановится только тогда, когда приложение будет закрыто).


  Сведения об ответе

PIRLO

03:52, 26th August, 2020

Вы уверены, что таймер не переживает 'dbiSchedule' каким-то образом и не стреляет после того, как 'dbiSchedule' был удален?

Если это так, то вы могли бы воссоздать его более последовательно, если таймер срабатывает быстрее, что увеличивает шансы на закрытие формы так же, как таймер срабатывает.


  Сведения об ответе

darknet

10:04, 17th August, 2020

Еще одним местом, где вы можете остановить таймер, является событие FormClosing - это происходит до того, как форма фактически закрыта, поэтому это хорошее место для остановки вещей, прежде чем они могут получить доступ к недоступным ресурсам.


  Сведения об ответе

screen

11:25, 26th August, 2020

Мое решение было поставить попробовать поймать, & работает нормально

пробовать {
this.Invoke(new EventHandler(DoUpdate)); }
ловить { }


  Сведения об ответе

repe

18:18, 1st August, 2020

Если это происходит спорадически, то я предполагаю, что это как-то связано с таймером.

Я предполагаю (и это только предположение, поскольку у меня нет доступа к вашему коду), что таймер срабатывает, когда форма закрывается. Объект dbiSchedule был удален, но таймер каким-то образом все еще пытается вызвать его. Этого не должно произойти, потому что если таймер имеет ссылку на объект расписания, то сборщик мусора должен увидеть это и не утилизировать его.

Это заставляет меня спросить: вы вызываете Dispose() на объекте расписания вручную? Если да, то делаете ли вы это перед тем, как избавиться от таймера? Убедитесь, что вы освободили все ссылки на объект расписания, прежде чем избавляться от него (т. е. избавиться от таймера заранее).

Теперь я понимаю, что прошло несколько месяцев между тем, как вы опубликовали это, и когда я отвечаю, так что, надеюсь, вы решили эту проблему. Я пишу это для пользы других людей, которые могут прийти позже с подобной проблемой.

Надеюсь, это поможет.


  Сведения об ответе

FAriza

02:20, 24th August, 2020

Глядя на стек ошибок trace, кажется, что ваш таймер все еще активен. Попробуйте отменить таймер при закрытии формы (т. е. в методе OnClose() формы). Это выглядит как самое чистое решение.


  Сведения об ответе

lool

02:38, 29th August, 2020

потому что папка решения находилась внутри папки OneDrive.

Если вы переместите папки решения из одной папки диска, то ошибки исчезнут.

лучший


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться