Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Invoke() для уничтоженного элемента. 
:(
    Опции темы
priest08
Дата 3.8.2011, 11:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 22.3.2008

Репутация: нет
Всего: нет



Может быть я не совсем понимаю что-то. Ситуация:
Есть самописный контрол. В нем среди прочего есть System.Threading.Timer (чтобы точечки бегали; для поиска). Этот таймер инициализируется так:
Код

private delegate void UpdateSearchIndicatorCharDelegate();

private void InitTimers()
        {
            // Инициализируем таймер для показа состояния поиска.
            _searchIndicatorTimer = new Timer(x => Invoke(new UpdateSearchIndicatorCharDelegate(delegate
            {
                _searchIndicatorImageIndex = (byte) (++_searchIndicatorImageIndex % _searchIndicatorImagesCount);
                searchIndicator.ImageIndex = _searchIndicatorImageIndex + _searchIndicatorImageStartIndex;
            })));
        }

Стартует этот таймер при событии начала поиска и стопится при окончании.
Итак: я нажимаю кнопочку - открывается форма со всякими полями/другими кнопками (и в том числе с этим контролом). Тыкаю на него - идет запрос к базе в надежде выбить из нее инфу. И тут скажем что-то подвисает (ну пусть хранимка долго делается), а я резко передумал => формочку закрываю. Все на ней умирает, таймеры тоже (Dispose перегружен). И почти сразу же получаю exception:
Caught unhanded exception: System.ObjectDisposedException: Доступ к ликвидированному объекту невозможен.
Имя объекта: "DictionaryForm".
DictionaryForm это как раз контрол этот. Происходит я так понимаю все потому, что таймер работает с дескриптором окна, которое я закрыл. Вот почему он все еще работает, вместо того, чтобы умереть - я хз.
Если делаю так:
Код

private void InitTimers()
        {
            _searchIndicatorTimer = new Timer(x => 
            {
                _searchIndicatorImageIndex = (byte) (++_searchIndicatorImageIndex % _searchIndicatorImagesCount);
                searchIndicator.ImageIndex = _searchIndicatorImageIndex + _searchIndicatorImageStartIndex;
            });
        }

то все работает без ошибок.
Вопрос: кто может объяснить ситуацию?
P.S. Ошибка кстати не постоянная (может случиться, а может и нет). Но если я ставлю брейк-поинт в Dispose() скажем и дальше F10, F10, F10... - 100% гарантия, что exception будет. Такое впечатление, что окно так неудачно умирает, что иногда метод не успевает доработать.
Спасибо за ответы.
PM MAIL   Вверх
jonie
Дата 3.8.2011, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



Invoke производит маршалинг в STA поток, в котором живет окно. Все окна живут в STA потоке (-ах)... Закрытие окна не гарантирует мгновенного завершения потока и\или отчистку накопившихся в нем сообщений windows (взаимодействие с окном производится посредством пихания в оконную очередь windows оконныхсообщений, на которое и реагирует окно) , и даже закрытия собственно окна мгновенного не гарантирует (окно как я помню сначала "скрывается")...

Т.к. у вас перегружен Dispose  то вы без труда сможете проставить флаг bool isDisposed внутри экземпляра вашего окна, на который в timer процедуре будете обращать внимание типа (if (isDisposed) return;)


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
priest08
Дата 3.8.2011, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 22.3.2008

Репутация: нет
Всего: нет



Спасибо за ответ.
Уточнение. Я так понимаю, что метод уже! запущен в потоке окошка, которому этот элемент принадлежит.
Код

private void InitTimers()
        {
            // Инициализируем таймер для показа состояния поиска.
            _searchIndicatorTimer = new Timer(x => Invoke(new UpdateSearchIndicatorCharDelegate(delegate
            {
            })));
        }

Он даже в таком виде дает ошибку. Таймер написанным выше ничего_не_деланием и занимается, но окно уже закрыто => хэндла нет, а Invoke()'у он нужен...
Оказывается в проекте уже был написанный хорошим человеком метод TryInvoke() smile  Он запускает тот же самый Invoke(), только при этом проверяет IsDispose контрола+наличие хэндла окна. Им и воспользовался=)
Все сделано и все понятно. Отдельное спасибо jonie.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1844 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.