188 lines
6.1 KiB
Markdown
188 lines
6.1 KiB
Markdown
# 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()`:
|
|
```csharp
|
|
moduleCatalog.AddModule<{ModuleName}.{ModuleClass}>();
|
|
```
|
|
|
|
## Code Template
|
|
|
|
### Module Class (`{ModuleName}Module.cs`)
|
|
```csharp
|
|
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`
|
|
```csharp
|
|
[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`
|
|
```csharp
|
|
[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`
|
|
```csharp
|
|
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
|