如何检测代码是在设计时执行的?

How to detect that code is executed in design-time?

Visual Studio 的 ActiveReports 10 扩展有报表设计器。
设计器 windows 包含选项卡 "Preview",无需 运行 整个应用程序

即可在其中查看设计器报告

我想创建 "testing" 仅在设计时使用的数据。
在代码中设置数据工作正常。

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

但在使用报告后,您需要记住删除测试数据并设置 "production" 代码,这些代码很容易被遗忘。

似乎"Preview"-代码在运行-时间模式下执行,请参阅下面使用的测试代码

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

感谢您使用activereports。

目前,我不知道有什么方法可以在 AR10 中执行此操作。您可以在应用程序中使用配置参数来控制它,类似于 isDebug 设置,但使用 XML 配置代替。

此外,请给我们的支持团队发送电子邮件 http://activereports.grapecity.com,我们可以在未来的更新中添加一个设计时报告变量,您可以检查您的代码和查询。

经过一些阅读和测试后,我想出了两个解决该问题的方法。

解决方案 1 - Assembly.GetEntryAssembly()
来自 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.

似乎 "Preview" 未在默认应用程序域中 运行ning,并且 ActiveReports 未调用 AppDomain.ExecuteAssembly()。所以方法 Assembly.GetEntryAssembly() 将 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

解决方案 2 - 无参数构造函数
- 报告 class 使用接口 IDataService 获取数据。
- 创建 IDataService 的实现,其中 return 测试数据
- 创建无参数构造函数,其中采用 IDataService 实例的原始构造函数将以接口的测试实现实例作为参数调用。
- 使用 Obsolete 属性标记无参数构造函数以告诉其他开发人员不要使用它
- 可选:如果在 运行-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

法比奥,我玩过这个。

我发现 LicenseUsageMode 没有帮助。它 return 运行时在 IDE 中预览,如果 运行 通过编译的 exe(可以这么说,纯 运行 时间)。这是因为报告预览代码的结构。我们基本上在大部分情况下都会获取报告的副本并将其加载到预览中的查看器中,而无需考虑许可上下文。这就是为什么它给了 运行时间。

我也尝试使用进程名称来检查,当 运行 到 IDE 时,它给出了 vs exe 的名称:devenv 可以使用但有点不可靠,因为它可以手动更改为名称别的。

getEntryAssembly 在 运行 到 IDE 时执行 return NULL,我认为这是最可靠的。我还没有找到任何其他方法,但我认为一定有其他方法可以看出这种区别。

这是我在报告的格式事件中使用的代码片段

// ((这作为 IComponent).Site == null)
// 这对于通过设计器预览的纯 运行 时间 pr 都为真。

        // use licensemode usage.
        this.textBox1.Text += "LicenseUsageMode:   " + LicenseManager.UsageMode;

        this.textBox1.Text += "\r\n";

        // getEntryassembly
        if (System.Reflection.Assembly.GetEntryAssembly() == null)
            this.textBox1.Text += "GetEntryAssembly:   null";
        else
            this.textBox1.Text += "GetEntryAssembly:   NOT null";

        this.textBox1.Text += "\r\n";
        // System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe")
        this.textBox1.Text += "Process.GetCurrentProcess().ProcessName:   ";
        this.textBox1.Text += System.Diagnostics.Process.GetCurrentProcess().ProcessName ;
        this.textBox1.Text += "\r\n";

这给了我:

在 IDE 中预览时的 LicenseManger 值:LicenseManager.UsageMode 是运行时 在纯 运行 时间(例如单击按钮)预览时的 LicenseManger 值:LicenseManager.UsageMode 是运行时

在 IDE 中预览时的 getEntryassembly 值:空 在纯 运行 时间预览时的 getEntryassembly 值(例如单击按钮):NOT null

在 IDE 中预览时的进程名称值:devenv.exe(正如我上面提到的,有点不可靠) 在纯 运行 时间(例如单击按钮)预览时的进程名称值:NOT devenv.exe