File: StackTraceExplorer\StackTraceExplorerViewModel.cs
Web Access
Project: ..\..\..\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_ckcrqypr_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.StackTraceExplorer;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.Text.Classification;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Editor.Host;
 
namespace Microsoft.VisualStudio.LanguageServices.StackTraceExplorer
{
    internal class StackTraceExplorerViewModel : ViewModelBase
    {
        private readonly IThreadingContext _threadingContext;
        private readonly Workspace _workspace;
        public ObservableCollection<FrameViewModel> Frames { get; } = new();
 
        private bool _isLoading;
        private readonly ClassificationTypeMap _classificationTypeMap;
        private readonly IClassificationFormatMap _formatMap;
 
        public bool IsLoading
        {
            get => _isLoading;
            set => SetProperty(ref _isLoading, value);
        }
 
        private FrameViewModel? _selection;
        public FrameViewModel? Selection
        {
            get => _selection;
            set => SetProperty(ref _selection, value);
        }
 
        public bool IsListVisible => Frames.Count > 0;
        public bool IsInstructionTextVisible => Frames.Count == 0;
 
        private int _id;
 
        internal void OnClear()
        {
            Frames.Clear();
        }
 
        public string InstructionText => ServicesVSResources.Paste_valid_stack_trace;
        public string StackTrace => ServicesVSResources.Stack_Trace;
 
        public StackTraceExplorerViewModel(IThreadingContext threadingContext, Workspace workspace, ClassificationTypeMap classificationTypeMap, IClassificationFormatMap formatMap)
        {
            _threadingContext = threadingContext;
            _workspace = workspace;
 
            workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
            _classificationTypeMap = classificationTypeMap;
            _formatMap = formatMap;
 
            Frames.CollectionChanged += CallstackLines_CollectionChanged;
        }
 
        public bool Matches(string text) => text.GetHashCode() == _id;
 
        public void OnPaste_CallOnUIThread(string text)
        {
            IsLoading = true;
            Frames.Clear();
            var cancellationToken = _threadingContext.DisposalToken;
            System.Threading.Tasks.Task.Run(async () =>
            {
                try
                {
                    var result = await StackTraceAnalyzer.AnalyzeAsync(text, cancellationToken).ConfigureAwait(false);
                    await SetStackTraceResultAsync(result, text, cancellationToken).ConfigureAwait(false);
                }
                finally
                {
                    await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();
                    IsLoading = false;
                }
            }, cancellationToken);
        }
 
        public async System.Threading.Tasks.Task SetStackTraceResultAsync(StackTraceAnalysisResult result, string originalText, System.Threading.CancellationToken cancellationToken)
        {
            _id = originalText.GetHashCode();
            var viewModels = result.ParsedFrames.Select(l => GetViewModel(l));
 
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
 
            Selection = null;
            Frames.Clear();
 
            foreach (var vm in viewModels)
            {
                Frames.Add(vm);
            }
        }
 
        private void CallstackLines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            NotifyPropertyChanged(nameof(IsListVisible));
            NotifyPropertyChanged(nameof(IsInstructionTextVisible));
        }
 
        private void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
        {
            if (e.Kind == WorkspaceChangeKind.SolutionChanged)
            {
                Selection = null;
                Frames.Clear();
            }
        }
 
        private FrameViewModel GetViewModel(ParsedFrame frame)
            => frame switch
            {
                IgnoredFrame ignoredFrame => new IgnoredFrameViewModel(ignoredFrame, _formatMap, _classificationTypeMap),
                ParsedStackFrame stackFrame => new StackFrameViewModel(stackFrame, _threadingContext, _workspace, _formatMap, _classificationTypeMap),
                _ => throw ExceptionUtilities.UnexpectedValue(frame)
            };
    }
}