Prism 2.1 Внедрение модулей в ViewModel - PullRequest
5 голосов
/ 22 января 2010

Я пытался внедрить модули из моего ModuleCatalog в ViewModel моей оболочки, но мне не очень повезло ...

Я создаю ModuleCatalog в моем загрузчике, и мой модуль без проблем попадает на экран из своего инициализатора. Тем не менее, я бы хотел иметь возможность связать мой список модулей с контейнером с помощью DataTemplate, который позволял запускать их из меню!

Вот мой файл Boostrapper, со временем я буду добавлять больше модулей, но сейчас он просто содержит мой довольно надуманный «ProductAModule»:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        Container.RegisterType<IProductModule>();

        base.ConfigureContainer();
    }

    protected override IModuleCatalog GetModuleCatalog()
    {
        return new ModuleCatalog()
            .AddModule(typeof(ProductAModule));
    }

    protected override DependencyObject CreateShell()
    {
        var view = Container.Resolve<ShellView>();
        var viewModel = Container.Resolve<ShellViewModel>();
        view.DataContext = viewModel;
        view.Show();

        return view;
    }
}

Исходя из этого, вот ViewModel моей Shell:

public class ShellViewModel : ViewModelBase
{
    public List<IProductModule> Modules { get; set; }

    public ShellViewModel(List<IProductModule> modules)
    {
        modules.Sort((a, b) => a.Name.CompareTo(b));
        Modules = modules;
    }
}

Как вы можете видеть, я пытаюсь внедрить список IProductModule (которому ProductAModule наследует некоторые из его свойств и методов), чтобы затем его можно было привязать к представлению моей оболочки. Есть ли что-то ДЕЙСТВИТЕЛЬНО простое, что я пропускаю, или это нельзя сделать с помощью Unity IoC? (Я видел, что это сделано с расширением StructureMap для Prism)

Еще одна вещь ... При запуске приложения, в тот момент, когда ShellViewModel разрешается контейнером в загрузчике, я получаю следующее исключение:

Не удалось разрешить зависимость, type = "PrismBasic.Shell.ViewModels.ShellViewModel", name = "". Сообщение об исключении: Текущая операция сборки (ключ сборки Build Key [PrismBasic.Shell.ViewModels.ShellViewModel, null]) завершилась неудачно: не удалось разрешить модули параметров при попытке вызвать конструктор PrismBasic.Shell.ViewModels.ShellViewModel (System.Collections .Generic.List`1 [[PrismBasic.ModuleBase.IProductModule, PrismBasic.ModuleBase, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = null]] модули). (Тип стратегии BuildPlanStrategy, индекс 3)

Во всяком случае, просто да ... Выглядит ошеломленным ...

Любая помощь будет принята с благодарностью!

Rob

Ответы [ 4 ]

2 голосов
/ 22 января 2010

Я думаю, вы могли бы просто сделать это:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        Container.RegisterType<IProductModule>();

        base.ConfigureContainer();
    }

    private static ObservableCollection<IProductModule> _productModules = new Obser...();
    public static ObservableCollection<IProductModule> ProductModules
    { 
         get { return _productModules; } 
    }
    protected override IModuleCatalog GetModuleCatalog()
    {
        var modCatalog = new ModuleCatalog()
            .AddModule(typeof(ProductAModule));
        //TODO: add all modules to ProductModules collection

        return modCatalog;
    }

   ...
}

Тогда у вас будет статическое свойство, к которому можно привязать что-либо напрямую или использовать из вашей ViewModel.


Вот как получить список имен модулей, которые были зарегистрированы в каталоге модулей.

public class MyViewModel : ViewModel
{

      public ObservableCollection<string> ModuleNames { ... }
      public MyViewModel(IModuleCatalog catalog)
      {
           ModuleNames = new ObservableCollection<string>(catalog.Modules.Select(mod => mod.ModuleName));
      }
}

Вот и все. IModuleCatalog и IModuleManager - единственные вещи, которые настроены в контейнере для вас, чтобы получить доступ с точки зрения модулей. Как я уже сказал, вы не получите никаких данных экземпляра, потому что эти модули (будем надеяться) еще не созданы . Вы можете получить доступ только к данным типа.

Надеюсь, это поможет.

1 голос
/ 02 марта 2010

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

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

То, как вы хотите развернуть свои представления и сервисы с точки зрения модулей, больше зависит от того, какой уровень модульности вы ищете, т.е. хотите ли вы иметь возможность развертывать представления и сервисы ModuleA независимо от представлений и услуги ModuleB и так далее. В вашем случае может быть достаточно зарегистрировать все в одном модуле.

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

Причина, по которой ваши примеры генерируют пример, заключается в том, что ваша ShellViewModel зависит от List, и этот тип не зарегистрирован в Unity. Кроме того, вы регистрируете IProductModule в Unity, что не имеет смысла, поскольку интерфейс не может быть создан.

0 голосов
/ 25 января 2010
var modules = new IProductModule[]
{
    Container.Resolve<ProductAModule>()
    //Add more modules here...
};
Container.RegisterInstance<IProductModule[]>(modules);

Вот и все! Используя этот код, я могу вставить свои модули в ShellViewModel и отобразить каждый модуль как кнопку в моем приложении!

ТАКОЕ простое разрешение! От отличного парня из дискуссионной группы CompositeWPF. Я рекомендую их без остатка ^ _ ^

0 голосов
/ 22 января 2010

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

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

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


Редактировать: Вам необходимо применить атрибут DependencyAttribute к свойствам, чтобы использовать метод установки в Unity; Вы можете прочитать об этом здесь .

...