#silverlight #inversion-of-control #unity-container
#silverlight #инверсия управления #unity-контейнер
Вопрос:
Я использую платформу навигации Silverlight и недавно кодировал свое приложение следующим общим способом:
Public MasterPageView: UserControl
{
private IMasterPageViewModel _ViewModel = null;
public MasterPageView():this(new MasterPageViewModel(), new BusinessObjectProvider())
{
}
public MasterPage(IMasterPageViewModel viewModel)
{
InitializeComponent();
_ViewModel = viewModel;
this.DataContext = viewModel;
}
}
Теперь, когда у меня создан скелет моего проекта, я хочу выполнить некоторую уборку, прежде чем начнется интенсивная разработка. В рамках моего процесса рефакторинга я хочу использовать IOC Unity и удалить конструкторы по умолчанию.
Кто-нибудь использовал платформу навигации Silverlight с Unity? Я был бы признателен за любые предложения о том, как это сделать.
Основные проблемы и вопросы, которые я вижу, это 1) Где мне зарегистрировать объекты в Unity Framework? 2) Все представления создаются с использованием URIMAPPER в среде навигации Silverlight, как нам заставить URIMAPPER использовать Unity для создания своих представлений.
Любая помощь была бы высоко оценена.
Комментарии:
1. Я думаю, я могу помочь. Я постоянно путаюсь в том, какие части этого «материала» считаются «Unity», а что такое «Prism». Используете ли вы такие вещи, как «загрузчики», «регионы» и «модули» (я думаю, это было частью Prism)? Вот где добавление навигации стало сложным.
2. Да, это Prism. Unity — это контейнер IOC, который поставляется с Prism, то есть класс UnityContainer. У меня есть сайт навигации Silverlight, проблема в том, что при переходе на новую страницу URIMapper создает представление для перехода. Что, я думаю, мне нужно для начала, так это способ вызова URIMapper в контейнер IOC для разрешения представления
3. Хорошо, я просто позволяю навигационной системе создавать представление так, как она хочет. В представлении я использую элементы управления XAML с поддержкой IOC (области Prism).
Ответ №1:
Ответ №2:
Мы используем области Prism в XAML каждой страницы. Регионы автоматически выполнят функции IOC, когда создадут зарегистрированное для него представление. Таким образом, страницы не создаются через Unity, но области, которые они содержат, создаются.
Практически весь код на страницах передает любые параметры URL в регионы. Это несколько некрасивая вещь, выполняемая страницами; они вставляют параметры строки запроса в параметр RegionContext региона. Затем в представлении региона содержится некоторый код для получения этих контекстных данных и передачи их на виртуальную машину, предоставляемую Unity.
Если вы не используете Prism, это не сильно поможет. РЕДАКТИРОВАТЬ: Было еще несколько подробностей о том, как заставить области Prism хорошо работать со страницами навигации. Я поделюсь, если вы хотите пойти этим путем.
Иногда мы получаем доступ к контейнеру Unity с помощью созданного нами статического метода (я думаю, что статический метод просто разрешает объекты для вас, он не предоставляет всем полный интерфейс контейнера). Это отстой, но вы можете решить проблему вручную с помощью этого.
Ответ №3:
Видя, как люди создают представления, передавая их через контейнер IOC, я всегда чувствую себя грязным. Ваши поверхности дизайна (Visual Studio и Expression Blend) не будут этого делать — они настаивают на конструкторе по умолчанию. Так зачем с ними бороться?
Гораздо более чистым решением является использование шаблона view model locator. Вот базовый:
public abstract class ViewModelLocator<TViewModel>
{
public TViewModel ViewModel
{
get { return StaticGateway.ServiceLocator.GetInstance<TRuntimeViewModel>(); }
}
}
Где StaticGateway — это статический класс, который предоставляет доступ к вашему контейнеру Unity и предоставляет его ServiceLocator. Затем вы просто объявляете один:
public class MasterPageViewModelLocator : ViewModelLocator<IMasterPageViewModel> { }
И использовать ее в XAML:
<UserControl x:Class="YourCompany.MasterPageView" etc.>
<UserControl.Resources>
<local:MasterPageViewModelLocator x:Key="Locator" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource Locator}" Path="ViewModel" />
</UserControl.DataContext>
...etc...
</UserControl>
Ваши привязки, как правило, будут намного удобнее, потому что вы устанавливаете контекст данных в вашем XAML. Установка контекста данных в исходном коде может привести к некоторым странным поведениям, особенно когда вы переходите к интересным мыслям, таким как прикрепленное поведение. И вы по-прежнему полностью используете свой контейнер IOC для выполнения внедрения зависимостей с дополнительным преимуществом, заключающимся в том, что все ваши дизайнерские поверхности продолжают функционировать.
Что касается того, где регистрироваться, я не уверен точно, куда бы вы поместили это в навигационном приложении. Обычно вы используете Unity с чем-то вроде Prism и выполняете регистрацию в инициализаторах модуля. Я полагаю, вы могли бы сделать это в своем классе приложений или придумать эквивалент инициализатора модуля (но тогда вам следует просто использовать Prism, а не изобретать велосипед).
Комментарии:
1. В моем текущем дизайне у меня теперь есть конструктор по умолчанию для всех моих представлений. Внутри тела конструктора по умолчанию у меня есть это. DataContext = MyViewModelProvider.Resolve<MasterViewModel>(); Вы думаете, это плохая идея и ее нужно переработать. Кажется, что она поддается тестированию и представляет собой только одну строку кода в представлении
2. Я думаю, что это может быть плохой идеей, в зависимости от особенностей вашей ситуации. Хуже того, это может быть хорошо сейчас, но не будет хорошо позже, после внесения дальнейших улучшений. Вот почему я всегда начинаю с локатора модели представления в XAML. И это может быть «всего одна строка кода», но это очень важная строка кода, которая заставляет все работать. Вот эксперимент: откройте свой view в Blend и посмотрите, как это выглядит сейчас. Если вы удовлетворены, то двигайтесь дальше. Если вы не удовлетворены, попробуйте то, что я предложил, и вы увидите улучшение.