/// <summary>
        /// Starts the process of closing the project file editor, if one is open currently.
        /// </summary>
        public async Task CloseCurrentEditorAsync()
        {
            lock (_lock)
            {
                if (_currentState == EditorState.NoEditor)
                {
                    return;
                }

                // Checking for potential dirty state and asking if the user wants to save their changes will have already occurred at this point.
                // Just go to EditorClosing.
                _currentState = EditorState.EditorClosing;
            }

            _projectFileModelWatcher?.Dispose();
            _textBufferStateListener?.Dispose();
            if (_frameEventsListener != null)
            {
                await _frameEventsListener.DisposeAsync().ConfigureAwait(false);
            }
            _textBufferManager?.Dispose();

            _projectFileModelWatcher = null;
            _frameEventsListener     = null;
            _textBufferStateListener = null;
            _textBufferManager       = null;

            lock (_lock)
            {
                _currentState = EditorState.NoEditor;
            }
            return;
        }
        // Initialization Logic

        /// <summary>
        /// Called by anything attempting to open a project file editor window, usually by a command. This will show the window frame, creating it if
        /// has not already been created.
        /// </summary>
        public async Task OpenEditorAsync()
        {
            // We access _windowFrame inside the lock, so we must be on the UI thread in that case
            await _threadingService.SwitchToUIThread();

            lock (_lock)
            {
                // If the editor is already open, just show it and return
                if (_currentState != EditorState.NoEditor)
                {
                    // If we're initializing, _windowFrame might be null. In that case, when the initialization code
                    // is done, it'll take care of showing the frame.
                    _windowFrame?.Show();
                    return;
                }
                _currentState = EditorState.Initializing;
            }

            // Set up the buffer manager, which will create the temp file. Nothing else in OpenEditor requires the UI thread (tasks aquire it as needed)
            // so we don't need to resume on the same thread.
            _textBufferManager = _textBufferManagerFactory.CreateExport().Value;
            await _textBufferManager.InitializeBufferAsync().ConfigureAwait(false);

            // Open and show the editor frame.
            _windowFrame = await _shellHelper.OpenDocumentWithSpecificEditorAsync(_serviceProvider, _textBufferManager.FilePath, XmlFactoryGuid, Guid.Empty).ConfigureAwait(false);

            // Set up the save listener
            _textBufferStateListener = _textBufferListenerFactory.CreateExport().Value;
            await _textBufferStateListener.InitializeListenerAsync(_textBufferManager.FilePath).ConfigureAwait(false);

            // Set up the listener that will check for when the frame is closed.
            _frameEventsListener = _frameEventsListenerFactory.CreateExport().Value;
            await _frameEventsListener.InitializeEventsAsync(_windowFrame).ConfigureAwait(false);

            // Set up the project file watcher, so changes to the project file are detected and the buffer is updated.
            _projectFileModelWatcher = _projectFileWatcherFactory.CreateExport().Value;
            _projectFileModelWatcher.InitializeModelWatcher();

            // Finally, move to the editor open state
            lock (_lock)
            {
                _currentState = EditorState.EditorOpen;
            }
        }