Обработка событий с анонимным делегатом - PullRequest
0 голосов
/ 27 января 2010

Для справки: я нашел похожий вопрос здесь , но мне нужно подробнее остановиться на этом вопросе.

Мой конкретный сценарий таков:

В Silverlight 4 метод myFrameworkElement.FindName("otherElementName"), кажется, теперь работает нормально, но я столкнулся с проблемой. Он по-прежнему возвращает null, когда элемент еще не добавлен в визуальное дерево.

Но теперь мне нужна эта функциональность в DependencyProperty PropertyChangedCallback пользовательского обработчика UserControl. В этой области пока неизвестно, добавлен ли UserControl в визуальное дерево. Но я должен выполнить определенное действие над другим элементом дерева. Когда элемент уже доступен, это можно и нужно сделать прямо сейчас. Если нет, то это должно быть сделано немедленно, когда это доступно. Итак, я придумал этот метод расширения, который я могу назвать так:

myFrameworkElement.FindNameEnsured("otherElementName",
    result => this.DoSomethingWith(result));

Код для метода расширения выглядит следующим образом:

    static public void FindNameEnsured(this FrameworkElement self,
            string name, Action<object> resultAction)
    {
        if (self != null && resultAction != null)
        {
            object result = self.FindName(name);

            if (result != null)
            {
                resultAction(result);
            }
            else
            {
                RoutedEventHandler handler = null;
                handler = (sender, e) =>
                     {
                         result = self.FindName(name);
                         resultAction(result);

                         self.Loaded -= handler;
                     };

                self.Loaded += handler;
            }
        }

Как видите, я должен использовать анонимный делегат, потому что мне нужны значения для name и resultAction внутри обработчика. Затем я отказываюсь от подписки на событие внутри обработчика, потому что я умный и чистый парень и не хочу никаких утечек. Я также не хочу разбивать мух на колесах с помощью каких-нибудь причудливых WeakEventFactories или подобных вещей.

Теперь это работает без сбоев. Но у меня есть несколько вопросов.

  1. Это вообще достаточно чистый подход, чтобы отписаться от обработчика событий внутри обработчика? Или это в конечном итоге убьет невинного щенка?
  2. Могут ли быть некоторые проблемы, например утечка, из-за использования внешних переменных области действия внутри анонимного делегата?
  3. Могут ли быть проблемы с синхронизацией потоков, из-за которых я могу "пропустить" событие Loaded? В этом особом сценарии должен участвовать только поток диспетчера пользовательского интерфейса Silverlight. Но если это все равно проблема, и / или если мне нужны аналогичные функциональные возможности в сценарии, не связанном с пользовательским интерфейсом, каков лучший подход к f1x0r?

Спасибо уже за ваше терпение и за время, прочитав мои длинные разработки. ; -)

1 Ответ

2 голосов
/ 27 января 2010
  1. Это должно быть хорошо, хотя это немного больно. LINQ to Rx имеет более хорошую идею отказа от подписки - когда вы подписываетесь, вы получаете IDisposable, который отписывается, когда вы его утилизируете. Это не соответствует существующей модели событий.
  2. Я не думаю, что в этом конкретном случае у вас будет какая-либо утечка - есть некоторые граничные условия, когда две разные анонимные функции, использующие переменные в одной и той же области видимости, могут в итоге получить переменные, которые им не нужны, но это действительно это крайний случай.
  3. Вы должны были бы дать более точные сведения о гипотетической ситуации - что именно вас беспокоило, как реализовано событие и т. Д.
...