Добавление userform в другую книгу во время выполнения

у меня есть addin и открытая книга. В addin это .файл xlam и в книге я добавил ссылку на него. Этот файл защищен паролем.

можно запустить общедоступные методы добавления из моей книги. Однако один метод в addin использует VBA.UserForms.Add чтобы открыть пользовательскую форму, созданную во время выполнения такой

скажем, книга, которая содержит ссылку на myAddin это:

Private Sub callAddin()
    myAddin.ShowForm ThisWorkbook
End Sub

обычно, код в моем addin выглядит так:

Public Sub ShowForm(CallerWorkbook As Workbook)
    Const vbext_ct_MSForm As Long = 3

    'This is to stop screen flashing while creating form
    Application.VBE.MainWindow.Visible = False

    'Add to ThisWorkbook, not supplied workbook or VBE will crash - ignore CallerWorkbook
    Dim myForm As Object
    Set myForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)

    'Create the User Form
    With myForm
        .Properties("Caption") = "Select"
        .Properties("Width") = 300
        .Properties("Height") = 270
    End With

    'Show the form
    Dim finalForm As Object
    Set finalForm = VBA.UserForms.Add(myForm.Name)
    finalForm.Show

    'Remove form
    ThisWorkbook.VBProject.VBComponents.Remove myForm

End Sub

который отлично работает. Однако, когда мой addin защищен паролем, попытка добавить временную пользовательскую форму к нему не разрешена. Нет проблем, я просто добавляю временную форму пользователя в книгу, которая вызвала код, так как это не будет защищено паролем

Sub ShowForm(CallerWorkbook As Workbook)
    Const vbext_ct_MSForm As Long = 3

    'This is to stop screen flashing while creating form
    Application.VBE.MainWindow.Visible = False

    'Add to CallerWorkbook instead
    Dim myForm As Object
    Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)

    'Create the User Form
    With myForm
        .Properties("Caption") = "Select"
        .Properties("Width") = 300
        .Properties("Height") = 270
    End With

    'Show the form
    Dim finalForm As Object
    'Now myForm cannot be found and added
    Set finalForm = VBA.UserForms.Add(myForm.Name)
    finalForm.Show

    'Remove form
    CallerWorkbook.VBProject.VBComponents.Remove myForm

End Sub

однако VBA не может показаться посмотреть здесь myForm.Name указывает на now, поэтому метод Add не работает с "Run time error 424: Object required"

есть ли способ открыть форму созданного во время выполнения в другой книге?

1 ответов


проблема, с которой вы сталкиваетесь, заключается в том, что по умолчанию пользовательские формы создаются частным образом. Это означает, что проект не может ссылаться на пользовательскую форму в другом проекте, а если вы не можете ссылаться на форму, вы не можете вызвать ее Show метод.

код Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm) оператор возвращает VbComponent, а не UserForm, поэтому вы не можете использовать VBA.UserForms.Add(myForm.Name)

есть 2 способа обойти это:

1 - Создать PublicNotCreatable шаблон UserForm в вашем добавить-в

пользовательская форма похожа на класс, поэтому она может иметь свой Instancing набор свойств, как и класс. Однако VBE не выставляет Instancing свойство в окне Свойства для UserForms, поэтому для установки экземпляра необходимо экспортировать форму, а затем отредактировать Attribute VB_Exposed атрибут в файле FRM в текстовом редакторе перед повторным импортом формы. Вот шаги:

  • создайте пользовательскую форму с именем TemplateForm надстройки проект
  • удалить TemplateForm и выберите Экспорт формы перед ее удалением
  • открыть TemplateForm.frm файл в текстовом редакторе
  • изменить строку Attribute VB_Exposed = False так вот читает Attribute VB_Exposed = True
  • сохраните изменения в TemplateForm.frm
  • импорт TemplateForm.frm в надстройке
  • добавить публичную функцию, которая возвращает новый экземпляр TemplateForm для надстройки. Я заставил эту функцию принять ссылку на книгу, чтобы надстройка может настраивать любые свойства книги в форме:

    Public Function GetTemplateForm(CallerWorkbook As Workbook) As TemplateForm
      Dim frm As TemplateForm
      Set frm = New TemplateForm
      'Set early-bound properties with intellisense
      frm.Caption = "Select"
      frm.Width = 300
      frm.Height = 270
    
      'Configure CallerWorkbook specific form properties here
      '...
      Set GetTemplateForm = frm
    End Function
    
  • в книге пользователя, вы можете показать экземпляр TemplateForm, без необходимости динамически добавлять форму, или иметь дело с мерцанием экрана, или трудно отлаживать код:

    Sub ShowAddinForm()
        With MyAddin.GetTemplateForm(ThisWorkbook)
            'Do more workbook specific propery setting here...
            '...
            .Show
        End With
    End Sub
    

** Примечание-надстройка Rubberduck VBA скоро будет иметь возможность добавить PublicNotCreatable UserForm.

2 - есть надстройка создать пользовательскую форму компонент, но пусть книга пользователя управляет им

этот подход не так элегантен. Там гораздо больше кода для пользователя, чтобы управлять, и есть мерцание экрана, и трудно отлаживать код. Вот шаги:

  • добавьте этот код в надстройке:

    Public Function GetTempFormName(CallerWorkbook As Workbook) As String
        Const vbext_ct_MSForm As Long = 3
    
        'This is to stop screen flashing while creating form
        Application.VBE.MainWindow.Visible = False
    
        'Add to CallerWorkbook instead
        With CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
            .Properties("Caption") = "Select"
            .Properties("Width") = 300
            .Properties("Height") = 270
            GetTempFormName = .Name
        End With
    End Function
    
    Public Sub RemoveTempForm(CallerWorkbook As Workbook, FormName As String)
        With CallerWorkbook.VBProject.VBComponents
            Dim comp As Object
            Set comp = .Item(FormName)
            .Remove .Item(FormName)
        End With
    End Sub
    
  • потом, в книге пользователя, добавьте этот код:

    Sub GetAddinToCreateForm()
        Dim FormName As String
        FormName = MyAddin.GetTempFormName(ThisWorkbook)
        With VBA.UserForms.Add(FormName)
            .Show
        End With
        MyAddin.RemoveTempForm ThisWorkbook, FormName
    End Sub