Есть ли способ вызвать процедуру события BeforeUpdate любого элемента управления в VBA (MS Access 2002 или 2003)? - PullRequest
3 голосов
/ 28 мая 2009

В VBA я меняю значение нескольких элементов управления в форме доступа. Мне нравится запускать события BeforeUpdate этих элементов управления после этого, так как он проверяет согласованность между полями:

Private Sub ExampleProc1()
  Dim intCancel as Integer

  intCancel = False

  Me.Controls("Date1").Value=Null
  Me.Controls("Textfield1").Value=Null

  Call Date1_BeforeUpdate(intCancel)
  Call Textfield1_BeforeUpdate(intCancel)
End Sub

Я бы хотел сделать его общим, но не могу найти способ запустить процедуру события. Я хотел бы что-то вроде этого:

Private Sub ExampleProc2(ParamArray Fields())
  Dim intCancel as Integer, varV as Variant

  For Each varV in Fields
    Me.Controls(varV).value=Null
    intCancel = False
    Call Me.Controls(varV).BeforeUpdate(intCancel)
  Next
End Sub

Это вообще возможно? Может быть, что-то с DoCmd.RunMacro это путь?

Ответы [ 4 ]

3 голосов
/ 28 мая 2009

На самом деле вы можете сделать это, используя CallByName

CallByName Me, Me.Controls(varV).Name & "_BeforeUpdate", VbMethod, intCancel
1 голос
/ 29 мая 2009

Возможно, вы захотите изучить создание пользовательских коллекций, а затем передать их своим функциям. Я широко использую их в формах для проверки контроля. Скажем, на уровне модуля формы вы определили эту коллекцию:

  Dim mcolDateFields As New Collection

Тогда в событии OnLoad вашей формы вы можете сделать это:

  mcolDateFields.Add Me!txtDateEntered, "txtDateEntered"
  mcolDateFields.Add Me!txtDatePrinted, "txtDatePrinted"
  mcolDateFields.Add Me!txtDateArchived, "txtDateArchived"

Чтобы просмотреть эту коллекцию, вы должны сделать что-то вроде этого:

  Dim varItem As Variant
  Dim ctl As Control

  For Each varItem In mcolDateFields
    Set ctl = varItem
    Debug.Print ctl.Name & ": " & ctl.Value
  Next varItem
  Set ctl = Nothing

... где вы бы заменили Debug.Print чем-то действительно полезным.

Затем вы также можете передать элемент управления другим подпрограммам кода, которые принимают коллекцию в качестве параметра и что-то с ней делают:

  Public Sub (mcolCollection As Collection)
    Dim varItem As Variant
    Dim ctl As Control

    For Each varItem In mcolCollection 
      Set ctl = varItem
      Debug.Print ctl.Name & ": " & ctl.Value
    Next varItem
    Set ctl = Nothing
  End Sub

Это может позволить вам передать коллекцию элементов управления, которые вы хотите проверить. Поскольку в вашей коллекции хранятся контрольные ссылки, а не контрольные имена или контрольные значения, нет необходимости передавать имя родительской формы. Если вам это нужно, вы можете получить это с помощью:

  Dim varItem As Variant
  Dim ctl As Control

  For Each varItem In mcolCollection 
    Set ctl = varItem
    Debug.Print ctl.Parent.Name & "!" & ctl.Name & ": " & ctl.Value
  Next varItem
  Set ctl = Nothing

Аналогичным образом, если вы хотите использовать форму таким же образом, как и ключевое слово Me в собственном модуле формы, просто используйте ctl.Parent, который возвращает ссылку на форму, если элемент управления находится в самой форме ( а не, скажем, на вкладке управления).

Некоторые комментарии к вашим примерам кода - ваш первый выглядит так:

  Private Sub ExampleProc1()
    Dim intCancel as Integer

    intCancel = False

    Me.Controls("Date1").Value=Null
    Me.Controls("Textfield1").Value=Null

    Call Date1_BeforeUpdate(intCancel)
    Call Textfield1_BeforeUpdate(intCancel)
  End Sub

Хотя оно определяется как целое число при создании отменяемого события, на самом деле это совсем не так - это логическое значение, и для отмены события вы должны установить его равным True (-1). Я думаю, что это на самом деле удержание в Access VBA со времен Access до VBA, когда в Access Basic отсутствовал логический тип данных. В общем случае я использую логические значения только для переменных, используемых с параметром Cancel.

  Me.Controls("Date1").Value=Null

Я не знаю, почему ты так поступил. Я бы написал это так:

  Me!Date1 = Null

Ваш код слишком многословен, так как вы дважды указали значения по умолчанию: коллекция Controls является коллекцией формы по умолчанию. На самом деле коллекция по умолчанию представляет собой конкатенацию коллекций Controls и Fields, поэтому могут быть веские причины для указания того, что вы хотите использовать элемент управления, например, если вы используете свойство элемента управления, которого нет в соответствующем поле. Но для манипулирования значениями, если есть элемент управления с тем же именем, что и у поля, не имеет значения, какое значение вы используете, поскольку они будут идентичны, за исключением крайне маловероятного события, когда элемент управления фактически не привязан к полю с таким же именем.

Аналогично, .Value является свойством по умолчанию для элементов управления, поэтому нет никаких оснований указывать его. Единственные обстоятельства, при которых вы можете захотеть это сделать, - это если вы используете его в качестве параметра для вызова другой подпрограммы, где параметром является ByRef, а не ByVal. Но в целом, просто присвоить значение элементу управления, это пустая трата ввода.

Чтобы сделать то, что вы пытаетесь достичь, сбор контрольных ссылок кажется мне хорошим решением. Я не знаю, должны ли события для этих элементов управления быть публичными или нет.

1 голос
/ 28 мая 2009

Вы можете подумать, чтобы рассмотреть Run (http://msdn.microsoft.com/en-us/library/aa199108(office.10).aspx) и Eval Function:

Debug.Print Eval("ShowNames()")    
Debug.Print Eval("StrComp(""Joe"",""joe"", 1)")
Debug.Print Eval("Date()")
0 голосов
/ 28 мая 2009

Очевидно, что в Access можно сделать CallByName, но вы также можете поместить логику BeforeUpdate для всех ваших элементов управления в централизованную подпрограмму, изменяя ее поведение в зависимости от параметров, которые вы передаете. Тогда все, что у вас будет в обработчиках событий BeforeUpdate, - это вызов вашей централизованной подпрограммы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...