复合WPF(Prism)模块资源数据模板

发布于 2024-07-27 15:19:35 字数 1369 浏览 5 评论 0原文

假设我有一个 shell 应用程序和几个使用 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 中。 这可能吗?

Given that I have a shell application and a couple of separate module projects using Microsoft CompoisteWPF (Prism v2)...

On receiving a command, a module creates a new ViewModel and adds it to a region through the region manager.

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

I thought that I could then create a resource dictionary within the module and set up a data template to display a view for the view model type that was loaded (see below xaml). But when the view model is added to the view, all I get is the view models namespace printed out.

<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>

Edit:

I can get it to work by adding to the 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>

Which is fine, but it means that as new modules are created, the App.xaml file needs to be added to. What I'm looking for is a way for modules, as they load to dynamically add to the the Application.Resources. Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

她如夕阳 2024-08-03 15:19:35

为了避免您的 shell 应用程序必须了解有关您的模块的任何信息以及您的模块以任何方式接触 shell,我会为您的模块提供一个如下所示的接口:

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");
     }
}

然后,您可以在 shell 中实现此操作:

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

最后,在引导程序的配置容器中:

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

这将为您提供所需的功能,并且您的 Shell 和模块将保持彼此独立。 这样做的另一个好处是更具可测试性,因为您无需启动 Application 来测试您的模块代码(只需模拟 IMergeDictionaryRegistry 即可完成)。

让我们知道您的情况如何。

To avoid your shell app from having to know anything about your modules and your modules from reaching out into the shell in any way, I'd provide an interface to your modules like this:

IMergeDictionaryRegistry
{
     void AddDictionaryResource(Uri packUri);
}

You'd ask for this interface in your Module code:

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");
     }
}

You would then implement this in your shell to do this:

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

And then finally, in your Bootstrapper's ConfigureContainer:

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

This will get you the functionality you want and your Shell and your Module will remain independent of each other. This has the added benefit of being more testable in that you have no need to spin up an Application to test your module code (just mock IMergeDictionaryRegistry and you are done).

Let us know how this goes for you.

阳光的暖冬 2024-08-03 15:19:35

在每个模块的初始化中,您可以添加到应用程序资源:

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"))
                              });
              });
}

Within the initialisation of each module, you can add to the application resources:

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

Or if you follow a convention of each module has a resource dictionary called "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"))
                              });
              });
}
无戏配角 2024-08-03 15:19:35

这一切看起来工作量很大!

就我个人而言,我只是在视图的 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>

我猜你会在那里声明你的数据模板。

HTH。

That all seems like a lot of work!

Personally, I just declare a resource dictionary in my view's UserControl.Resources section like this...

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

That merged dictionary then points to any resources I need to include.

<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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文