Files
DP44/GLM5Analysis/PatternLibrary/PrismModulePattern.md
2026-04-17 14:55:32 -04:00

6.1 KiB

Prism Module Pattern

When to Use

  • Creating a new feature module that integrates with DataPRO shell
  • Adding new UI components that need to be loaded at runtime
  • Implementing isolated feature sets that can be developed independently

Files to Create/Modify

1. Module Project Structure

DataPRO/Modules/{ModuleName}/
├── {ModuleName}Module.cs       (Module entry point)
├── View/
│   └── {ViewName}.xaml(.cs)    (XAML views)
├── ViewModel/
│   └── {ViewModelName}.cs      (View models)
├── Model/                       (Data models, if needed)
└── Resources/                   (String resources, images)

2. Register Module in Bootstrapper

File: DataPRO/DataPRO/Bootstrapper.cs Add to ConfigureModuleCatalog():

moduleCatalog.AddModule<{ModuleName}.{ModuleClass}>();

Code Template

Module Class ({ModuleName}Module.cs)

using System;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using DTS.Common;
using DTS.Common.Interface;
using Prism.Ioc;
using Prism.Modularity;
using Unity;

[assembly: {ModuleName}Name]
[assembly: {ModuleName}ImageAttribute]
namespace {ModuleName}
{
    [Export(typeof(IModule))]
    [Module(ModuleName = "{ModuleName}")]
    public class {ModuleName}Module : IModule
    {
        private readonly IUnityContainer _unityContainer;

        public {ModuleName}Module(IUnityContainer unityContainer)
        {
            _unityContainer = unityContainer;
        }

        public void Initialize()
        {
            _unityContainer.RegisterType<I{ViewName}, {ViewName}>();
            _unityContainer.RegisterType<I{ViewModelName}, {ViewModelName}>();
        }

        public void OnInitialized(IContainerProvider containerProvider) { }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            Initialize();
        }
    }

    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
    public class {ModuleName}NameAttribute : TextAttribute
    {
        public {ModuleName}NameAttribute() : this(null) { }
        public {ModuleName}NameAttribute(string s)
        {
            AssemblyName = AssemblyNames.{ModuleName}.ToString();
        }
        public override string AssemblyName { get; }
        public override Type GetAttributeType() => typeof(TextAttribute);
        public override string GetAssemblyName() => AssemblyName;
    }

    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
    public class {ModuleName}ImageAttribute : ImageAttribute
    {
        private BitmapImage _img;
        public {ModuleName}ImageAttribute() : this(null) { }
        public override BitmapImage AssemblyImage
        {
            get { _img = AssemblyInfo.GetImage(AssemblyNames.{ModuleName}.ToString()); return _img; }
        }
        public {ModuleName}ImageAttribute(string s)
        {
            _img = AssemblyInfo.GetImage(AssemblyNames.{ModuleName}.ToString());
        }
        public override Type GetAttributeType() => typeof(ImageAttribute);
        public override BitmapImage GetAssemblyImage() => AssemblyImage;
        private string _name;
        public override string AssemblyName
        {
            get { _name = AssemblyNames.{ModuleName}.ToString(); return _name; }
        }
        public override string GetAssemblyName() => AssemblyName;
        private string _group;
        public override string AssemblyGroup
        {
            get { _group = eAssemblyGroups.{GroupType}.ToString(); return _group; }
        }
        public override string GetAssemblyGroup() => AssemblyGroup;
        private eAssemblyRegion _region;
        public override eAssemblyRegion AssemblyRegion
        {
            get { _region = eAssemblyRegion.{ModuleName}Region; return _region; }
        }
        public override eAssemblyRegion GetAssemblyRegion() => AssemblyRegion;
    }
}

Examples from Codebase

Example 1: SensorsListModule

File: DataPRO/Modules/SensorsList/SensorsList/SensorsListModule.cs:22

[Module(ModuleName = "SensorsListModule")]
public class SensorsListModule : IModule
{
    private readonly IUnityContainer _unityContainer;

    public SensorsListModule(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public void Initialize()
    {
        _unityContainer.RegisterType<ISensorsListView, SensorsListView>();
        _unityContainer.RegisterType<ISensorsListViewModel, SensorsListViewModel>();
    }

    public void RegisterTypes(IContainerRegistry containerRegistry) => Initialize();
}

Example 2: GraphModule (DTS Viewer)

File: DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.Graph/GraphModule.cs:16

[Module(ModuleName = "Graph")]
public class GraphModule : IModule
{
    private readonly IUnityContainer _unityContainer;

    public GraphModule(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public void Initialize()
    {
        _unityContainer.RegisterType<IGraphView, GraphView>();
        _unityContainer.RegisterType<IGraphViewModel, GraphViewModel>();
    }
}

Example 3: Bootstrapper Registration

File: DataPRO/DataPRO/Bootstrapper.cs:179-220

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
    moduleCatalog.AddModule<StatusAndProgressBar.StatusAndProgressBarModule>();
    moduleCatalog.AddModule<DatabaseServices.DatabaseServicesModule>();
    moduleCatalog.AddModule<SensorsList.SensorsListModule>();
    // ... more modules
}

Common Mistakes to Avoid

  1. Forgetting to register module in Bootstrapper - Module won't load
  2. Not implementing both Initialize() and RegisterTypes() - Both are required for Prism 6+
  3. Missing assembly attributes - Module won't appear in UI tiles/menu
  4. Wrong eAssemblyGroups value - Module appears in wrong section
  5. Not using interface for View/ViewModel registration - Breaks testability and DI
  6. Singleton vs Transient - Use ContainerControlledLifetimeManager for singletons, otherwise default is transient
  7. Missing [Export(typeof(IModule))] - Required for MEF discovery in some scenarios