Hi David,
Thank you very much for having a close look at the async / RxExcel
feature, and your detailed questions. If you find it useful, I hope
you'll be able to post a description or example somewhere of how you
are using it.
-----
I've made a check-in on CodePlex (change set 78811 here:
http://exceldna.codeplex.com/SourceControl/list/changesets ) that also
includes a fix for the RTD Disconnect issue under unpatched Excel
2010. I haven't tested it myself, but I believe it addresses the issue
completely, without too much overhead. Maybe you can check that this
version still works as you expect. If you have access to an unpatched
Excel 2010, some feedback on whether the fix works would be very
welcome. With this version you should always see the Disconnect /
Dispose call as expected, even under the buggy Excel 2010 release
version.
-----
As to your other issues: I agree with your description of the async /
ExcelObservable behaviour, but it's the best implementation I could
figure out given how Excel's RTD feature works. The behaviour you
describe is as expected.
1. The wrapper UDF is called for every update.
We have no control over when Excel calls the wrapper UDF - in
particular, for any RTD wrapper UDF Excel will always call the UDF
when the RTD value changes. In general, the UDF need not return the
value that the RTD Server provides, a feature that we use e.g. to
return strings longer than 255 characters. The ExcelAsyncUtil.Run and
ExcelAsyncUtil.Observe functions are written so that the extra calls
to the wrapper UDF are very lightweight, and in particular don't call
into your async function or observable at all. I can't imagine the
overhead of the extra calls being significant (unless you're doing
something like logging every call), but anyway we have no way to avoid
these calls.
The only way to eliminate the extra UDF call is to make a plain RTD
server (perhaps using Excel-DNA's thread-safe ExcelRtdServer base
class), doing the COM registration yourself, and then putting raw RTD
calls in the sheet, like =RTD("MyCool.DataSource",,"Close", "MSFT")
Otherwise Excel will always make the extra calls to the UDF.
2. The #N/A return before the first value.
Excel-DNA is does not 'send' the #N/A value to the cell, our UDF
wrapper must return *something*. I've chosen for the UDF wrapper to
return #N/A while the async call is outstanding / OnNext has not been
called. It's not easy for the UDF to wait for the first OnNext at that
point - it would basically have to suspend Excel completely until the
OnNext happens, which is not what we want at all.
Of course you can customize the wrapper UDF to return something other
than the #N/A value, or provide an immediate OnNext value of your
choice. But we need to return something from the UDF...
3. Mixing async / Observe with volatile functions doesn't work
Your example of MyFunction(TEXT(NOW(),"HH:mm:ss.sss")) is actually a
different case to the #N/A story above. Mixing async / observe
functions with volatile inputs will not work. Every call with a new
parameter would Dispose the observable and then create a new
observable (with the new parameters) which is subscribed to, followed
by an update to the UDF which repeats the cycle. Your UDF could ignore
the input parameter (just don't pass it to the ExcelAsyncUtil.Observe
call), but then you need some out-of-band way of dealing with changes
to the input value. The current implementation is quite general in
this regard.
With the normal use, where the input parameters are used to create the
observable, I can't think of a sensible way for volatile to mix with
async functions, and am happy if Excel does not crash in this case.
I'd say the perpetual '#N/A' in this case would be 'by design'.
-----
I hope my answer addresses these concerns, and look forward to some
more questions... :-)
Regards,
Govert
On Mar 6, 2:22 pm, DavidS <
dsh...@gmail.com> wrote:
> Hello Govert,
>
> With Excel 2010 SP1, my ExcelDna program now does call delete correctly. So
> it seems the reported bug was the problem. A great thanks! I suggest you
> just warn developers in the release notes rather than trying to workaround
> this Excel bug. The fix is easy (upgrade to SP1), but a workaround could be
> difficult and possibly break other functionality.
>
> More questions. I am looking at the debug output from my ExcelDna test
> program. I see that when I type my MyFunction() into Excel, first Excel
> calls MyFunction(), then an ExcelObservable object is created, then the
> observer subscribes. After that, data is sent to the subscriber using a
> task whick periodically calls OnNext(value). This seems to be what I would
> expect. However, each time after calling OnNext(value), Excel calls then
> MyFunction() again for every worksheet cell which contains MyFunction(). I
> wonder why this happens and whether it is necessary. I would expect that
> MyFunction() would only be called only when a MyFunction() is first typed
> into Excel or when the MyFunction(parameter) parameter changes. I have
> attached an image file showing the debug output. Please have a look at the
> middle section which shows what happens when there are three cells
> containing MyFunction().
>
> One more thing. When I type MyFunction() in a cell or change the
> MyFunction(parameter) parameter, first Excel calls MyFunction, then an
> ExcelObservable object is created, then the observer subscribes. At this
> point, since OnNext() has not yet been called, ExcelDna does not know the
> value to be returned to the cell, and ExcelDna returns "#NA". This behavior
> could especially cause problems with functions that take a date as
> parameter, like, for example MyFunction(TEXT(NOW(),"HH:mm:ss.sss")), which,
> will continually display "#NA". I think it would be better if ExcelDna did
> not send the first result ("#NA") to the cell until the next Rtd refresh
> (which defaults to every 2 seconds). Please have a look at the third
> section of the attached image which roughly shows at what point cells "#NA"
> is shown in cells.
>
> Thanks again for the help.
>
> Regards,
>
> David
>
> all.png
> 104KViewDownload