Какой самый безопасный способ очистить свойство Controls контейнера и убедиться, что элементы управления расположены правильно? - PullRequest
0 голосов
/ 29 марта 2011

В приложении WinForms у меня есть несколько случаев, когда я добавляю элемент управления в контейнер в ответ на действие пользователя (panel.Controls.Add(new CustomControl(...))), затем позже очищаю панель (panel.Controls.Clear()) и повторно использую ее.

В работе приложение иногда выдает исключение, связанное с ошибками GDI или с ошибкой загрузки ImageList.Это обычно происходит на машинах с ограниченными ресурсами и с пользователями, которые интенсивно используют приложение в течение дня.Кажется довольно очевидным, что у меня есть утечка ручки GDI и что я должен избавиться от элементов управления, которые вычищены из контейнера, однако любые объяснения, которые я могу найти, являются неопределенными относительно того, где и когда должен быть расположен элемент управления.

Должен ли я утилизировать дочерние элементы управления сразу после очистки контейнера?Что-то вроде:

var controls = new List<Control>(_panel.Controls.Cast<Control>());
_panel.Controls.Clear();
foreach (var c in controls) c.Dispose();

Или я должен отслеживать элементы управления в списке и вызывать dispose в методе Dispose() контейнера?Такие как:

List<Control> _controlsToDispose = new List<Control>();
void ClearControls()
{
    _controlsToDispose.AddRange(_panel.Controls.Cast<Control>());
    _panel.Controls.Clear();
}
void Dispose()
{
    ...
    foreach (var c in _controlsToDispose) c.Dispose();
}

Ответы [ 2 ]

0 голосов
/ 18 апреля 2011

После (довольно эффективного) исправления любых случаев, когда мое приложение не использовало очищенные элементы управления, я могу придумать несколько моментов:

  • Иногда я предварительно создавал список элементов управления, хранящихся, например, в свойстве Tag коллекции ListViewItem с или TreeViewItem с. Они не должны быть расположены в открытом виде, но весь список должен быть повторен и ((Control)item.Tag).Dispose() вызван в методе Dispose() родителя.
  • Если элемент управления не будет использоваться снова, что может произойти, когда я создаю его на лету, его следует утилизировать, когда он вынут из контейнера.
  • При очистке и добавлении элементов управления на лету необходимо учитывать жизненный цикл элементов управления, чтобы определить, следует ли их немедленно утилизировать, отложить его до удаления родительского элемента или не беспокоиться об этом.
  • У меня была ситуация, когда я удалял элемент управления для отображения сообщения «Загрузка ...», а затем возвращал элемент управления позже, в ответ на завершение потока. Я добавил вызов для удаления элемента управления при его удалении, что приводило к ошибкам при попытке добавить его снова. Из-за проблемы с многопоточностью отладка не была простой. Дело в том, что жизненный цикл может зависеть от потоков, отличных от потока пользовательского интерфейса. Показательный пример состоял из 20 секунд после отображения формы, поэтому, по крайней мере, элемент управления все еще существовал. Управление ситуацией, когда элемент управления может быть уничтожен потоками, которые все еще хотят ссылаться на него, вероятно, является причиной слабых событий.

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

0 голосов
/ 29 марта 2011

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

...