Files
DP44/GLM5Analysis/PromptTemplates/AddNewReport.md
2026-04-17 14:55:32 -04:00

15 KiB

Add New Report - DataPRO Prompt Template

Context

DataPRO reports are implemented as Prism modules in two locations:

  • DataPRO/Modules/Reports/ - Full DataPRO reports
  • DTS 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:

  • ReportParameters
  • StartDate
  • EndDate
  • Threshold
  • Generate
  • ExportCSV
  • ExportExcel

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

  1. Two-View Pattern: Reports use separate Input and Output views
  2. ExportBase Inheritance: Export classes inherit from ExportBase
  3. ObservableCollection: Use for data binding in ViewModels
  4. DelegateCommand: Use Prism's DelegateCommand for ICommand implementation