Пример #1
0
 public void Unsubscribe()
 {
     Debug.Assert(_currentSubscription != null);
     _currentSubscription.Dispose();
     _currentSubscription = null;
     _currentObserver     = null;
 }
Пример #2
0
 // Under unpatched Excel 2010, we rely on the ExcelRtd2010BugHelper to ensure we get a good Unsubscribe...
 public void Unsubscribe()
 {
     Debug.Assert(_currentSubscription != null);
     _currentSubscription.Dispose();
     _currentSubscription = null;
     _callerState.RemoveObserver(_currentObserver);
     _currentObserver = null;
 }
Пример #3
0
 public void RemoveObserver(ExcelRtdObserver observer)
 {
     _observers.Remove(observer);
     if (_observers.Count == 0 && _caller != null)
     {
         _callerStates.Remove(_caller);
     }
 }
Пример #4
0
        internal static void ConnectObserver(Guid id, ExcelRtdObserver rtdObserver)
        {
            // TODO: Checking...(huh?)
            AsyncObservableState state = _observableStates[id];

            // Start the work for this AsyncCallInfo, and subscribe the topic to the result
            state.Subscribe(rtdObserver);
        }
Пример #5
0
        protected override object ConnectData(Topic topic, IList <string> topicInfo, ref bool newValues)
        {
            Debug.Print("ExcelObserverRtdServer.ConnectData: ProgId: {0}, TopicId: {1}, TopicInfo: {2}, NewValues: {3}", RegisteredProgId, topic.TopicId, topicInfo[0], newValues);

            // The topic might be "completed" on a separate thread, so we need to return the initial, intended active value
            // Mostly this is TopicValueActive, but sometimes TopicValueActiveNA
            // Rather than store this for every topic, we just recalculate it here
            object valueActive = ValueActiveFromTopicInfo(topicInfo);

            if (newValues == false)
            {
                // Excel has a cached value, and we are being called from the file open refresh.

                // Indicating "newValues", should be safe since it is consistent with normal updates.
                // Result should be a Disconnect followed by a proper Connect via the wrapper.

                newValues = true;
                return(valueActive);
            }
            // Retrieve and store the GUID from the topic's first info string - used to hook up to the Async state
            Guid id = ((ObserverRtdTopic)topic).Id;

            // Create a new ExcelRtdObserver, for the Topic, which will listen to the Observable
            // (Internally this will also set the initial value of the Observer wrapper to #N/A)
            ExcelRtdObserver rtdObserver = new ExcelRtdObserver(topic);

            // ... and subscribe it
            AsyncObservableImpl.ConnectObserver(id, rtdObserver);

            // Now ConnectData needs to return some value, which will only be used by Excel internally (and saved in the book's RTD topic value).
            // Our wrapper function (ExcelAsyncUtil.Run or ExcelAsyncUtil.Observe) will return #N/A no matter what we return here.
            // However, it seems that Excel handles the special 'busy' error #N/A here (return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA))
            // in a special way (<tp t="e"><v>#N/A</v> in volatileDependencies.xml) - while other values seem to trigger a recalculate on file open,
            // when Excel attempts to restart the RTD server and fails (due to transient ProgId).
            // So for the ObserverRtdTopic we ensure the internal value is not an error,
            // (it is initialized to TopicValueActive)
            // which we return from here.
            // 2017-03-19: Except if the topic is configured as ExcelObservableOptions.NoAutoStartOnOpen, in which case we _do_ want
            //             the internal value to be #N/A. We return whichever ective value was set in the CreateTopic according to the topic info.

            // 2016-11-04: We are no longer returning the current value of topic.Value here.
            //             Since calls to UpdateValue inside the ConnectData no longer raise an
            //             UpdateNotify automatically, we need to ensure a different value
            //             is returned for a completed topic (so that ConnectData.returned != topic.Value)
            //             to raise an extra UpdateNotify, for the Disconnect of the already completed topic
            //             (I.e. if the completion happened during the ConnectData call).

            return(valueActive);
        }
Пример #6
0
        protected override object ConnectData(Topic topic, IList <string> topicInfo, ref bool newValues)
        {
            // Retrieve and store the GUID from the topic's first info string - used to hook up to the Async state
            Guid id = new Guid(topicInfo[0]);

            _topicGuids[topic] = id;

            // Create a new ExcelRtdObserver, for the Topic, which will listen to the Observable
            // (Internally also set initial value - #N/A for now)
            ExcelRtdObserver rtdObserver = new ExcelRtdObserver(topic);

            // ... and subscribe it
            AsyncObservableImpl.ConnectObserver(id, rtdObserver);

            // Return something: #N/A for now. Not currently used.
            // TODO: Allow customize?
            return(ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA));
        }
