Должны ли элементы управления Silverlight повторно загружаться на страницы? - PullRequest
3 голосов
/ 26 февраля 2011

Несколько месяцев назад я начал самостоятельно разрабатывать приложение Silverlight. Я быстро обнаружил, что не смог получить ожидаемую сборку мусора для большинства моих элементов управления. Я около недели боролся с WinDBG и профилировщиком памяти ANTS, а затем нашел ветку «утечка памяти DataTemplate» на форуме Silverlight (http://forums.silverlight.net/forums/t/171739.aspx).

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

Во всяком случае, теперь я снова изучаю проблему и понимаю, что проблема, с которой я столкнулся, гораздо более фундаментальна, чем я думала. У меня просто нет парадигмы для написания собираемых мусором элементов управления Silverlight, когда: a) элемент управления имеет свойства зависимостей, с которыми можно связываться, и b) элемент управления может быть выгружен из одного элемента управления, а затем снова загружен.

Я начинаю думать, что второе из этих требований слишком велико. Кто-нибудь может это подтвердить?

Чтобы дать чуть больше деталей, самый надежный шаблон, который я могу придумать для написания хороших, собираемых мусором элементов управления Silverlight, выглядит следующим образом:

1) Когда применяется шаблон элемента управления (в переопределении OnApplyTemplate), я устанавливаю любые внутренние привязки между локальными свойствами и TemplateParts. Например, я мог бы установить привязку между локальным свойством CanSearch и кнопкой.

if (x_Button_Search != null)
            {
                Binding b = new Binding("CanSearch");
                b.Source = this;
                this.x_Button_Search.SetBinding(Button.IsEnabledProperty, b);
            }

2) Когда Control вызывает событие Unloaded, я очищаю внутренние привязки и отключаю любые обработчики событий.

if (x_Button_Search != null)
            {
                this.x_Button_Search.ClearValue(Button.IsEnabledProperty);
            }

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

3) Опять же, когда элемент управления вызывает событие Unloaded, я очищаю привязки к существующим свойствам зависимостей.

 this.ClearValue(SearchParametersProperty);

Если я не смогу сделать это, я могу вызвать утечки. Например, если свойство SearchParameters было привязано к какому-либо объекту INotifyPropertyChanged, то ссылка на элемент управления остается в событии PropertyChanged объекта INotifyPropertyChanged, к которому я привязан, даже после того, как элемент управления был выгружен, т. Е. Представление будет сохраняться до тех пор, пока Модель и того не может быть желаемой.

4) Я «мерцаю» значение шаблона, чтобы при следующей загрузке элемента управления шаблон повторно применялся и снова вызывался метод OnApplyTemplate.

var oldTemplate = this.Template;
            this.Template = null;
            this.Template = oldTemplate;

Причина для выполнения 4 заключается в том, что мне необходимо восстановить привязки, когда элемент управления перезагружается на страницу. В Silverlight есть две точки входа, через которые это можно сделать: в переопределении OnApplyTemplate или после того, как элемент управления инициирует событие Loaded. Поскольку я хочу применить обязательные значения перед загрузкой элемента управления (чтобы избежать мерцания), доступна только одна доступная точка входа, OnApplyTemplate. Я должен мерцать шаблон, чтобы заставить шаблон повторно применяться, когда элемент управления перезагружен.

Похоже, этот шаблон до точки 3 является минимальным для обеспечения контроля сбора мусора.

Моя проблема возникает, когда вы хотите выгрузить свой элемент управления (например, удалить его из Panel) и затем перезагрузить его. Любые свойства зависимости для элемента управления были установлены равными нулю в пункте 3. Например, представьте, что в объявлении элемента управления есть привязка, например. , Насколько я могу судить, не существует способа восстановить эту привязку, если для значения SearchParameters установлено нулевое значение, в конце концов, он не является частью шаблона. В результате, когда элемент управления перезагружается, все равно, что значение SearchParameters было нулевым Поэтому я либо пропускаю шаг 3 в шаблоне и получаю перезагружаемый элемент управления, который не является сборщиком мусора, либо я сохраняю 3 и получаю не перегружаемый элемент управления.

1 Ответ

1 голос
/ 26 февраля 2011

То, что вы делаете в 1), кажется действительно странным. Почему инициирование привязки к шаблону в коде, а не в xaml? Мы решили множество проблем утечки памяти в Silverlight с помощью этого программного обеспечения

http://memprofiler.com/

EDIT

Для большего контроля над связыванием вы можете использовать

{Binding Property, RelativeSource={RelativeSource TemplatedParent}}

Таким образом, неявные преобразователи используются должным образом, и вы также можете указать свои собственные. И я считаю, что BindingMode TwoWay также работает. Удачи!

...