Example #1
0
        private async Task StartUIThreadEpilogueAsync(QuickInfoSessionState initialState, IList <ITrackingSpan> applicableToSpans, CancellationToken cancellationToken)
        {
            // Ensure we're back on the UI thread.
            await this.JoinableTaskContext.Factory.SwitchToMainThreadAsync();

            if (applicableToSpans != null)
            {
                // Update the applicable-to span.
                this.ComputeApplicableToSpan(applicableToSpans);
            }

            // Check if any of our content is interactive and cache that so it's not done on mouse move.
            this.ComputeHasInteractiveContent();

            // If we have results and a span for which to show them and we aren't cancelled update the tip.
            if ((initialState == QuickInfoSessionState.Dismissed) ||
                !this.Content.Any() ||
                (this.ApplicableToSpan == null) ||
                cancellationToken.IsCancellationRequested)
            {
                // If we were unable to await some computation task and don't end up with
                // a visible presenter + content, ensure that we cleanup and change our state appropriately.
                await this.DismissAsync().ConfigureAwait(false);
            }
        }
Example #2
0
        private async Task <IList <Exception> > ComputeContentAndUpdateAsync(QuickInfoSessionState initialState, bool allowUpdate, CancellationToken cancellationToken)
        {
            IntellisenseUtilities.ThrowIfNotOnMainThread(this.JoinableTaskContext);

            // Alert subscribers on the UI thread.
            this.TransitionTo(QuickInfoSessionState.Calculating, allowUpdate);

            cancellationToken.ThrowIfCancellationRequested();

            var failures = new FrugalList <Exception>();

            // Find and create the sources. Sources cache is smart enough to
            // invalidate on content-type changed and free on view close.
            var sources = this.GetOrCreateSources(failures);

            // Compute quick info items. This method switches off the UI thread.
            // From here on out we're on an arbitrary thread.
            (IList <object> items, IList <ITrackingSpan> applicableToSpans)? results
                = await ComputeContentAsync(sources, failures, cancellationToken).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            // Update our content, or put the empty list if there is none.
            Volatile.Write(
                ref this.content,
                results != null ? ImmutableList.CreateRange(results.Value.items) : ImmutableList <object> .Empty);

            await StartUIThreadEpilogueAsync(initialState, results?.applicableToSpans, cancellationToken).ConfigureAwait(false);

            return(failures);
        }
Example #3
0
        private async Task StartUIThreadEpilogueAsync(
            QuickInfoSessionState originalState,
            IList <ITrackingSpan> applicableToSpans,
            CancellationToken cancellationToken)
        {
            // Ensure we're back on the UI thread.
            await this.joinableTaskContext.Factory.SwitchToMainThreadAsync();

            if (applicableToSpans != null)
            {
                // Update the applicable-to span.
                this.ComputeApplicableToSpan(applicableToSpans);
            }

            // Check if any of our content is interactive and cache that so it's not done on mouse move.
            this.ComputeHasInteractiveContent();

            // If we have results and a span for which to show them and we aren't cancelled update the tip.
            if ((originalState == QuickInfoSessionState.Created) &&
                this.Content.Any() &&
                (this.ApplicableToSpan != null) &&
                !cancellationToken.IsCancellationRequested)
            {
                this.CreateAndStartPresenter();
            }
        }
Example #4
0
        private void TransitionTo(QuickInfoSessionState newState)
        {
            IntellisenseUtilities.ThrowIfNotOnMainThread(this.joinableTaskContext);

            var  oldState = this.State;
            bool isValid  = false;

            switch (newState)
            {
            case QuickInfoSessionState.Created:
                isValid = false;
                break;

            case QuickInfoSessionState.Calculating:
                isValid = oldState == QuickInfoSessionState.Created || oldState == QuickInfoSessionState.Visible;
                break;

            case QuickInfoSessionState.Dismissed:
                isValid = oldState == QuickInfoSessionState.Visible ||
                          oldState == QuickInfoSessionState.Calculating;
                break;

            case QuickInfoSessionState.Visible:
                isValid = oldState == QuickInfoSessionState.Calculating;
                break;
            }

            if (!isValid)
            {
                throw new InvalidOperationException($"Invalid {nameof(IAsyncQuickInfoSession)} state transition from {oldState} to {newState}");
            }

            Volatile.Write(ref this.uiThreadWritableState, (int)newState);
            this.StateChanged?.Invoke(this, new QuickInfoSessionStateChangedEventArgs(oldState, newState));
        }
 /// <summary>
 /// Creates a new instance of <see cref="QuickInfoSessionStateChangedEventArgs"/>.
 /// </summary>
 /// <param name="oldState">The state before the transition.</param>
 /// <param name="newState">The state after the transition.</param>
 public QuickInfoSessionStateChangedEventArgs(QuickInfoSessionState oldState, QuickInfoSessionState newState)
 {
     this.OldState = oldState;
     this.NewState = newState;
 }