"У меня есть пользовательская функция (= MyFunction ()), которую можно вызывать из листа Excel. Таким образом, у меня также есть кнопка меню, где мне нужно вызвать все функции, вызываемые для = MyFunction () , когда пользователь нажимает кнопку. "
Это легко сделать без создания кэша для хранения диапазона ячеек. Тем не менее, вы должны быть осторожны с методом расчета. Я полагаю, что приведенный ниже код гарантирует, что ваш диапазон всегда будет рассчитываться, но: (1) Если метод calc не является ручным, то Excel в конечном итоге контролирует то, что рассчитывается, когда и почему, поэтому он может пересчитать и другие ячейки. (2) Опять же, я верю, что это гарантирует пересчет всех ячеек с вашей функцией независимо от метода calc, но я не проверял приведенный ниже код для таблиц и полуавтоматического метода вычисления.
Код ниже предлагает два подхода:
(1) - Пересчитайте все ячейки, содержащие формулу: преимущество заключается в том, что вы пропускаете цикл и код в нем, недостатком является то, что вы можете принудительно пересчитать гораздо больше ячеек, чем вам действительно нужно.
(2) - Создайте интересующий диапазон и пересчитайте этот диапазон: недостатком является то, что построение этого диапазона может потребовать серьезных вычислительных усилий. Преимущество состоит в том, что если для метода calc задано ручное управление, я ВЕРИМ, что Excel будет только пересчитывать ячейку в этом диапазоне.
Полагаю, выбор зависит от конкретных деталей проблемы, которую нужно решить.
"Мой план состоит в том, чтобы внутри MyFunction () назначить ссылку на имя для вызывающей ячейки и сохранить ее в vba. Поэтому я мог бы иметь массив имен ячеек. Тогда я могу вызвать эти ссылки на ячейки, когда кнопка меню щелкнул ".
Если вы действительно хотите следовать этому подходу или если вам определенно необходимо создать кэш ячеек для цели, которую вы описываете, то это можно сделать и, хотя и элементарно, его можно даже построить таким образом, чтобы оно сохраняется между сессиями Excel. Тем не менее, это требует дополнительной работы, более продвинутого подхода, и это все еще будет довольно элементарно. ИМО, явное излишество для этой проблемы. Что еще хуже, вам придется вызывать код каждый раз при обновлении ячейки, чтобы гарантировать, что кэш обновляется, что может существенно повлиять на производительность. Что касается предложения GSerg: этот подход - как он сам упоминает - не дает вам никакого реального контроля над жизнью самого кэша. Это означает, что каждый раз, когда вы достигаете кеша, вам нужно будет проверить, уничтожил ли его Excel и, если это так, перестроить его.
Вывод: я бы порекомендовал вам не кэшировать ячейки. Вместо этого я бы посоветовал вам попытаться найти ячейки, которые необходимо пересчитать, по требованию, и принудительно пересчитать их наиболее оптимальным способом, который вы сможете найти для этого. Все еще не убежден? В этом случае используйте Application.Caller.Address
(см. Код ниже), чтобы получить адрес ячейки, вызывающей вашу функцию.
ЗАМЕЧАНИЕ: реализовано и протестировано в Excel 2003. Символы комментариев в стиле C # включены для форматирования.
Option Explicit
Public Sub ReEvaluateMyFunction()
On Error GoTo Handle_Exception
Dim targetCells As Range
Dim targetCell As Range
Dim rangeToRecalc As Range
/*'Workbook and worksheet names
'hard-coded for the example*/
Set targetCells = Application _
.Workbooks("Book1") _
.Worksheets("Sheet1").UsedRange _
.SpecialCells(xlCellTypeFormulas)
If targetCells Is Nothing Then Exit Sub
/*'You can narrow down the range if you know
'more about the function's return type, e.g.:
'.SpecialCells(xlCellTypeFormulas, xlNumbers)
'.SpecialCells(xlCellTypeFormulas, xlTextValues)
'OPTION 1: re-calculate all cells in the range
'Remark: unless calc method is set to "Manual", which
'should give you full control, I think there's no
'guarantee that other cells will not be recalculated*/
If Application.Calculation = xlCalculationManual Then
//'Use to force recalculation if calc mode is manual
targetCells.Calculate
Else
//'Use this to force recalculation in other cases
targetCells.Dirty
End If
Set targetCells = Nothing
Exit Sub
/*'OPTION 2: create a range specific to your
'function and recalculate that range*/
For Each targetCell In targetCells
If targetCell.Formula = "=MyFunction()" Then
If rangeToRecalc Is Nothing Then
Set rangeToRecalc = targetCell
Else
Set rangeToRecalc = Union(rangeToRecalc, targetCell)
End If
End If
Next targetCell
//'Same comments as before
If Application.Calculation = xlCalculationManual Then
rangeToRecalc.Calculate
Else
rangeToRecalc.Dirty
End If
Set rangeToRecalc = Nothing
Set targetCell = Nothing
Set targetCells = Nothing
Exit Sub
Handle_Exception:
Set rangeToRecalc = Nothing
Set targetCell = Nothing
Set targetCells = Nothing
MsgBox "An error has been found: " + Err.Description, vbCritical
End Sub
Public Function MyFunction() As String
MyFunction = Application.Caller.Address
End Function