显示依赖于变量的备用用户窗体

Display alternate UserForm dependent on variable

我想显示依赖于 UserName 环境变量的特定用户窗体。我在整个代码的不同地方更新了用户窗体,所以我认为创建两个独立的用户窗体(具有截然不同的设计)然后在代码。我显然在这里误解了一些东西,因为当它到达 .Show 命令时,VBA 错误:

Dim usrForm As UserForm

If Environ("UserName") = "redacted" Then
    Set usrForm = LlamaForm 'for specific user, form styled differently including picture of Llama
Else
    Set usrForm = NormalForm 'for EVERYONE ELSE, normal professional looking form
End If

With usrForm 'initialize UserForm and display wait message
    .Cancelbutton.Visible = False
    .Proceedbutton.Visible = False
    .Exitbutton.Visible = False 
    .labmsg.Caption = Chr(10) & Chr(10) & Chr(10) & "Starting background processes, please wait..."
    .Show vbModeless
End With

我是不是把它弄得太复杂了?我真的希望在开始时只更改引用的表单对象,而不是每次需要更新用户时都引入带有冗余代码的逻辑。任何想法或改进将不胜感激。需要注意的是,因为它们截然不同 layout/design,我 真的 喜欢保留两个单独的用户表单而不是操纵一个用户表单(我知道可以做到,但那是与理解为什么我的上述方法不起作用相比,此时需要做更多的工作。)

您可以使用通用对象,但您失去了早期绑定功能

试试这个代码

Option Explicit

Public Sub ShowUserForm()

    ' You can use a generic object, but you lose the early binding features
    Dim myUserForm As Object

    If Environ("UserName") = "redacted" Then
        Set myUserForm = New LlamaForm 
    Else
        Set myUserForm = New NormalForm 
    End If

    myUserForm.Show

End Sub

如果有效请告诉我

问题是负责显示表单的代码不应该关心任一表单上的任何控件。

出现错误 438,因为 UserForm class 没有 CancelButtonProceedButtonExitButtonlabmsg成员。

解决方案是 这些成员调用,使它们都反对 Object(或 Variant,但 Object 在这里更合适)。 ..或重新评估谁负责什么。

看起来你正在制作某种东西 progress indicator;当您开始需要可交换的对象组件时并且必须保持早期绑定,为此使用的正确工具是多态性,即接口。

链接的文章描述了如何制作一个可重用进度指示器,其工作代码与指示器表单完全分离。你需要的是类似的东西,除了文章末尾提到的你会想要 ProgressIndicatorForm LlamaIndicatorForm 来实现一些 IProgressView 接口,并将此 IProgressView 作为 ProgressIndicator class 的依赖项,而不是将其硬连接到初始化代码中。

困难的部分是设法在界面上公开进度指示器事件 - 这将需要正式的 ProgressIndicatorEvents class 来转发 ActivatedCancelled 事件到 ProgressIndicator class,类似于 this class 将事件从抽象视图转发到另一个组件。

做对了,你最终得到的调用代码如下所示:

Dim progressForm As IProgressView
If Environ$("username") = "redacted" Then
    Set progressForm = New LlamaProgressForm
Else
    Set progressForm = New StandardProgressForm
End If
With ProgressIndicator.Create("DoWork", Form:=progressForm)
    .Execute
End With

其中 DoWork 是您的 "worker code" - 可以是采用 ProgressIndicator 参数的任何 Sub 过程。

显然,这比仅针对 Object 编码要多得多,我不会责怪您采用简单的方法。但是如果学习新的编程概念比仅仅让它工作更重要的话,这里的原则非常值得研究。