Hi,
I'm trying to add a custom UltraCalcFunction (GetPrice) that's able to poll periodically for price updates based on an investment identifier in another column. The investment identifier isn't changing, but I need GetPrice() to evaluate periodically anyways in case the price in the price provider has changed.
I thought I could do this by overriding AlwaysDirty to always return true. But it appears that even if a function is AlwaysDirty, it doesn't always get recalculated on the next ultraCalcManager.ReCalc() run.
I've attached a small project that demonstrates the problem. To test this, I'm using the built-in now() function as well as a custom CurrentTime() function that basically returns DateTime.Now. The properties on the UltraCalcManager are all default (asynchronous calculations, freq=10 ms, duration=50ms).
Letting the application sit and run doesn't update either unbound column as I would have expected (since the calc manager should be recalcing every 10 ms). Explicitly calling UltraCalcManager.ReCalc() doesn't do anything either. I have to explicitly DirtyAllFormulas before calling ReCalc for it to work. DirtyAllFormulas is prohibitively expensive for my application because there're many other formulas that should not be dirtied.
Interestingly, changing the sort order triggers an update of the timestamps, but only the first time I change the sort order.
Separately from the above issue where IsAlwaysDirty doesn't seem to really make formulas dirty, I would appreciate any advice you have on how I can periodically poll. Let's say that I only want to poll using GetPrice() every 5 minutes. But I have other formulas that need to respond at a much higher freqency. So I can't just adjust the UltraCalcManager's frequency setting. If IsAlwaysDirty worked as I expect, I would be hammering my price provider many times every second.
I was thinking of tracking the last evaluation time and comparing that to the current time to determine if I should actually do anything in Evaluate. But that doesn't work because every call of Evaluate is made independently and I have no way of knowing that the last evaluation time was for my cell or for a different cell.
Then I thought of trying to check to see if the current time falls into the couple of seconds after the start of an arbitrary 5-minute interval. If so, I poll. Otherwise, I have to return some sort of cached result. I would prefer to not have to set up result caching and just abort the Evaluate, leaving the current value as is. But it appears that I have to always return something, so caching is the best solution that comes to mind.
The problem with the above approach is that if, for whatever reason (other calcs taking a long time?), the calcmanager's misses the small window where polling should occur, you're stuck waiting for another 5 minutes before another window opens. This seems unreliable. Lengthening the window might help, but that also increases the duration under which we're hammering the price provider.
Any suggestions?
Thanks in advance,
-- Yale
Hello Yale,
Thanks for provided information, Could you please try to upload your sample again, because I didn`t find it in the thread and I`ll try to reserach your issue.
Thanks in advance!
Regards
Oh, I guess that explains the error message the forum gave me. I thought it went through fine because my post made it.
Here's the sample project again.
Thanks.
The AlwaysDirty formulas are only dirtied when something else in the calc network is dirtied. They are not constantly dirtied on a timer or anything.
If you want a function to be constantly updated, then you will need to use a timer or something to constantly update it.
What I would probably do is - don't use a custom function. Instead, use a NamedReference and use a timer to set the Formula on the NamedReference to the new value at regular intervals.
I need to have a different Price for each row. NamedReferences aren't associated with controls, so can't be row-specific, right?
What I have done is added a NamedReference, but just so I have something that I can dirty using a timer. So if my custom function is AlwaysDirty, period dirtying of this dummy NamedReference gives it the kick it needs in order to recalculate.
But there're other timers running every 100ms that could possibly (but not always, so I need the NamedReference timer above) change data in the grid. So there could potentially be a dirtying of the calculation network every 100ms, which is much more frequent than I would like to hit my price provider. So I still have the problem I described in the second half of my original post where I want to exit Evaluate() and do nothing some of time. Is there any way to do that?
--yale
Hi Yale,
I'm afraid you lost me. Formulas can only be applied to a column, not a cell. So whether you use a Function or a NamedReference, you cannot apply a different value to each row, anyway.
I'm afraid I just don't understand what you are trying to do. It sounds to me like maybe what you need is to simply have an unbound column in the grid and populate that unbound column with a value and then reference that unbound column in your formula.
Hi Mike,
I have a grid with a bunch of rows. For each of those rows, I need to fetch a price based on parameters passed in from other cells in the row. I also need to be able to display this price and use it in other calculations. We've exposed the FormulaBuilder in our application. So I wanted to provide a custom formula to go get the price and the users can provider their own parameter mappings.
Because I want the formula to refresh periodically (but not every time anything changes in the calculation network), I've set the formula.IsAlwaysDirty to false. Then I add a NamedReference "timer". Then with a Timer, I periodically update the formula on the "timer" NamedReference to the tick count. Then I pass in "timer" as a parameter to my price formula so it would detect a change in the parameter and recalculate whenever the timer ticked.
I would prefer not to have to rig up this external Timer to trigger updates, but instead have a setting on the UltraCalcFormula (similiar to IsAlwaysDirty) that determines a refresh frequency. But it seems to be working.
I'm still not really clear on what the problem is.
yalewang said:I have a grid with a bunch of rows. For each of those rows, I need to fetch a price based on parameters passed in from other cells in the row. I also need to be able to display this price and use it in other calculations. We've exposed the FormulaBuilder in our application. So I wanted to provide a custom formula to go get the price and the users can provider their own parameter mappings.
If this value is calculated based on other cells in the row, then it should only change when some value in the row changes. So couldn't you use an unbound column in this row with a formula that references the other columns in the same row? The unbound column needn't be visible to the user if you don't want it to be. But it would still show up in the formula builder, even though it is hidden in the grid.
If the calculation relies on some external value that my change outside of the grid, then you could create a NamedReference which contains this literal value and updating it would update the grid cells that depend on it.
I'm still unclear on why you need a timer.
So you are saying that you have some external value which is involved in the calculation, and that there can be a completely different external value for each and every row in the grid? And that any of these values may change at any time and there's no way for the application to know about this change so it has to periodically poll the value for changes? Is that right?
If that's the case, then I suppose your solution of just dirtying a dummy NamedReference Formula to force the functions to recalculate is one way to handle it.
The calculation is more of a lookup in an external system. The parameters to the calculation are just parameters used to look up the price. So in order to pick up changes in the external system, I need to poll it once in a while. I can't use a NamedReference to store the prices because each row needs to look up its own price.