Шаблоны данных ресурсов модуля Composite WPF (Prism)

Учитывая, что у меня есть приложение оболочки и несколько отдельных проектов модулей с использованием Microsoft CompoisteWPF (Prism v2) ...

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

var viewModel = _container.Resolve<IMyViewModel>();
_regionManager.Regions[RegionNames.ShellMainRegion].Add(viewModel);

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

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:Modules.Module1.ViewModels"
    xmlns:vw="clr-namespace:Modules.Module1.Views"
>
    <DataTemplate DataType="{x:Type vm:MyViewModel}">
        <vw:MyView />
    </DataTemplate>
</ResourceDictionary>

Редактировать:

Я могу заставить его работать, добавив в App.xaml

<Application.Resources>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/Module1;component/Module1Resources.xaml"/>
        <ResourceDictionary Source="pack://application:,,,/Module2;component/Module2Resources.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</Application.Resources>

Это нормально, но это означает, что по мере создания новых модулей необходимо добавлять файл App.xaml. Я ищу способ для модулей, загружаемых для динамического добавления в Application.Resources. Это возможно?


person Oll    schedule 23.07.2009    source источник


Ответы (3)


Чтобы ваше приложение-оболочка не узнало что-либо о ваших модулях, а ваши модули каким-либо образом не обращались к оболочке, я бы предоставил интерфейс для ваших модулей следующим образом:

IMergeDictionaryRegistry
{
     void AddDictionaryResource(Uri packUri);
}

Вы бы попросили этот интерфейс в своем коде модуля:

public class MyModule : IModule
{
     IMergeDictionaryRegistry _merger;
     public MyModule(IMergeDictionaryRegistry merger)
     {
          _merger = merger;
     }

     public void Initialize()
     {
          _merger.AddDictionaryResource(new Uri("pack://application:,,,/Module1;component/Module1Resources.xaml");
     }
}

Затем вы должны реализовать это в своей оболочке, чтобы сделать это:

public MergeDictionaryRegistry : IMergeDictionaryRegistry
{
     public void AddDictionaryResource(Uri packUri)
     {
          Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
          {
               Source = packUri;
          });
     }
}

И, наконец, в ConfigureContainer загрузчика:

public override void ConfigureContainer()
{
     base.ConfigureContainer();
     Container.RegisterType<IMergeDictionaryRegistry, MergeDictionaryRegistry>();
}

Это даст вам желаемую функциональность и, что ваша оболочка и ваш модуль останутся независимыми друг от друга. Это имеет дополнительное преимущество, заключающееся в том, что вам не нужно запускать Application для проверки кода вашего модуля (просто смоделируйте IMergeDictionaryRegistry, и все готово).

Сообщите нам, как это пойдет для вас.

person Anderson Imes    schedule 23.07.2009
comment
Спасибо. WPF знает, как визуализировать ViewModel с помощью DataTemplate (см. msdn. microsoft.com/en-us/magazine/dd419663.aspx#id0090097). Проблема заключается в том, чтобы приложение узнало о DataTemplate в другой сборке. Я отредактировал сообщение, чтобы предоставить более подробную информацию. - person Oll; 23.07.2009
comment
О, я вижу, что ты делаешь. Возможно, вам придется предоставить какой-либо интерфейс (IMergeDictionaryRegistration с методом, принимающим URL-адрес пакета) для ваших модулей и добавить их в словарь ресурсов вашего приложения. Просто теория. - person Anderson Imes; 24.07.2009
comment
Кроме того ... Мне любопытно, как это происходит у вас. Дайте нам знать. Это интересный подход. - person Anderson Imes; 24.07.2009

В рамках инициализации каждого модуля вы можете добавить к ресурсам приложения:

Application.Current.Resources.MergedDictionaries
                .Add(new ResourceDictionary
                {
                    Source = new Uri(
                        @"pack://application:,,,/MyApplication.Modules.Module1.Module1Init;component/Resources.xaml")
                });

Или, если вы следуете соглашению о том, что каждый модуль имеет словарь ресурсов под названием "Resources.xmal" ...

protected override IModuleCatalog GetModuleCatalog()
{
    var catalog = new ModuleCatalog();

    AddModules(catalog,
               typeof (Module1),
               typeof(Module2),
               typeof(Module3),
               typeof(Module4));

    return catalog;
}

private static void AddModules(ModuleCatalog moduleCatalog,
    params Type[] types)
{
    types.ToList()
         .ForEach(x =>
             {
                 moduleCatalog.AddModule(x);
                 Application.Current.Resources.MergedDictionaries
                     .Add(new ResourceDictionary
                              {
                                  Source = new Uri(string.Format(
                                                       @"pack://application:,,,/{0};component/{1}",
                                                       x.Assembly,
                                                       "Resources.xaml"))
                              });
              });
}
person Oll    schedule 19.08.2009
comment
Первая часть вашего ответа требует, чтобы ваш модуль проник в Приложение. Я бы не рекомендовал этого, поскольку это непроверено. Второй подход более уместен. - person Anderson Imes; 03.06.2011

Кажется, это требует много работы!

Лично я просто объявляю словарь ресурсов в разделе UserControl.Resources моего представления вот так ...

<UserControl.Resources>
    <ResourceDictionary Source="../Resources/MergedResources.xaml" />
</UserControl.Resources>

Затем этот объединенный словарь указывает на любые ресурсы, которые мне нужно включить.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Iconography.xaml" />
    <ResourceDictionary Source="Typeography.xaml" />
</ResourceDictionary.MergedDictionaries>

You'd declare your data templates in there I guess.

HTH.

person EightyOne Unite    schedule 09.09.2010