Другой курс = новый ответ.
Несколько трудностей, которые я открыл для себя, которые могут оказаться полезными:
1. В UDF,возврат вызова RTD, подобный этому
' excel equivalent: =RTD("GeodesiX.RTD",,"status","Tokyo")
result = excel.WorksheetFunction.rtd( _
"GeodesiX.RTD", _
Nothing, _
"geocode", _
request, _
location)
ведет себя так, как будто вы вставили закомментированную функцию в ячейку, а НЕ значение, возвращаемое RTD.Другими словами, «результат» - это объект типа «вызов функции RTD», а не ответ RTD.И наоборот, делая это:
' excel equivalent: =RTD("GeodesiX.RTD",,"status","Tokyo")
result = excel.WorksheetFunction.rtd( _
"GeodesiX.RTD", _
Nothing, _
"geocode", _
request, _
location).ToDouble ' or ToString or whetever
возвращает действительное значение, эквивалентное вводу «3.1418» в ячейку.Это важное различие;в первом случае ячейка продолжает участвовать в питании RTD, во втором случае она просто получает постоянное значение.Это может быть решением для вас.
2. MS VSTO создает впечатление, что написание Office Addin - это очень просто ... до тех пор, пока вы на самом деле не попытаетесь создать промышленный продукт,распространяемое решение.Получение всех привилегий и полномочий для установки - это кошмар, и оно значительно ухудшается, если у вас есть блестящая идея поддержки более чем одной версии Excel.Я пользуюсь Addin Express уже несколько лет.Это скрывает всю эту злобу MS и позвольте мне сосредоточиться на кодировании моего аддина.Их поддержка тоже первоклассная, стоит посмотреть.(Нет, я не аффилирован или что-то в этом роде.)
3. Помните, что Excel может и будет вызывать Connect / RefreshData / RTD в любое время, даже когда вы находитесь всередина чего-то - за кулисами происходит какая-то тонкая многозадачность.Вам нужно будет украсить свой код соответствующими блоками Synclock, чтобы защитить свои структуры данных.
4. Когда вы получаете данные (предположительно асинхронно в отдельном потоке), вы абсолютноНЕОБХОДИМО обратный вызов Excel в потоке, в котором вы изначально были вызваны (Excel).Если вы этого не сделаете, какое-то время он будет работать нормально, а затем вы начнете получать таинственные, неразрешимые сбои и, что еще хуже, осиротелые Excels на фоне.Вот пример соответствующего кода для этого:
Imports System.Threading
...
Private _Context As SynchronizationContext = Nothing
...
Sub New
_Context = SynchronizationContext.Current
If _Context Is Nothing Then
_Context = New SynchronizationContext ' try valiantly to continue
End If
...
Private Delegate Sub CallBackDelegate(ByVal GeodesicCompleted)
Private Sub GeodesicComplete(ByVal query As Query) _
Handles geodesic.Completed ' Called by asynchronous thread
Dim cbd As New CallBackDelegate(AddressOf GeodesicCompleted)
_Context.Post(Function() cbd.DynamicInvoke(query), Nothing)
End Sub
Private Sub GeodesicCompleted(ByVal query As Query)
SyncLock query
If query.Status = "OK" Then
Select Case query.Type
Case Geodesics.Query.QueryType.Directions
GeodesicCompletedTravel(query)
Case Geodesics.Query.QueryType.Geocode
GeodesicCompletedGeocode(query)
End Select
End If
' If it's not resolved, it stays "queued",
' so as never to enter the queue again in this session
query.Queued = Not query.Resolved
End SyncLock
For Each topic As AddinExpress.RTD.ADXRTDTopic In query.Topics
AddinExpress.RTD.ADXRTDServerModule.CurrentInstance.UpdateTopic(topic)
Next
End Sub
5. Я сделал что-то вроде того, что вы просите в этом дополнении ,Там я асинхронно извлекаю данные геокодирования из Google и подаю их с RTD, скрытым UDF.Поскольку звонок в GoogleMaps очень дорогой, я попробовал 101 способ и несколько месяцев по вечерам, чтобы сохранить значение в ячейке, как то, что вы пытаетесь, безуспешно.Я ничего не рассчитывал, но мое внутреннее чувство таково, что вызов Excel, такой как «Application.Caller.Value», на порядок медленнее, чем поиск по словарю.
В конце я создал компонент кэшакоторый сохраняет и повторно загружает значения, уже полученные из очень скрытой электронной таблицы, которую я создаю на лету в Workbook OnSave.Данные хранятся в словаре (строки, myQuery), где каждый myQuery содержит всю необходимую информацию.
Он работает хорошо, отвечает требованиям для работы в автономном режиме и даже для формул 20'000 + он появляется мгновенно.
HTH.
Редактировать: Из любопытства я проверил, что вызов Excel является гораздо более дорогим, чем поиск по словарю.Оказывается, не только догадка была правильной, но пугающе такой.
Public Sub TimeTest()
Dim sw As New Stopwatch
Dim row As Integer
Dim val As Object
Dim sheet As Microsoft.Office.Interop.Excel.Worksheet
Dim dict As New Dictionary(Of Integer, Integer)
Const iterations As Integer = 100000
Const elements As Integer = 10000
For i = 1 To elements + 1
dict.Add(i, i)
Next
sheet = _ExcelWorkbook.ActiveSheet
sw.Reset()
sw.Start()
For i As Integer = 1 To iterations
row = 1 + Rnd() * elements
Next
sw.Stop()
Debug.WriteLine("Empty loop " & (sw.ElapsedMilliseconds * 1000) / iterations & " uS")
sw.Reset()
sw.Start()
For i As Integer = 1 To iterations
row = 1 + Rnd() * elements
val = sheet.Cells(row, 1).value
Next
sw.Stop()
Debug.WriteLine("Get cell value " & (sw.ElapsedMilliseconds * 1000) / iterations & " uS")
sw.Reset()
sw.Start()
For i As Integer = 1 To iterations
row = 1 + Rnd() * elements
val = dict(row)
Next
sw.Stop()
Debug.WriteLine("Get dict value " & (sw.ElapsedMilliseconds * 1000) / iterations & " uS")
End Sub
Результаты:
Empty loop 0.07 uS
Get cell value 899.77 uS
Get dict value 0.15 uS
Поиск значения в словаре из 10'000 элементов (Of Integer,Integer) на в 11000 раз быстрее , чем выборка значения ячейки из Excel.
QED