Exemplo n.º 1
0
        private bool ForcePrecedentCalculated(ExcelReference caller, Precedents precedents)
        {
            // Ensure that all precedents have been calculated, force calculation otherwise.
            foreach (ReferenceFunc rf in precedents.GetFormulas())
            {
                string funcName = rf.FuncName;
                if (knownAsyncFuncs_.Contains(funcName)) // Check that precedent is our known function, so we force its calculation if need.
                {
                    // We just check that our function has been calculated at the specified reference.
                    if (!calculatedFunctions_.Contains(rf))
                    {
                        ExcelReference precedent = rf.ExcelReference;

                        bool shouldForceCalculation = IsPrecedentCalcShouldForced(caller, precedent, funcName);
                        if (shouldForceCalculation)
                        {
                            if (!evalStates_.ContainsKey(precedent))
                            {
                                // Force evaluate precedent because we don't know its state.
                                ExcelAsyncUtil.QueueAsMacro(() => ForceFormulaEvaluate(precedent));
                            }
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Starts async UDF calculation.
        /// Returns Scheduled/Calculating or calculated value.
        /// Make sure calling UDF marked with IsMacroType=true.
        /// </summary>
        public object Calc(CallArguments args)
        {
            CheckFuncName(args);
            MarkUdfNonVolatile();
            ExcelReference caller;

            try
            {
                caller = GetCallerExcelReference();
            }
            catch (Exception e)
            {
                logService_.WriteError(
                    "Error getting reference. " +
                    FunctionLoggerHelper.LogParameters(args.FunctionName, null), e);
                // TODO Cleanup
                return("Error getting reference.");
            }

            if (IsNewEvaluationBatchStarted)
            {
                OnEvaluatingBatchStarted();
            }

            object[]      asyncKeyArgs  = GetAsyncKeyArgs(args.RawArgs, caller, batchStarted_);
            AsyncCallInfo asyncCallInfo = new AsyncCallInfo(args.FunctionName, asyncKeyArgs);

            if (!IsCalculatingTheSame(caller, asyncCallInfo) || IsScheduled(caller))
            {
                // Check simple case. Precedent is still calculating.
                Precedents precedents = caller.GetPrecedents();
                if (precedents.GetRefs().Any(IsCalculatingAny))
                {
                    SetEvalState(caller, EvalState.Scheduled, args, asyncCallInfo);
                    return(Scheduled);
                }

                if (ForcePrecedentCalculated(caller, precedents))
                {
                    SetEvalState(caller, EvalState.Scheduled, args, asyncCallInfo);
                    return(Scheduled);
                }
            }

            Validate(args);

            bool   isCalculating;
            object result = Observe(asyncKeyArgs, caller.XlfToReference(), args, out isCalculating);

            if (isCalculating)
            {
                // Async call to service scheduled.
                SetEvalState(caller, EvalState.ObservableCreated, args, asyncCallInfo);
                return(Calculating);
            }
            else
            {
                // Async call to service and result are ready.
                SetEvalState(caller, EvalState.ObservableFinished, args, asyncCallInfo);
                return(result);
            }
        }