diff --git a/src/Client/App.axaml.cs b/src/Client/App.axaml.cs
index 94c0423..2be2dea 100644
--- a/src/Client/App.axaml.cs
+++ b/src/Client/App.axaml.cs
@@ -4,6 +4,7 @@
using Autofac;
using Avalonia;
+using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using WillowTree.Sweetgum.Client.DependencyInjection;
@@ -35,6 +36,13 @@ public override void Initialize()
///
public override void OnFrameworkInitializationCompleted()
{
+ if (Design.IsDesignMode)
+ {
+ // The Visual Studio designer doesn't run our entry point, so DI and services haven't been set up.
+ // Do this now.
+ Dependencies.ConfigureServices();
+ }
+
var settingsManager = Dependencies.Container.Resolve();
settingsManager.Load();
diff --git a/src/Client/ViewModels/MainWindowViewModel.cs b/src/Client/ViewModels/MainWindowViewModel.cs
index 2dcdc46..db4e965 100644
--- a/src/Client/ViewModels/MainWindowViewModel.cs
+++ b/src/Client/ViewModels/MainWindowViewModel.cs
@@ -2,6 +2,7 @@
// Copyright (c) WillowTree, LLC. All rights reserved.
//
+using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading;
@@ -23,10 +24,10 @@ public sealed class MainWindowViewModel : ReactiveObject
public MainWindowViewModel()
{
this.NewWorkbookCommand = ReactiveCommand.CreateFromTask(this.NewWorkbookAsync);
- this.NewWorkbookSpecifyPathInteraction = new Interaction();
+ this.NewWorkbookSpecifyPathInteraction = new Interaction();
this.LoadWorkbookCommand = ReactiveCommand.CreateFromTask(this.LoadWorkbookAsync);
- this.LoadWorkbookSpecifyPathInteraction = new Interaction();
+ this.LoadWorkbookSpecifyPathInteraction = new Interaction();
this.OpenSettingsCommand = ReactiveCommand.Create(() => { });
}
@@ -49,12 +50,12 @@ public MainWindowViewModel()
///
/// Gets the interaction to specify a path for a new workbook.
///
- public Interaction NewWorkbookSpecifyPathInteraction { get; }
+ public Interaction NewWorkbookSpecifyPathInteraction { get; }
///
/// Gets the interaction to specify a path for an existing workbook.
///
- public Interaction LoadWorkbookSpecifyPathInteraction { get; }
+ public Interaction LoadWorkbookSpecifyPathInteraction { get; }
private async Task NewWorkbookAsync(
Unit input,
@@ -62,6 +63,12 @@ private async Task NewWorkbookAsync(
{
var path = await this.NewWorkbookSpecifyPathInteraction.Handle(Unit.Default);
+ if (string.IsNullOrEmpty(path))
+ {
+ // We don't have access to the observable subscription or CTS here since it's eaten by Avalonia.
+ throw new TaskCanceledException();
+ }
+
return await WorkbookManager.NewAsync(path, cancellationToken);
}
@@ -71,6 +78,12 @@ private async Task LoadWorkbookAsync(
{
var path = await this.LoadWorkbookSpecifyPathInteraction.Handle(Unit.Default);
+ if (string.IsNullOrEmpty(path))
+ {
+ // We don't have access to the observable subscription or CTS here since it's eaten by Avalonia.
+ throw new TaskCanceledException();
+ }
+
return await WorkbookManager.LoadAsync(path, cancellationToken);
}
}
diff --git a/src/Client/Views/ErrorDialog.axaml b/src/Client/Views/ErrorDialog.axaml
new file mode 100644
index 0000000..2c23a42
--- /dev/null
+++ b/src/Client/Views/ErrorDialog.axaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Client/Views/ErrorDialog.axaml.cs b/src/Client/Views/ErrorDialog.axaml.cs
new file mode 100644
index 0000000..69d39ae
--- /dev/null
+++ b/src/Client/Views/ErrorDialog.axaml.cs
@@ -0,0 +1,72 @@
+//
+// Copyright (c) WillowTree, LLC. All rights reserved.
+//
+
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WillowTree.Sweetgum.Client.Views
+{
+ ///
+ /// A class for showing a simple error message.
+ ///
+ /// This class does not derive from because
+ /// it only displays a simple string and doesn't interact with any model objects.
+ public partial class ErrorDialog : Window
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception whose message to display.
+ /// The window that owns this dialog.
+ public ErrorDialog(Exception exception, WindowBase parent)
+ {
+ this.Exception = exception;
+ this.Owner = parent;
+ this.InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ TextBlock block = this.Find("txtMessage");
+ block.Text = this.Exception.Message;
+
+ this.Find