Как WPF резолвит ссылки на ещё не созданные элементы

Written by elwood

xamllogo

Используя стандартную конструкцию {Binding ElementName=myElement}, никогда не задумывался о том, как происходит разрешение элемента по имени, если этот элемент определён дальше. А когда сам стал писать XAML-подобный механизм, озадачился. Ведь парсер должен строить граф объектов последовательно, сверху вниз, читая атрибуты и содержимое тегов и тут же их применяя к текущему конструируемому объекту. Но как в таком случае разруливать ссылки на элементы, до которых парсер ещё не добрался ? Неужели WPF обрабатывает расширения разметки отдельно, уже после построения графа объектов ? Это было бы весьма нелогично. Документация по этому вопросу отсутствовала, было только описание интерфейса IXamlNameResolver с сигнатурами методов, по которым можно догадаться о том, что метод Resolve может возвращать ссылки на не до конца инициализированные объекты, а заказывать нужные элементы можно через GetFixupToken.

Поискав на stackoverflow с полчаса, я нашёл замечательнейший ответ на свой вопрос.

Работает всё следующим образом. Классы, зарегистрированные в качестве расширений разметки, вызываются тотчас же для преобразования строки в объект. Метод ProvideValue может вернуть либо готовый объект, либо FixupToken, получаемый от сервиса IXamlNameResolver. Если ProvideValue возвращает FixupToken, то ProvideValue этого расширения разметки будет вызван ещё раз, когда все требуемые элементы будут созданы. А для отлова случаев, когда искомого элемента вообще нет в разметке, код ProvideValue должен перед вызовом GetFixupToken проверять значение свойства IsFixupTokenAvailable. Если оно равно False, граф объектов уже создан полностью, и метод должен как-то обработать ошибку (выбросить исключение, как правило), если нужного элемента среди созданных объектов нет.