Необходимо остановить пересчет пользовательских функций при удалении несвязанных ячеек.

Я заметил, что мои пользовательские функции пересчитываются всякий раз, когда я удаляю ячейки. Это приводит к значительным задержкам при удалении целых столбцов, потому что UDF вызывается для каждой ячейки, в которой он используется. Таким образом, если вы используете 1000 UDFS, то удаление столбца или ячейки вызовет его 1000 раз.

Например, поместите следующий UDF в модуль, а затем несколько раз вызовите его из рабочего листа с помощью =HelloWorld().

Function HelloWorld()
HelloWorld = "HelloWorld"
Debug.Print Now()
End Function

Затем удалите строку. Если ваш опыт подобен моему, вы увидите, что он вызывается один раз для каждого случая использования.

У кого-нибудь есть идеи, можно ли остановить это поведение? Мне также было бы интересно, почему это должно вызываться. Мне это кажется недостатком в дереве зависимостей Excel, но вполне может быть веская причина.

Изменить: после экспериментов я нашел больше действий, которые запускают UDFS:

  1. Any change to the number of columns that a ListObject (i.e. Excel Table) spans through resizing (but not rows). Even if the UDFs themselves aren't in the ListObject concerned, or in fact in any ListObject at all.
    1. Adding new cells or columns anywhere in the sheet (but not rows).

Обратите внимание, что режим ручного расчета недоступен по нескольким направлениям.

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

Во-вторых, я на самом деле не разрабатываю конкретную электронную таблицу, а скорее пишу книгу о том, как не являющиеся разработчиками могут использовать хорошо написанный готовый код, такой как UDF, для выполнения задач, которые в противном случае были бы им недоступны. Примеры включают динамическое объединение или разделение текста или пользовательскую функцию точного совпадения бинарного поиска, которую Чарльз Уильямс описывает по адресу https://fastexcel.wordpress.com/2011/07/22/developing-faster-lookups-part-2.-how-to-build-a-faster-vba-lookup/ (И да, я предупреждаю их, что обычно собственное решение на основе формул превосходит UDF. Но, как вы увидите из темы, которую я упоминалось выше, тщательно написанные функции могут работать хорошо).

Я не знаю, как пользователи будут их использовать.

В отсутствие решения для программирования, похоже, мне просто придется указать в книге, что пользователи могут испытывать значительные задержки при добавлении или удалении ячеек или изменении размера ListObjects, если они используют ресурсоемкую UDFS. Даже если эти UDF написаны эффективно.


person jeffreyweir    schedule 23.04.2015    source источник
comment
dicks blog встречает stackoverflow :) Интересный вопрос, поскольку я подтверждаю, что это верно, даже если ваш UDF не имеет связанного диапазона ячеек, изменчивой функции в сочетании с ним или Application.Volatile. Простое очищение содержимого не запускает UDF, а удаляет строку. Я с интересом буду ждать сообщения от Чарльза Уильямса.   -  person brettdj    schedule 23.04.2015
comment
Вы пытались установить метод расчета Excel на ручной. Режим ручного расчета означает, что Excel будет пересчитывать все открытые книги только тогда, когда вы запросите это, нажав F9 или Ctrl-Alt-F9, или когда вы сохраните книгу. Для рабочих книг, для пересчета которых требуется более доли секунды, обычно лучше установить для параметра «Вычисление» значение «Вручную».   -  person izzymo    schedule 23.04.2015
comment
Привет, Иззимо. Я избегаю режима ручного расчета, когда это возможно, по следующим причинам: * Возможность использования вывода без обновления модели. Я вообще не единственный пользователь. * Если первая рабочая книга, открытая вами в течение дня, была сохранена в режиме ручного расчета, то все остальные рабочие книги, которые вы открываете в течение дня, также будут переключены в режим ручного расчета. Возможно, даже без вашего ведома. Часто ручной режим расчета используется для маскировки признаков плохо спроектированной электронной таблицы. Не во всех случаях, и я не говорю, что все плохо. Просто в основном можно избежать.   -  person jeffreyweir    schedule 23.04.2015


Ответы (2)


К сожалению, я не верю, что можно предотвратить пересчет UDF при удалении «несвязанных» ячеек. Причина этого в том, что аргумент, передаваемый в UDF, на самом деле является объектом Range (а не просто значением в ячейке(ях)). Удаление «несвязанных» ячеек может фактически изменить файл Range.

Например, пользователи могут написать такую ​​UDF:

Function func1(rng)
    func1 = rng.Address & " (" & Format(Now, "hh:mm:ss") & ")"
End Function

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

Здесь я просто возвращаю адрес аргумента. Я также добавляю метку времени, чтобы сигнализировать о пересчете UDF. Если вы удалите какой-либо столбец на листе, все ячейки с этой пользовательской функцией будут пересчитаны. Но не в том случае, если вы вставите столбец, оставив ячейки справа (от этого нового столбца) без изменений и с неправильным значением (адресом ячейки). Результаты те же, что и при вставке/удалении строк. Как ни странно, вставка одной ячейки приводит к пересчету всех пользовательских функций.

Я попытался удалить «зависимость» от файла Range. Но поведение такое же, даже если аргумент UDF имеет тип as double (вместо того, чтобы оставить его как Variant, как в моем примере).

Как вы объяснили, удаление столбца приведет к пересчету UDF. Это имеет смысл, поскольку UDF может зависеть от аргумента Range. Другой вопрос, является ли это умным дизайном для UDF.

person bouvierr    schedule 23.04.2015
comment
re your comment ** Причина этого в том, что аргумент, переданный в UDF, на самом деле является диапазоном **: моя простая функция вообще не передает никаких аргументов. Поэтому я не понимаю, почему Excel нужно было бы пересчитывать его. - person jeffreyweir; 24.04.2015
comment
@jeffreyweir: Да, ты прав. Я имел в виду, что UDF может зависеть от аргумента Range. Похоже, что разработчики решили (к сожалению) обновить все UDF вместо обновления только тех, у которых есть Range аргументов (т. е. тех, которые могут потребовать обновления после удаления столбца). - person bouvierr; 24.04.2015

Вставка или удаление строки, столбца или ячейки всегда вызывает перерасчет в автоматическом режиме. (Вы можете проверить это, добавив =NOW() в пустую книгу и вставив или удалив что-то)


Вопрос должен заключаться в том, какие (непредвиденные) обстоятельства помечают ячейку как грязную, чтобы она была пересчитана. Существует (возможно, неполный) список таких вещей на http://www.decisionmodels.com/calcsecretsi.htm.

Похоже, мне нужно добавить несколько слов о пользовательских функциях VBA (не проверял пользовательские функции XLL
- они могут вести себя по-разному, поскольку они зарегистрированы по-другому, чем пользовательские функции VBA)

person Charles Williams    schedule 23.04.2015