ActiveReports 10 Extension for Visual Studio have designer for reports.
Designer windows contains tab "Preview" where designer report can be viewed without running whole application
I want create "testing" data which will be used only in design-time.
Setting data in the code works fine.
Private Sub TestReport_ReportStart(sender As Object, e As EventArgs) Handles Me.ReportStart
Me.DataSource = TestModule.GetData() ' - Test data
'Me.DataSource = _MyDataService.GetData() ' - Production data
End Sub
But after working with reports you need to remember remove testing data and set "production" code, which very easily can be forgotten.
It seems like "Preview"-code executing in run-time mode, see used testing code below
Private Sub TestReport_ReportStart(sender As Object, e As EventArgs) Handles Me.ReportStart
Dim isDebug As Boolean = System.Diagnostics.Debugger.IsAttached 'Return false
Dim mode As LicenseUsageMode = LicenseManager.UsageMode 'Return Runtime
End Sub
After some reading and tests I came up with two solutions for that problem.
Solution 1 - Assembly.GetEntryAssembly()
From MSDN:
Gets the process executable in the default application domain. In other application domains, this is the first executable that was executed by AppDomain.ExecuteAssembly.
Seems like "Preview" not running in the default application domain and ActiveReports not calling AppDomain.ExecuteAssembly()
. So method Assembly.GetEntryAssembly()
will return null
Public Class TestReport
Private _DataService As IDataService
Public Sub New(dataService As IDataService)
Me.InitializeComponent()
_DataService = dataService
End Sub
Private Sub Me_ReportStart(sender As Object, e As EventArgs) Handles Me.ReportStart
If Me.IsDesignMode = True Then
Me.DataSource = TestModule.GetData()
Else
Me.DataSource = _DataService.GetData()
End If
End Sub
Protected ReadOnly Property IsDesignMode As Boolean
Get
Return Assembly.GetEntryAssembly() Is Nothing
End Get
End Property
End Class
Solution 2 - Parameterless constructor
- Report class use interface IDataService
for getting data.
- Create implementation of IDataService
which return testing data
- Create parameterless constructor where original constructor which takes instance of IDataService
will be called with instance of testing implementation of interface as parameter.
- Mark parameterless constructor with Obsolete
attribute to tell other developers not use it
- Optional: use first solution here and throw exception if test data service was using in the run-time
Public Class TestReport
Private _DataService As IDataService
Public Sub New(dataService As IDataService)
Me.InitializeComponent()
_DataService = dataService
End Sub
<Obsolete("Parameterless consrtuctor only for designer usage.")>
Public Sub New()
MyClass.New(New TestDataService())
End Sub
Private Sub Me_ReportStart(sender As Object, e As EventArgs) Handles Me.ReportStart
Me.DataSource = _DataService.GetData()
End Sub
End Class
Public Class TestDataService
Implements IDataService
Public Sub New()
If Assembly.GetEntryAssembly() IsNot Nothing Then
Throw New InvalidOperationException("Service cannot be used in run-time")
End If
End Sub
Public Function GetData() As List(Of CustomItem) Implements IDataService.GetData
'Generate test data
End Function
End Class