15 KiB
Add New Report - DataPRO Prompt Template
Context
DataPRO reports are implemented as Prism modules in two locations:
DataPRO/Modules/Reports/- Full DataPRO reportsDTS Viewer/DTS.Viewer.Reports/- Viewer-specific reports
Reports follow MVVM with separate Input and Output views for parameter collection and results display.
System Architecture
DataPRO/Modules/Reports/PedestrianAndHeadReports/
├── Classes/ # Report generation logic
│ ├── ReportBase.cs # Base class for reports
│ ├── ExportBase.cs # Export functionality
│ └── {ReportName}Export.cs # Specific export logic
├── View/
│ ├── {ReportName}InputView.xaml # Parameter input UI
│ └── {ReportName}OutputView.xaml # Results display UI
├── ViewModel/
│ └── {ReportName}ViewModel.cs
├── Resources/ # Localization
└── {ReportName}Module.cs # Module registration
Step-by-Step Instructions
1. Create the Report Module Class
File: DataPRO/Modules/Reports/{ReportName}/{ReportName}Module.cs
using System;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using DTS.Common;
using DTS.Common.Interface;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
namespace {REPORT_NAME}
{
[Export(typeof(IModule))]
[Module(ModuleName = "{REPORT_NAME}Module")]
public class {REPORT_NAME}Module : IModule
{
private readonly IUnityContainer _unityContainer;
public {REPORT_NAME}Module(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public void Initialize()
{
_unityContainer.RegisterType<I{REPORT_NAME}InputView, {REPORT_NAME}InputView>();
_unityContainer.RegisterType<I{REPORT_NAME}OutputView, {REPORT_NAME}OutputView>();
_unityContainer.RegisterType<I{REPORT_NAME}ViewModel, {REPORT_NAME}ViewModel>();
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class {REPORT_NAME}ImageAttribute : ImageAttribute
{
private BitmapImage _img;
public {REPORT_NAME}ImageAttribute() : this(null) { }
public override BitmapImage AssemblyImage
{
get { _img = AssemblyInfo.GetImage(AssemblyNames.DB.ToString()); return _img; }
}
public {REPORT_NAME}ImageAttribute(string s)
{
_img = AssemblyInfo.GetImage(AssemblyNames.DB.ToString());
}
public override Type GetAttributeType() => typeof(ImageAttribute);
public override BitmapImage GetAssemblyImage() => AssemblyImage;
private string _name;
public override string AssemblyName
{
get { _name = AssemblyNames.{REPORT_GROUP}.ToString(); return _name; }
}
public override string GetAssemblyName() => AssemblyName;
private string _group;
public override string AssemblyGroup
{
get { _group = eAssemblyGroups.Administrative.ToString(); return _group; }
}
public override string GetAssemblyGroup() => AssemblyGroup;
public override eAssemblyRegion GetAssemblyRegion()
{
throw new NotImplementedException();
}
public override eAssemblyRegion AssemblyRegion => throw new NotImplementedException();
}
}
2. Create the Report Base Class
File: DataPRO/Modules/Reports/{ReportName}/Classes/{ReportName}.cs
using System;
using System.Collections.Generic;
using DTS.Common.Storage;
namespace {REPORT_NAME}
{
public class {REPORT_NAME}Report
{
public string ReportTitle { get; set; }
public DateTime GeneratedDate { get; set; }
public List<ReportChannel> Channels { get; set; }
public {REPORT_NAME}Report()
{
Channels = new List<ReportChannel>();
GeneratedDate = DateTime.Now;
}
public void Generate(TestSetup testSetup, ReportParameters parameters)
{
// Validate inputs
if (testSetup == null)
throw new ArgumentNullException(nameof(testSetup));
// Generate report data
ProcessData(testSetup, parameters);
}
private void ProcessData(TestSetup testSetup, ReportParameters parameters)
{
// Implementation specific to report type
}
}
public class ReportChannel
{
public string ChannelName { get; set; }
public double PeakValue { get; set; }
public double Duration { get; set; }
}
public class ReportParameters
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public double Threshold { get; set; }
}
}
3. Create the Export Class
File: DataPRO/Modules/Reports/{ReportName}/Classes/{ReportName}Export.cs
using System;
using System.Data;
using System.IO;
using DTS.Common.Storage;
namespace {REPORT_NAME}
{
public class {REPORT_NAME}Export : ExportBase
{
public {REPORT_NAME}Report Report { get; set; }
public void ExportToCSV(string filePath)
{
if (Report == null)
throw new InvalidOperationException("Report not generated");
using (var writer = new StreamWriter(filePath))
{
WriteHeader(writer);
WriteData(writer);
}
}
public void ExportToExcel(string filePath)
{
// Excel export implementation
}
private void WriteHeader(StreamWriter writer)
{
writer.WriteLine($"Report,{Report.ReportTitle}");
writer.WriteLine($"Generated,{Report.GeneratedDate:yyyy-MM-dd HH:mm:ss}");
writer.WriteLine();
writer.WriteLine("Channel,Peak Value,Duration");
}
private void WriteData(StreamWriter writer)
{
foreach (var channel in Report.Channels)
{
writer.WriteLine($"{channel.ChannelName},{channel.PeakValue},{channel.Duration}");
}
}
}
}
4. Create Input View (XAML)
File: DataPRO/Modules/Reports/{ReportName}/View/{ReportName}InputView.xaml
<UserControl x:Class="{REPORT_NAME}.{REPORT_NAME}InputView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:resx="clr-namespace:{REPORT_NAME}.Resources">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{x:Static resx:StringResources.ReportParameters}"
Style="{StaticResource HeaderStyle}"/>
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="5">
<DatePicker SelectedDate="{Binding StartDate, Mode=TwoWay}"
Header="{x:Static resx:StringResources.StartDate}"/>
<DatePicker SelectedDate="{Binding EndDate, Mode=TwoWay}"
Header="{x:Static resx:StringResources.EndDate}"/>
<TextBox Text="{Binding Threshold, Mode=TwoWay}"
Header="{x:Static resx:StringResources.Threshold}"/>
</StackPanel>
<Button Grid.Row="2" Content="{x:Static resx:StringResources.Generate}"
Command="{Binding GenerateCommand}"
HorizontalAlignment="Right" Margin="5"/>
</Grid>
</UserControl>
5. Create Output View (XAML)
File: DataPRO/Modules/Reports/{ReportName}/View/{ReportName}OutputView.xaml
<UserControl x:Class="{REPORT_NAME}.{REPORT_NAME}OutputView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:resx="clr-namespace:{REPORT_NAME}.Resources">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding ReportTitle}"
Style="{StaticResource HeaderStyle}"/>
<DataGrid Grid.Row="1" ItemsSource="{Binding ReportData}"
AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Channel" Binding="{Binding ChannelName}"/>
<DataGridTextColumn Header="Peak Value" Binding="{Binding PeakValue}"/>
<DataGridTextColumn Header="Duration" Binding="{Binding Duration}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="{x:Static resx:StringResources.ExportCSV}"
Command="{Binding ExportCSVCommand}" Margin="5"/>
<Button Content="{x:Static resx:StringResources.ExportExcel}"
Command="{Binding ExportExcelCommand}" Margin="5"/>
</StackPanel>
</Grid>
</UserControl>
6. Create the ViewModel
File: DataPRO/Modules/Reports/{ReportName}/ViewModel/{ReportName}ViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Windows.Input;
using DTS.Common.Interface;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
namespace {REPORT_NAME}
{
public class {REPORT_NAME}ViewModel : I{REPORT_NAME}ViewModel, INotifyPropertyChanged
{
private readonly IUnityContainer _unityContainer;
public I{REPORT_NAME}InputView InputView { get; set; }
public I{REPORT_NAME}OutputView OutputView { get; set; }
private DateTime _startDate;
public DateTime StartDate
{
get => _startDate;
set { _startDate = value; OnPropertyChanged(nameof(StartDate)); }
}
private DateTime _endDate;
public DateTime EndDate
{
get => _endDate;
set { _endDate = value; OnPropertyChanged(nameof(EndDate)); }
}
private double _threshold;
public double Threshold
{
get => _threshold;
set { _threshold = value; OnPropertyChanged(nameof(Threshold)); }
}
public ObservableCollection<ReportChannel> ReportData { get; set; }
public ICommand GenerateCommand { get; }
public ICommand ExportCSVCommand { get; }
public ICommand ExportExcelCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public {REPORT_NAME}ViewModel(
I{REPORT_NAME}InputView inputView,
I{REPORT_NAME}OutputView outputView,
IUnityContainer unityContainer)
{
InputView = inputView;
InputView.DataContext = this;
OutputView = outputView;
OutputView.DataContext = this;
_unityContainer = unityContainer;
ReportData = new ObservableCollection<ReportChannel>();
GenerateCommand = new DelegateCommand(OnGenerate);
ExportCSVCommand = new DelegateCommand(OnExportCSV);
ExportExcelCommand = new DelegateCommand(OnExportExcel);
InitializeDefaults();
}
private void InitializeDefaults()
{
StartDate = DateTime.Now.AddDays(-7);
EndDate = DateTime.Now;
Threshold = 0.0;
}
private void OnGenerate()
{
// Generate report logic
var report = new {REPORT_NAME}Report();
// ... generate data
}
private void OnExportCSV()
{
// Export to CSV
}
private void OnExportExcel()
{
// Export to Excel
}
}
}
7. Add Localization Resources
File: DataPRO/Modules/Reports/{ReportName}/Resources/StringResources.resx
Add required strings:
ReportParametersStartDateEndDateThresholdGenerateExportCSVExportExcel
For DTS Viewer Reports
If creating a Viewer report, use this location:
DTS Viewer/DTS.Viewer.Reports/DTS.Viewer.{ReportName}/
The module class differs slightly:
[Module(ModuleName = "{REPORT_NAME}")]
public class {REPORT_NAME}Module : I{REPORT_NAME}Module
{
public bool SessionStarted { get; private set; }
public void StartSession()
{
var eventAggregator = _unityContainer.Resolve<IEventAggregator>();
eventAggregator.GetEvent<LoadViewModulEvent>().Publish(new LoadViewModulArg());
SessionStarted = true;
}
}
Files to Create Summary
| File | Action |
|---|---|
{ReportName}/{ReportName}Module.cs |
Create |
{ReportName}/Classes/{ReportName}.cs |
Create |
{ReportName}/Classes/{ReportName}Export.cs |
Create |
{ReportName}/View/{ReportName}InputView.xaml |
Create |
{ReportName}/View/{ReportName}InputView.xaml.cs |
Create |
{ReportName}/View/{ReportName}OutputView.xaml |
Create |
{ReportName}/View/{ReportName}OutputView.xaml.cs |
Create |
{ReportName}/ViewModel/{ReportName}ViewModel.cs |
Create |
{ReportName}/Resources/StringResources.resx |
Create |
DTS.Common/Interface/{ReportName}Interfaces.cs |
Create |
Validation Checklist
- Module registered with
[Module]attribute - Assembly image attribute defined
- Input/Output views follow naming convention
- ViewModel implements
INotifyPropertyChanged - Commands use
DelegateCommandfrom Prism - Export methods handle file I/O properly
- Localization strings for all UI text
- Report generation validates inputs
- Error handling implemented
- Assembly group set appropriately (
eAssemblyGroups.Administrative)
Common Patterns
- Two-View Pattern: Reports use separate Input and Output views
- ExportBase Inheritance: Export classes inherit from
ExportBase - ObservableCollection: Use for data binding in ViewModels
- DelegateCommand: Use Prism's
DelegateCommandfor ICommand implementation