Отписаться перед удалением элемента?

У ListBox есть дочерние элементы, у которых есть подписки. Допустим, у ListBox есть StackPanel, а у StackPanel есть Button с подпиской.

После использования StackPanel я хочу удалить StackPanel из ListBox.

// There is a ListBox named "list".

StackPanel stack = new StackPanel();
Button button = new Button();

RoutedEventHandler eventHandler = (s, e) => { ... };
button.Click += eventHandler;

stack.Children.Add(button);
list.Items.Add(stack);

...

// Now I want to remove StackPanel. 
// Should I do this before removing: "button.Click -= eventHandler;"?

list.Items.Remove(stack);

Должен ли я отказаться от подписки Button перед удалением StackPanel из ListBox (во избежание утечек памяти)? Или достаточно удалить StackPanel из ListBox, чтобы дочерние подписки (в данном случае Button) исчезли и сборщик мусора смог их легко собрать? Спасибо.


person Кирилл Зацепин    schedule 03.01.2021    source источник
comment
Даже если вы не собираетесь полностью использовать MVVM, вам следует обратить внимание на DataTemplates и Commands — таким образом вам не придется беспокоиться об отписке от событий.   -  person Peregrine    schedule 03.01.2021
comment
Когда долгоживущий экземпляр регистрируется на событие, вы должны отменить подписку на него, чтобы он был отсоединен.   -  person Jeroen van Langen    schedule 03.01.2021
comment
Правильно ли я понимаю, что при удалении StackPanel из списка сначала удаляются дочерние элементы (кнопка в данном случае)? То есть мне не нужно беспокоиться об отписке кнопки, так как она удаляется до StackPanel?   -  person Кирилл Зацепин    schedule 03.01.2021
comment
Какой класс определяет обработчик событий? Предполагая, что это часть (более длительного) окна, вам нужно отменить регистрацию события, иначе вы получите утечку памяти, поскольку сборщик мусора не соберет кнопку. Эта конструкция кода по-прежнему больше похожа на то, что я писал в winforms в 2005 году, чем на то, как вы должны использовать WPF.   -  person Peregrine    schedule 03.01.2021
comment
Вы можете отказаться от подписки на свой обработчик событий или вместо этого использовать слабый шаблон события.   -  person Andy    schedule 03.01.2021
comment
Связывание и команды позволяют избежать утечек памяти. Вы можете использовать слабую ссылку для перенаправленного события stackoverflow.com/questions/18565396/ Но почти все коммерческие команды используют привязку команд.   -  person Andy    schedule 03.01.2021
comment
@JeroenvanLangen: Когда долгоживущий экземпляр регистрируется на событие, вы должны отменить подписку на него, чтобы отсоединить его — это противоположно правильному. Время жизни объекта определяется его достижимостью. Объект с более коротким сроком жизни — это объект, который становится недоступным перед другим. Если этот объект публикует событие, а другие объекты подписываются на это событие, этим другим объектам не нужно отписываться от более короткоживущего объекта, потому что он недоступен, и поэтому любые ссылки, которые он имеет на другие объекты, также не могут быть достигнуты через более короткий объект. жилой объект.   -  person Peter Duniho    schedule 04.01.2021


Ответы (1)


Насколько мне известно

list.Items.Remove(stack);

вообще не собирается изменять содержимое StackPanel. После этого вы можете продолжать использовать объект, на который ссылается stack.

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


Также стоит отметить, что вам совсем не обязательно отписываться от событий. Это может быть хорошей практикой, но также может просто добавить ненужную сложность. Для небольшого приложения, вероятно, не будет никакого вреда, чтобы оставить их. В конечном итоге сборщик мусора очистит все эти объекты, как только они больше не будут использоваться. (Скажем, после закрытия окна WPF).

person StayOnTarget    schedule 04.01.2021
comment
Если бы не было обработчика событий, StackPanel и все его содержимое, включая кнопку, в конечном итоге были бы удалены сборщиком мусора - при условии, что нет другой внешней ссылки на какой-либо из элементов управления. - person Peregrine; 04.01.2021
comment
@Peregrine Я согласен, но это зависит от того, что произойдет дальше в программе, что не указано в вопросе. Я думаю, что ОП не был уверен, какой эффект будет иметь добавление/удаление дочерних элементов и как это связано с событиями. Я не думал, что они спрашивали о GC. - person StayOnTarget; 04.01.2021
comment
Даже если попадание в память незначительно, вы не хотите оставлять несобранные элементы в долго работающем приложении. - person Peregrine; 04.01.2021