Пример #7
0
        // Safe to call with an invalid Id, but that's not expected.
        internal static void ConnectObserver(Guid id, ExcelRtdObserver rtdObserver)
        {
            Debug.Print("AsyncObservableImpl.ConnectObserver - Id: {0}", id);

            // It's an error if the id is not on the list - the ExcelObserverRtdServer should protect is from the onw known case
            // - when RTD is called from sheet open
            AsyncObservableState state;

            if (_observableStates.TryGetValue(id, out state))
            {
                // Start the work for this AsyncCallInfo, and subscribe the topic to the result
                state.Subscribe(rtdObserver);
            }
            else
            {
                // Not expected - the ExcelObserverRtdServer should have protected us,
                // since the only invalid id call would be for sheet open with direct RTD refresh.
                Debug.Fail("AsyncObservableImpl.ConnectObserver - Invalid Id: " + id);
            }
        }
        protected override object ConnectData(Topic topic, IList <string> topicInfo, ref bool newValues)
        {
            Debug.Print("ExcelObserverRtdServer.ConnectData: ProgId: {0}, TopicId: {1}, TopicInfo: {2}, NewValues: {3}", RegisteredProgId, topic.TopicId, topicInfo[0], newValues);

            if (newValues == false)
            {
                // Excel has a cached value, and we are being called from the file open refresh.

                // Calling UpdateNotify here seems to work (it causes the wrapper function to recalc,
                //    which Disconnects the bad topic, and allows a fresh one to be created)
                // Not needed if we return a new 'fake' value, which is safe since it is consistent with normal updates.
                // Result should be a Disconnect followed by a proper Connect via the wrapper.
                // topic.UpdateNotify();

                newValues = true;
                return(DateTime.UtcNow.ToOADate());
            }
            // Retrieve and store the GUID from the topic's first info string - used to hook up to the Async state
            Guid id = ((ObserverRtdTopic)topic).Id;

            // Create a new ExcelRtdObserver, for the Topic, which will listen to the Observable
            // (Internally this will also set the initial value to #N/A)
            ExcelRtdObserver rtdObserver = new ExcelRtdObserver(topic);

            // ... and subscribe it
            AsyncObservableImpl.ConnectObserver(id, rtdObserver);

            // Now ConnectData needs to return some value, which will only be used by Excel internally (and saved in the book's RTD topic value).
            // Our wrapper function (ExcelAsyncUtil.Run or ExcelAsyncUtil.Observe) will return #N/A no matter what we return here.
            // However, it seems that Excel handles the special 'busy' error #N/A here (return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA))
            // in a special way (<tp t="e"><v>#N/A</v> in volatileDependencies.xml) - while other values seem to trigger a recalculate on file open,
            // when Excel attempts to restart the RTD server and fails (due to transient ProgId).
            // So we already return the same kind of value we'd return for updates, putting Excel into the 'value has been updated' state
            // even if the sheet is saved. That will trigger a proper formula recals on file open.
            return(DateTime.UtcNow.ToOADate());
        }
Пример #9
0
 public void Subscribe(ExcelRtdObserver rtdObserver)
 {
     _currentObserver = rtdObserver;
     _callerState.AddObserver(_currentObserver);
     _currentSubscription = _observable.Subscribe(rtdObserver);
 }
Пример #10
0
 public void AddObserver(ExcelRtdObserver observer)
 {
     _observers.Add(observer);
 }
Пример #11
0
        protected override object ConnectData(Topic topic, IList<string> topicInfo, ref bool newValues)
        {
            // Retrieve and store the GUID from the topic's first info string - used to hook up to the Async state
            Guid id = new Guid(topicInfo[0]);
            _topicGuids[topic] = id;

            // Create a new ExcelRtdObserver, for the Topic, which will listen to the Observable
            // (Internally also set initial value - #N/A for now)
            ExcelRtdObserver rtdObserver = new ExcelRtdObserver(topic);
            // ... and subscribe it
            AsyncObservableImpl.ConnectObserver(id, rtdObserver);

            // Return something: #N/A for now. Not currently used.
            // TODO: Allow customize?
            return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA);
        }
Пример #12
0
 public void Unsubscribe()
 {
     Debug.Assert(_currentSubscription != null);
     _currentSubscription.Dispose();
     _currentSubscription = null;
     _currentObserver = null;
 }
Пример #13
0
 public void Subscribe(ExcelRtdObserver rtdObserver)
 {
     _currentObserver = rtdObserver;
     _currentSubscription = _observable.Subscribe(rtdObserver);
 }
Пример #14
0
 internal static void ConnectObserver(Guid id, ExcelRtdObserver rtdObserver)
 {
     // TODO: Checking...(huh?)
     AsyncObservableState state = _observableStates[id];
     // Start the work for this AsyncCallInfo, and subscribe the topic to the result
     state.Subscribe(rtdObserver);
 }