简体   繁体   English

访问VBA:如何订阅控件/字段的更改是由其他vba代码而不是用户交互引起的

[英]Access VBA: how to subscribe to a the change of a control/field happened from other vba code and not from user interaction

I'm in a weird situation. 我很奇怪。 I have a form with a subform. 我有一个带有子窗体的窗体。 When a value in the subform changes, in the after update I call 当子窗体中的值更改时,在更新后,我调用

If Not IsNull(Me.Parent) Then
   Me.Parent.ParentField.Value = Me.SubformField.Value
End If

In the parent form I want the change in ParentField to trigger another event. 在父窗体中,我希望ParentField的更改触发另一个事件。 Too bad that changing programmatically doesn't trigger either the AfterUpdate nor the onChange event. 不幸的是,以编程方式进行更改不会触发AfterUpdateonChange事件。

Since the same subform is used in more parent forms I can't call directly the method that is called on the afterUpdate 由于在更多父表单中使用了相同的子表单,因此我无法直接调用afterUpdate上调用的方法

Is there something else I can "subscribe" to? 还有什么我可以“订阅”的吗?

At least in Excel, this can be accomplished by adding a custom event to the sub userform, then adding the subuserform as an object in the parent userforms. 至少在Excel中,可以通过向子用户窗体添加自定义事件,然后将子用户窗体作为对象添加到父用户窗体中来实现。

I created a mock-up, shown below (the command button on the Parent Userform is primarily to hold the initial focus, as in this mock-up the sub form opens when the text box is entered): 我创建了一个模型,如下所示(“父用户”窗体上的命令按钮主要用于保持初始焦点,因为在此模型中,输入文本框后会打开子窗体):

子用户和父用户表单

'SubUserForm code
Option Explicit
'Custom Events don't have to pass values, or can pass multiple values as desired
Public Event FormChange(newValue As Variant)

Private Sub TextBoxS_Change()
    'If I wanted the event to raise for various control changes,
    '    I could add it to multiple Change Events.
    RaiseEvent FormChange(TextBoxS.Value)

    'Or I could instead call a private sub such as
    '        ConditionalEvent(TextBoxS.Value)
    '    with the logic for checking if the event should
    '    be raised; especially helpful if
    '    logic depends on multiple changes or conditions
End Sub

Private Sub ConditionalEvent(vNew As Variant)
    If True Then 'More complicated checks, maybe changed private variables, etc.
        RaiseEvent FormChange(vNew)
    End If
End Sub

'This is to prevent the parent losing refernce to the sub form.
'The parent should be the one that creates an instance of this form,
'   as well as be the one to delete it.
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    Cancel = True
    Me.Hide
End Sub

'Parent UserForm code
Option Explicit
'The private instance of the subform needs to be of the
'    baseform itself, not a generic object or userform.
'    Otherwise the custom event won't carry through.
'    However, this also means that the only events carried through
'    will be the custom ones (at least as far as I could tell)
Private WithEvents subForm As SubUserForm

'This is the custom event from the subform
Private Sub subForm_FormChange(newValue As Variant)
    TextBoxP.Value = newValue
End Sub

'This is important. The default value of subform is Nothing,
'    so initialization is required.
Private Sub UserForm_Initialize()
    Set subForm = New SubUserForm
End Sub

'This sub is the mock-up logic and call to show the sub form for testing.
'It is not required for using custom events.
Private Sub TextBoxP_Enter()
    subForm.Show
End Sub

Private Sub UserForm_Terminate()
    'Terminates the subform on parent closure
    Set subForm = Nothing
End Sub

For testing, I used the code below to show the parent userform. 为了进行测试,我使用下面的代码显示了父用户表单。 Please note I also changed the names of the TextBoxes and userforms like so: 请注意,我还更改了文本框和用户窗体的名称,如下所示:

  • Subform: SubUserForm , TextBoxS 子窗体: SubUserFormTextBoxS
  • ParentForm: ParentUserFrom , TextBoxP ParentForm: ParentUserFromTextBoxP

If any one wants to use the code mock-up, after creating the userforms, they will either need to change the names of the textboxes and userforms, or their references in the code. 如果有人想使用代码模型,则在创建用户表单后,他们将需要更改文本框和用户表单的名称,或在代码中对其的引用。

'In a generic module
Option Explicit

' Used to open the parent form for testing
Sub test()
    ' Using a with statement allows using a new instance of the form
    '    (instead of the "free instance" automatically provided)
    '    without having to assign the new instance to a variable to
    '    use, and then having to assign to variable to Nothing
    With New ParentUserForm
        .Show
    End With
End Sub

As a general rule, a controls events don't fire when changed by VBA. 通常,控件事件在由VBA更改时不会触发。 This makes sense, since a lot of events could occur for that control, and thus determining when and when not to have all those events run would be a nightmare. 这是有道理的,因为对该控件可能会发生很多事件,因此确定何时以及何时不运行所有这些事件将是一场噩梦。

However, you can most certainly call code and execute code in the parent form and have it run. 但是,您当然可以在父窗体中调用代码并执行代码并使其运行。

So if a button or some event code runs for a given control, simply have that event code call a public sub in the parent form. 因此,如果为给定控件运行按钮或某些事件代码,只需让该事件代码以父窗体形式调用公共子即可。

So button click, or after update could go: 因此,单击按钮,或在更新后可以进行以下操作:

Call MySub

MySub is simply a public sub that the button or event code calls in the main form. MySub只是按钮或事件代码在主窗体中调用的公共子项。

Now, in the sub form, you can go: 现在,在子表单中,您可以执行以下操作:

Me.Parent.ParentField.Value = me.SomeField

Call me.Parent.MySub()

And I suppose you could also use a Function, and go: 我想您也可以使用功能,然后执行以下操作:

My.Parent.MyFunctionToRun()

So setup a common routine (sub or function) in the parent form that the event code (or button) calls. 因此,以事件代码(或按钮)调用的父形式设置一个公共例程(子例程或函数)。 And then simply call that same routine as per above in the sub form. 然后,只需在子表单中调用与上述相同的例程即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM