Category Archives: WPF
Используя стандартную конструкцию {Binding ElementName=myElement}
, никогда не задумывался о том, как происходит разрешение элемента по имени, если этот элемент определён дальше. А когда сам стал писать XAML-подобный механизм, озадачился. Ведь парсер должен строить граф объектов последовательно, сверху вниз, читая атрибуты и содержимое тегов и тут же их применяя к текущему конструируемому объекту. Но как в таком случае разруливать ссылки на элементы, до которых парсер ещё не добрался ? Неужели WPF обрабатывает расширения разметки отдельно, уже после построения графа объектов ? Это было бы весьма нелогично. Документация по этому вопросу отсутствовала, было только описание интерфейса IXamlNameResolver с сигнатурами методов, по которым можно догадаться о том, что метод Resolve может возвращать ссылки на не до конца инициализированные объекты, а заказывать нужные элементы можно через GetFixupToken.
Поискав на stackoverflow с полчаса, я нашёл замечательнейший ответ на свой вопрос.
Работает всё следующим образом. Классы, зарегистрированные в качестве расширений разметки, вызываются тотчас же для преобразования строки в объект. Метод ProvideValue может вернуть либо готовый объект, либо FixupToken, получаемый от сервиса IXamlNameResolver. Если ProvideValue возвращает FixupToken, то ProvideValue этого расширения разметки будет вызван ещё раз, когда все требуемые элементы будут созданы. А для отлова случаев, когда искомого элемента вообще нет в разметке, код ProvideValue должен перед вызовом GetFixupToken проверять значение свойства IsFixupTokenAvailable. Если оно равно False, граф объектов уже создан полностью, и метод должен как-то обработать ошибку (выбросить исключение, как правило), если нужного элемента среди созданных объектов нет.
В свете недавних новостей решил наконец оформить своё поделие в open-source библиотеку и выложить, как это у меня принято, на bitbucket. Код этот я писал уже довольно давно, когда плотно работал с WPF, помнится, тогда мы использовали аналогичную разработку моего коллеги Рината Зарипова. На тот момент она показалась мне слишком усложнённой, и спустя некоторое время я решил написать свою, более простую реализацию. Из ринатовской концепции я позаимствовал гениальную идею о преобразовании методов в команды, за что ему респект и уважуха. Такой крутой фишки не было ни в одном из существовавших тогда MVVM-фреймворков. Сейчас – не знаю, может быть где-то и появилась, хотя навряд ли.
Пример использования с комментариями прилагается, сам код библиотеки откомментирован тоже, но недостаточно. Надо будет заняться этим более плотно. Если в будущем буду пересекаться с WPF, то обязательно попутно сделаю это.
На днях вычитал о вышедшей новой Visual Studio 2013 RC. Решил попробовать установить, чтобы проверить, пофиксили ли окончательно проблему с XAML-дизайнером. Проблема была в том, что наши WPF-приложения, использующие для организации UI-кода концепцию MVP (Model-View-Presenter), в базовых классах для Windows и UserControls использовали Generic-классы: ConcreteWindow: BaseWindow<TModel, TPresenter, TView>, где TModel – тип-аргумент класса модели (автоматически становится DataContext’ом), TPresenter – соответственно, класс презентера, и TView – интерфейс представления, реализуемого окном. Презентер имеет доступ к модели и к представлению (через интерфейс), представление работает с моделью посредством байндингов. Модель не знает ни о чем, кроме себя, хранит данные и оповещает об их изменении. Всё стандартно. И в старых версиях Visual Studio всё работало на ура, однако в 2012 версии майкрософтовцы перефигачили дизайнер (видимо, взяв код из Blend, поскольку там раньше наблюдалась такая же проблема), и отображение таких XAML (у которых главный элемент определяет generic-класс) отвалилось. При этом проект продолжал собираться и работать, и по спецификациям XAML всё было в порядке. Мои товарищи по несчастью тогда запостили вышеприведённый тред, и вскоре проблему вроде бы пофиксили, но, когда я установил себе обновление, всё осталось по-прежнему. Вчера я решил вновь побороться за улучшение мира, и отписался их “програм менеджеру”, рассказав свою душещипательную историю и приложив архив тестового проекта, воспроизводящего проблему. Сегодня мне пришел ответ:
Как оказалось, действительно достаточно убрать пробелы, и всё заработает ! В общем, я очень обрадовался, во-первых, быстрому ответу, а во-вторых тому, что мои изобретения снова можно использовать в современных Visual Studio. А то после неудач с 2012 студией мне казалось, что этот подход теперь будет нежизнеспособен, придется самому переезжать на традиционный MVVM, и уж точно никто из других людей не будет пользоваться технологией, которая не совместима с XAML-дизайнером. Теперь хотя бы есть надежда, что эти наработки не умрут. Собираюсь выложить их в открытый доступ, поскольку для наших проектов они оказались довольно удачным способом организации кода.
0