private async Task SaveAndClose() { try { // Save MRUs if (Editor.Session != null) { var openedAssets = assetEditorsManager.OpenedAssets.ToList(); if (!await Editor.Session.Close()) { closingTask?.SetResult(false); return; } // Make sure the curve editor is closed assetEditorsManager.CloseCurveEditorWindow(); // Close all windows (except if the user interrupt the flow) // Since all dirty assets must have been saved before, we don't need to ask for any user confirmation assetEditorsManager.CloseAllEditorWindows(false); Editor.Session.Destroy(); // Save opened assets dockingLayout.SaveOpenAssets(openedAssets); // Save layout dockingLayout.SaveCurrentLayout(); } var workArea = this.GetWorkArea(); // Save state GameStudioInternalSettings.WorkAreaWidth.SetValue((int)workArea.Width); GameStudioInternalSettings.WorkAreaHeight.SetValue((int)workArea.Height); GameStudioInternalSettings.WindowWidth.SetValue((int)Math.Max(320, (WindowState == WindowState.Maximized ? RestoreBounds.Width : ActualWidth))); GameStudioInternalSettings.WindowHeight.SetValue((int)Math.Max(240, (WindowState == WindowState.Maximized ? RestoreBounds.Height : ActualHeight))); GameStudioInternalSettings.WindowMaximized.SetValue(WindowState == WindowState.Maximized); // Write the settings file InternalSettings.Save(); forceClose = true; var studio = Editor as GameStudioViewModel; studio?.Destroy(); closingTask?.SetResult(true); // Shutdown after all other operations have completed await Application.Current.Dispatcher.InvokeAsync(Application.Current.Shutdown, DispatcherPriority.ContextIdle); } finally { closingTask = null; } }
/// <summary> /// Opens (and activates) an editor window for the given asset. If an editor window for this asset already exists, simply activates it. /// </summary> /// <param name="asset">The asset for which to show an editor window.</param> /// <param name="saveSettings">True if <see cref="MRUAdditionalData.OpenedAssets"/> should be updated, false otherwise. Note that if the editor fail to load it will not be updated.</param> /// <returns></returns> internal async Task OpenAssetEditorWindow([NotNull] AssetViewModel asset, bool saveSettings) { if (asset == null) { throw new ArgumentNullException(nameof(asset)); } if (dockingLayoutManager == null) { throw new InvalidOperationException("This method can only be invoked on the IEditorDialogService that has the editor main window as parent."); } // Switch to the editor layout before adding any Pane if (assetEditors.Count == 0) { dockingLayoutManager.SwitchToEditorLayout(); } using (await mutex.LockAsync()) { LayoutAnchorable editorPane = null; IEditorView view; // Asset already has an editor? if (asset.Editor != null) { // Look for the corresponding pane if (!assetEditors.TryGetValue(asset.Editor, out editorPane)) { // Inconsistency, clean leaking editor RemoveAssetEditor(asset); // Try to find if another editor currently has this asset var editor = assetEditors.Keys.OfType <IMultipleAssetEditorViewModel>().FirstOrDefault(x => x.OpenedAssets.Contains(asset)); if (editor != null) { editorPane = assetEditors[editor]; asset.Editor = editor; } } } // Existing editor? if (editorPane != null) { // Make the pane visible immediately MakeActiveVisible(editorPane); view = editorPane.Content as IEditorView; if (view?.EditorInitialization != null) { // Wait for the end of the initialization await view.EditorInitialization; } return; } // Create a new editor view view = asset.ServiceProvider.Get <IAssetsPluginService>().ConstructEditionView(asset); if (view != null) { // Pane may already exists (e.g. created from layout saving) editorPane = AvalonDockHelper.GetAllAnchorables(dockingLayoutManager.DockingManager).FirstOrDefault(p => p.Title == asset.Url); if (editorPane == null) { editorPane = new LayoutAnchorable { CanClose = true }; // Stack the asset in the dictionary of editor to prevent double-opening while double-clicking twice on the asset, since the initialization is async AvalonDockHelper.GetDocumentPane(dockingLayoutManager.DockingManager).Children.Add(editorPane); } editorPane.IsActiveChanged += EditorPaneIsActiveChanged; editorPane.IsSelectedChanged += EditorPaneIsSelectedChanged; editorPane.Closing += EditorPaneClosing; editorPane.Closed += EditorPaneClosed; editorPane.Content = view; // Make the pane visible immediately MakeActiveVisible(editorPane); // Initialize the editor view view.DataContext = asset; // Create a binding for the title var binding = new Binding(nameof(AssetViewModel.Url)) { Mode = BindingMode.OneWay, Source = asset }; BindingOperations.SetBinding(editorPane, LayoutContent.TitleProperty, binding); var viewModel = await view.InitializeEditor(asset); if (viewModel == null) { // Could not initialize editor CleanEditorPane(editorPane); RemoveEditorPane(editorPane); } else { assetEditors[viewModel] = editorPane; openedAssets.Add(asset); var multiEditor = viewModel as IMultipleAssetEditorViewModel; if (multiEditor != null) { foreach (var item in multiEditor.OpenedAssets) { if (item.Editor != null) { // Note: this could happen in some case after undo/redo that involves parenting of scenes RemoveAssetEditor(item); } item.Editor = viewModel; } multiEditor.OpenedAssets.CollectionChanged += (_, e) => MultiEditorOpenAssetsChanged(multiEditor, e); } else { asset.Editor = viewModel; } } } } // If the opening of the editor failed, go back to normal layout if (assetEditors.Count == 0) { dockingLayoutManager.SwitchToNormalLayout(); return; } if (saveSettings) { dockingLayoutManager.SaveOpenAssets(OpenedAssets); } }