Add Avalonia setup
This commit is contained in:
parent
ffd947eb2e
commit
fe6cfc899b
@ -6,6 +6,11 @@ using LibationFileManager;
|
|||||||
using LibationAvalonia.Views;
|
using LibationAvalonia.Views;
|
||||||
using System;
|
using System;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
using LibationAvalonia.Dialogs;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using ApplicationServices;
|
||||||
|
|
||||||
namespace LibationAvalonia
|
namespace LibationAvalonia
|
||||||
{
|
{
|
||||||
@ -31,6 +36,9 @@ namespace LibationAvalonia
|
|||||||
AssetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>();
|
AssetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Task<List<DataLayer.LibraryBook>> LibraryTask;
|
||||||
|
public static bool SetupRequired;
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
{
|
{
|
||||||
LoadStyles();
|
LoadStyles();
|
||||||
@ -41,16 +49,140 @@ namespace LibationAvalonia
|
|||||||
|
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
var mainWindow = new MainWindow();
|
if (SetupRequired)
|
||||||
desktop.MainWindow = mainWindow;
|
{
|
||||||
mainWindow.RestoreSizeAndLocation(Configuration.Instance);
|
var config = Configuration.Instance;
|
||||||
mainWindow.OnLoad();
|
|
||||||
|
var defaultLibationFilesDir = Configuration.UserProfile;
|
||||||
|
|
||||||
|
// check for existing settings in default location
|
||||||
|
var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json");
|
||||||
|
if (Configuration.SettingsFileIsValid(defaultSettingsFile))
|
||||||
|
config.SetLibationFiles(defaultLibationFilesDir);
|
||||||
|
|
||||||
|
if (config.LibationSettingsAreValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var setupDialog = new SetupDialog { Config = config };
|
||||||
|
setupDialog.Closing += Setup_Closing;
|
||||||
|
|
||||||
|
desktop.MainWindow = setupDialog;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ShowMainWindow(desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
base.OnFrameworkInitializationCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadStyles()
|
private void Setup_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
|
{
|
||||||
|
var setupDialog = sender as SetupDialog;
|
||||||
|
var desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// all returns should be preceded by either:
|
||||||
|
// - if config.LibationSettingsAreValid
|
||||||
|
// - error message, Exit()
|
||||||
|
|
||||||
|
if ((!setupDialog.IsNewUser
|
||||||
|
&& !setupDialog.IsReturningUser) ||
|
||||||
|
!RunInstall(setupDialog))
|
||||||
|
{
|
||||||
|
CancelInstallation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// most migrations go in here
|
||||||
|
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(setupDialog.Config);
|
||||||
|
|
||||||
|
MessageBox.VerboseLoggingWarning_ShowIfTrue();
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
|
checkForUpdate();
|
||||||
|
#endif
|
||||||
|
// logging is init'd here
|
||||||
|
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(setupDialog.Config);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var title = "Fatal error, pre-logging";
|
||||||
|
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MessageBox.ShowAdminAlert(null, body, title, ex);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||||
|
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
||||||
|
ShowMainWindow(desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RunInstall(SetupDialog setupDialog)
|
||||||
|
{
|
||||||
|
var config = setupDialog.Config;
|
||||||
|
|
||||||
|
if (setupDialog.IsNewUser)
|
||||||
|
{
|
||||||
|
config.SetLibationFiles(Configuration.UserProfile);
|
||||||
|
}
|
||||||
|
else if (setupDialog.IsReturningUser)
|
||||||
|
{
|
||||||
|
|
||||||
|
var libationFilesDialog = new LibationFilesDialog();
|
||||||
|
|
||||||
|
if (libationFilesDialog.ShowDialogSynchronously<DialogResult>(setupDialog) != DialogResult.OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
config.SetLibationFiles(libationFilesDialog.SelectedDirectory);
|
||||||
|
if (config.LibationSettingsAreValid)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// path did not result in valid settings
|
||||||
|
var continueResult = MessageBox.Show(
|
||||||
|
$"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}",
|
||||||
|
"New install?",
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Question);
|
||||||
|
|
||||||
|
if (continueResult != DialogResult.Yes)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT DEFAULT SETTINGS
|
||||||
|
// if 'new user' was clicked, or if 'returning user' chose new install: show basic settings dialog
|
||||||
|
config.Books ??= Path.Combine(Configuration.UserProfile, "Books");
|
||||||
|
|
||||||
|
return new SettingsDialog().ShowDialogSynchronously<DialogResult>(setupDialog) == DialogResult.OK
|
||||||
|
&& config.LibationSettingsAreValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancelInstallation()
|
||||||
|
{
|
||||||
|
MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
var mainWindow = new MainWindow();
|
||||||
|
desktop.MainWindow = mainWindow;
|
||||||
|
mainWindow.RestoreSizeAndLocation(Configuration.Instance);
|
||||||
|
mainWindow.OnLoad();
|
||||||
|
mainWindow.OnLibraryLoaded(LibraryTask.GetAwaiter().GetResult());
|
||||||
|
mainWindow.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadStyles()
|
||||||
{
|
{
|
||||||
ProcessQueueBookFailedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookFailedBrush");
|
ProcessQueueBookFailedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookFailedBrush");
|
||||||
ProcessQueueBookCompletedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookCompletedBrush");
|
ProcessQueueBookCompletedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookCompletedBrush");
|
||||||
|
|||||||
16
Source/LibationAvalonia/AppBasic.axaml
Normal file
16
Source/LibationAvalonia/AppBasic.axaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Application xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x2="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:LibationAvalonia"
|
||||||
|
x2:Class="LibationAvalonia.AppBasic">
|
||||||
|
|
||||||
|
<Application.DataTemplates>
|
||||||
|
<local:ViewLocator/>
|
||||||
|
</Application.DataTemplates>
|
||||||
|
|
||||||
|
<Application.Styles>
|
||||||
|
<FluentTheme Mode="Light"/>
|
||||||
|
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
|
||||||
|
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
|
||||||
|
<StyleInclude Source="/Assets/LibationStyles.xaml"/>
|
||||||
|
</Application.Styles>
|
||||||
|
</Application>
|
||||||
28
Source/LibationAvalonia/AppBasic.axaml.cs
Normal file
28
Source/LibationAvalonia/AppBasic.axaml.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using LibationAvalonia.Dialogs;
|
||||||
|
|
||||||
|
namespace LibationAvalonia
|
||||||
|
{
|
||||||
|
public class AppBasic : Application
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
public Window MainWindow { get; set; }
|
||||||
|
|
||||||
|
public override void OnFrameworkInitializationCompleted()
|
||||||
|
{
|
||||||
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
desktop.MainWindow = new SetupDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnFrameworkInitializationCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
{
|
{
|
||||||
public abstract class DialogWindow : Window
|
public abstract class DialogWindow : Window
|
||||||
{
|
{
|
||||||
|
public bool SaveAndRestorePosition { get; set; } = true;
|
||||||
public Control ControlToFocusOnShow { get; set; }
|
public Control ControlToFocusOnShow { get; set; }
|
||||||
public DialogWindow()
|
public DialogWindow()
|
||||||
{
|
{
|
||||||
@ -21,16 +22,22 @@ namespace LibationAvalonia.Dialogs
|
|||||||
this.AttachDevTools();
|
this.AttachDevTools();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
public DialogWindow(bool saveAndRestorePosition) : this()
|
||||||
|
{
|
||||||
|
SaveAndRestorePosition = saveAndRestorePosition;
|
||||||
|
}
|
||||||
|
|
||||||
private void DialogWindow_Initialized(object sender, EventArgs e)
|
private void DialogWindow_Initialized(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
this.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
this.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
this.RestoreSizeAndLocation(Configuration.Instance);
|
if (SaveAndRestorePosition)
|
||||||
|
this.RestoreSizeAndLocation(Configuration.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DialogWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
private void DialogWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
{
|
{
|
||||||
this.SaveSizeAndLocation(Configuration.Instance);
|
if (SaveAndRestorePosition)
|
||||||
|
this.SaveSizeAndLocation(Configuration.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DialogWindow_Opened(object sender, EventArgs e)
|
private void DialogWindow_Opened(object sender, EventArgs e)
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
Directory="{Binding Directory, Mode=TwoWay}"
|
Directory="{Binding Directory, Mode=TwoWay}"
|
||||||
|
SubDirectory=""
|
||||||
KnownDirectories="{Binding KnownDirectories}" />
|
KnownDirectories="{Binding KnownDirectories}" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@ -24,6 +25,7 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
Padding="30,3,30,3"
|
Padding="30,3,30,3"
|
||||||
Content="Save" />
|
Content="Save"
|
||||||
|
Click="SaveButton_Click" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace LibationAvalonia.Dialogs
|
namespace LibationAvalonia.Dialogs
|
||||||
{
|
{
|
||||||
public partial class LibationFilesDialog : DialogWindow
|
public partial class LibationFilesDialog : Window
|
||||||
{
|
{
|
||||||
private class DirSelectOptions
|
private class DirSelectOptions
|
||||||
{
|
{
|
||||||
@ -19,27 +19,32 @@ namespace LibationAvalonia.Dialogs
|
|||||||
Configuration.KnownDirectories.MyDocs
|
Configuration.KnownDirectories.MyDocs
|
||||||
};
|
};
|
||||||
|
|
||||||
public string Directory { get; set; } = Configuration.Instance.LibationFiles;
|
public string Directory { get; set; } = Configuration.GetKnownDirectoryPath(Configuration.KnownDirectories.UserProfile);
|
||||||
}
|
}
|
||||||
private DirSelectOptions dirSelectOptions;
|
private DirSelectOptions dirSelectOptions;
|
||||||
public string SelectedDirectory => dirSelectOptions.Directory;
|
public string SelectedDirectory => dirSelectOptions.Directory;
|
||||||
public LibationFilesDialog()
|
public LibationFilesDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
DataContext = dirSelectOptions = new();
|
DataContext = dirSelectOptions = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task SaveAndCloseAsync()
|
public void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
var libationDir = dirSelectOptions.Directory;
|
var libationDir = dirSelectOptions.Directory;
|
||||||
|
|
||||||
if (!System.IO.Directory.Exists(libationDir))
|
if (!System.IO.Directory.Exists(libationDir))
|
||||||
{
|
{
|
||||||
MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error, saveAndRestorePosition: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.SaveAndCloseAsync();
|
Close(DialogResult.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
|
|||||||
@ -12,6 +12,10 @@ namespace LibationAvalonia.Dialogs
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
public MessageBoxWindow(bool saveAndRestorePosition):base(saveAndRestorePosition)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
|
|||||||
50
Source/LibationAvalonia/Dialogs/SetupDialog.axaml
Normal file
50
Source/LibationAvalonia/Dialogs/SetupDialog.axaml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="330"
|
||||||
|
MinWidth="500" MinHeight="330"
|
||||||
|
MaxWidth="500" MaxHeight="330"
|
||||||
|
x:Class="LibationAvalonia.Dialogs.SetupDialog"
|
||||||
|
WindowStartupLocation="CenterScreen"
|
||||||
|
Icon="/Assets/libation.ico"
|
||||||
|
Title="Welcome to Libation">
|
||||||
|
|
||||||
|
<Grid Margin="10" RowDefinitions="*,Auto,Auto">
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Text="This appears to be your first time using Libation or a previous setup was incomplete.
|
||||||
|


|
||||||
|

Please fill in a few settings. You can also change these settings later.
|
||||||
|


|
||||||
|

After you make your selections, get started by importing your library.
|
||||||
|

Go to Import > Scan Library
|
||||||
|


|
||||||
|

Download your entire library from the "Liberate" tab or
|
||||||
|

liberate your books one at a time by clicking the stoplight." />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,10,0,10"
|
||||||
|
Padding="0,10,0,10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Click="NewUser_Click">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
TextAlignment="Center"
|
||||||
|
Text="NEW USER

Choose Settings"/>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Row="2"
|
||||||
|
Padding="0,10,0,10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Click="ReturningUser_Click">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
TextAlignment="Center"
|
||||||
|
Text="RETURNING USER

I have previously installed Libation. This is an upgrade or re-install."/>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
39
Source/LibationAvalonia/Dialogs/SetupDialog.axaml.cs
Normal file
39
Source/LibationAvalonia/Dialogs/SetupDialog.axaml.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using LibationFileManager;
|
||||||
|
|
||||||
|
namespace LibationAvalonia.Dialogs
|
||||||
|
{
|
||||||
|
public partial class SetupDialog : Window
|
||||||
|
{
|
||||||
|
public bool IsNewUser { get;private set; }
|
||||||
|
public bool IsReturningUser { get;private set; }
|
||||||
|
public Configuration Config { get; init; }
|
||||||
|
public SetupDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NewUser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
IsNewUser = true;
|
||||||
|
Close(DialogResult.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReturningUser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
IsReturningUser = true;
|
||||||
|
Close(DialogResult.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,7 @@ namespace LibationAvalonia
|
|||||||
static readonly WindowIcon WindowIcon;
|
static readonly WindowIcon WindowIcon;
|
||||||
static FormSaveExtension()
|
static FormSaveExtension()
|
||||||
{
|
{
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow is not null)
|
||||||
WindowIcon = desktop.MainWindow.Icon;
|
WindowIcon = desktop.MainWindow.Icon;
|
||||||
else
|
else
|
||||||
WindowIcon = null;
|
WindowIcon = null;
|
||||||
|
|||||||
@ -80,6 +80,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Update="AppBasic.axaml.cs">
|
||||||
|
<DependentUpon>AppBasic.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Views\ProcessBookControl.axaml.cs">
|
<Compile Update="Views\ProcessBookControl.axaml.cs">
|
||||||
<DependentUpon>ProcessBookControl.axaml</DependentUpon>
|
<DependentUpon>ProcessBookControl.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|||||||
@ -62,8 +62,8 @@ namespace LibationAvalonia
|
|||||||
|
|
||||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
||||||
=> ShowCoreAsync(null, text, caption, buttons, icon, defaultButton);
|
=> ShowCoreAsync(null, text, caption, buttons, icon, defaultButton);
|
||||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, bool saveAndRestorePosition = true)
|
||||||
=> ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1);
|
=> ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, saveAndRestorePosition);
|
||||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons)
|
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons)
|
||||||
=> ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
=> ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||||
public static DialogResult Show(string text, string caption)
|
public static DialogResult Show(string text, string caption)
|
||||||
@ -148,9 +148,9 @@ Libation.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true)
|
||||||
{
|
{
|
||||||
var dialog = new MessageBoxWindow();
|
var dialog = new MessageBoxWindow(saveAndRestorePosition);
|
||||||
|
|
||||||
dialog.HideMinMaxBtns();
|
dialog.HideMinMaxBtns();
|
||||||
|
|
||||||
|
|||||||
@ -18,24 +18,33 @@ namespace LibationAvalonia
|
|||||||
|
|
||||||
static async Task Main()
|
static async Task Main()
|
||||||
{
|
{
|
||||||
|
//***********************************************//
|
||||||
|
// //
|
||||||
|
// do not use Configuration before this line //
|
||||||
|
// //
|
||||||
|
//***********************************************//
|
||||||
|
// Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration
|
||||||
|
var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations();
|
||||||
|
|
||||||
|
App.SetupRequired = !config.LibationSettingsAreValid;
|
||||||
|
|
||||||
//Start as much work in parallel as possible.
|
//Start as much work in parallel as possible.
|
||||||
var runDbMigrationsTask = Task.Run(() => RunDbMigrations());
|
|
||||||
var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime());
|
var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime());
|
||||||
var appBuilderTask = Task.Run(BuildAvaloniaApp);
|
var appBuilderTask = Task.Run(BuildAvaloniaApp);
|
||||||
|
|
||||||
if (!await runDbMigrationsTask)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var dbLibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
if (!App.SetupRequired)
|
||||||
|
{
|
||||||
|
if (!RunDbMigrations(config))
|
||||||
|
return;
|
||||||
|
|
||||||
|
App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(await appBuilderTask).SetupWithLifetime(await classicLifetimeTask);
|
(await appBuilderTask).SetupWithLifetime(await classicLifetimeTask);
|
||||||
|
|
||||||
var form1 = (Views.MainWindow)classicLifetimeTask.Result.MainWindow;
|
|
||||||
|
|
||||||
form1.OnLibraryLoaded(await dbLibraryTask);
|
|
||||||
|
|
||||||
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
|
|
||||||
|
|
||||||
classicLifetimeTask.Result.Start(null);
|
classicLifetimeTask.Result.Start(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +53,15 @@ namespace LibationAvalonia
|
|||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
.UseReactiveUI();
|
.UseReactiveUI();
|
||||||
|
public static AppBuilder BuildAvaloniaAppBasic()
|
||||||
|
=> AppBuilder.Configure<AppBasic>()
|
||||||
|
.UsePlatformDetect()
|
||||||
|
.LogToTrace();
|
||||||
|
|
||||||
private static bool RunDbMigrations()
|
public static bool RunDbMigrations(Configuration config)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//***********************************************//
|
|
||||||
// //
|
|
||||||
// do not use Configuration before this line //
|
|
||||||
// //
|
|
||||||
//***********************************************//
|
|
||||||
// Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration
|
|
||||||
var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations();
|
|
||||||
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
|
||||||
|
|
||||||
// most migrations go in here
|
// most migrations go in here
|
||||||
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config);
|
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config);
|
||||||
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Release\publish\linux-x64\</PublishDir>
|
<PublishDir>..\bin\publish\linux-x64\</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
|||||||
@ -345,7 +345,7 @@ namespace LibationFileManager
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region known directories
|
#region known directories
|
||||||
public static string AppDir_Relative => $@".\{LIBATION_FILES_KEY}";
|
public static string AppDir_Relative => $@".{Path.PathSeparator}{LIBATION_FILES_KEY}";
|
||||||
public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), LIBATION_FILES_KEY));
|
public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), LIBATION_FILES_KEY));
|
||||||
public static string MyDocs => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Libation"));
|
public static string MyDocs => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Libation"));
|
||||||
public static string WinTemp => Path.GetFullPath(Path.Combine(Path.GetTempPath(), "Libation"));
|
public static string WinTemp => Path.GetFullPath(Path.Combine(Path.GetTempPath(), "Libation"));
|
||||||
@ -522,8 +522,6 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
public void SetLibationFiles(string directory)
|
public void SetLibationFiles(string directory)
|
||||||
{
|
{
|
||||||
libationFilesPathCache = null;
|
|
||||||
|
|
||||||
// ensure exists
|
// ensure exists
|
||||||
if (!File.Exists(APPSETTINGS_JSON))
|
if (!File.Exists(APPSETTINGS_JSON))
|
||||||
{
|
{
|
||||||
@ -532,6 +530,8 @@ namespace LibationFileManager
|
|||||||
System.Threading.Thread.Sleep(100);
|
System.Threading.Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libationFilesPathCache = null;
|
||||||
|
|
||||||
var startingContents = File.ReadAllText(APPSETTINGS_JSON);
|
var startingContents = File.ReadAllText(APPSETTINGS_JSON);
|
||||||
var jObj = JObject.Parse(startingContents);
|
var jObj = JObject.Parse(startingContents);
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using ApplicationServices;
|
using Dinah.Core;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationWinForms.Dialogs;
|
using LibationWinForms.Dialogs;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
@ -20,98 +18,6 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
|
||||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|
||||||
var config = LoadLibationConfig();
|
|
||||||
|
|
||||||
if (config is null) return;
|
|
||||||
|
|
||||||
|
|
||||||
var bmp = System.Drawing.SystemIcons.Error.ToBitmap();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Results below compare startup times when parallelizing startup tasks vs when
|
|
||||||
running everything sequentially, from the entry point until after the call to
|
|
||||||
OnLoadedLibrary() returns. Tests were run on a ReadyToRun enabled release build.
|
|
||||||
|
|
||||||
The first run is substantially slower than all subsequent runs for both serial
|
|
||||||
and parallel. This is most likely due to file system caching speeding up
|
|
||||||
subsequent runs, and it's significant because in the wild, most runs are "cold"
|
|
||||||
and will not benefit from caching.
|
|
||||||
|
|
||||||
All times are in milliseconds.
|
|
||||||
|
|
||||||
Run Parallel Serial
|
|
||||||
1 2837 5835
|
|
||||||
2 1566 2774
|
|
||||||
3 1562 2316
|
|
||||||
4 1642 2388
|
|
||||||
5 1596 2391
|
|
||||||
6 1591 2358
|
|
||||||
7 1492 2363
|
|
||||||
8 1542 2335
|
|
||||||
9 1600 2418
|
|
||||||
10 1564 2359
|
|
||||||
11 1567 2379
|
|
||||||
|
|
||||||
Min 1492 2316
|
|
||||||
Q1 1562 2358
|
|
||||||
Med 1567 2379
|
|
||||||
Q3 1600 2418
|
|
||||||
Max 2837 5835
|
|
||||||
*/
|
|
||||||
|
|
||||||
void Form1_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
sw.Stop();
|
|
||||||
//MessageBox.Show(sw.ElapsedMilliseconds.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//For debug purposes, always run AvaloniaUI.
|
|
||||||
if (config.GetNonString<bool>("BetaOptIn"))
|
|
||||||
{
|
|
||||||
//Start as much work in parallel as possible.
|
|
||||||
var runDbMigrationsTask = Task.Run(() => RunDbMigrations(config));
|
|
||||||
var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime());
|
|
||||||
var appBuilderTask = Task.Run(BuildAvaloniaApp);
|
|
||||||
|
|
||||||
if (!runDbMigrationsTask.GetAwaiter().GetResult())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var runOtherMigrationsTask = Task.Run(() => RunOtherMigrations(config));
|
|
||||||
var dbLibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
|
||||||
|
|
||||||
appBuilderTask.GetAwaiter().GetResult().SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult());
|
|
||||||
|
|
||||||
if (!runOtherMigrationsTask.GetAwaiter().GetResult())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var form1 = (AvaloniaUI.Views.MainWindow)classicLifetimeTask.Result.MainWindow;
|
|
||||||
form1.Opened += Form1_Load;
|
|
||||||
|
|
||||||
form1.OnLibraryLoaded(dbLibraryTask.GetAwaiter().GetResult());
|
|
||||||
|
|
||||||
classicLifetimeTask.Result.Start(null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!RunDbMigrations(config) || !RunOtherMigrations(config))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var form1 = new Form1();
|
|
||||||
form1.Shown += Form1_Load;
|
|
||||||
|
|
||||||
System.Windows.Forms.Application.Run(form1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
|
||||||
=> AppBuilder.Configure<AvaloniaUI.App>()
|
|
||||||
.UsePlatformDetect()
|
|
||||||
.LogToTrace()
|
|
||||||
.UseReactiveUI();
|
|
||||||
|
|
||||||
private static Configuration LoadLibationConfig()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -120,7 +26,7 @@ namespace LibationWinForms
|
|||||||
//AllocConsole();
|
//AllocConsole();
|
||||||
|
|
||||||
// run as early as possible. see notes in postLoggingGlobalExceptionHandling
|
// run as early as possible. see notes in postLoggingGlobalExceptionHandling
|
||||||
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||||
|
|
||||||
ApplicationConfiguration.Initialize();
|
ApplicationConfiguration.Initialize();
|
||||||
|
|
||||||
@ -131,40 +37,13 @@ namespace LibationWinForms
|
|||||||
//***********************************************//
|
//***********************************************//
|
||||||
// Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration
|
// Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration
|
||||||
var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations();
|
var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations();
|
||||||
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DisplayStartupErrorMessage(ex);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool RunDbMigrations(Configuration config)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// do this as soon as possible (post-config)
|
// do this as soon as possible (post-config)
|
||||||
RunInstaller(config);
|
RunInstaller(config);
|
||||||
|
|
||||||
// most migrations go in here
|
// most migrations go in here
|
||||||
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config);
|
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DisplayStartupErrorMessage(ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool RunOtherMigrations(Configuration config)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// migrations which require Forms or are long-running
|
// migrations which require Forms or are long-running
|
||||||
RunWindowsOnlyMigrations(config);
|
RunWindowsOnlyMigrations(config);
|
||||||
|
|
||||||
@ -175,36 +54,26 @@ namespace LibationWinForms
|
|||||||
#endif
|
#endif
|
||||||
// logging is init'd here
|
// logging is init'd here
|
||||||
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||||
|
|
||||||
// global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd
|
|
||||||
#if WINDOWS7_0_OR_GREATER
|
|
||||||
postLoggingGlobalExceptionHandling();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
DisplayStartupErrorMessage(ex);
|
var title = "Fatal error, pre-logging";
|
||||||
return false;
|
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MessageBoxLib.ShowAdminAlert(null, body, title, ex);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd
|
||||||
|
postLoggingGlobalExceptionHandling();
|
||||||
|
|
||||||
private static void DisplayStartupErrorMessage(Exception ex)
|
Application.Run(new Form1());
|
||||||
{
|
|
||||||
var title = "Fatal error, pre-logging";
|
|
||||||
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
|
||||||
#if WINDOWS7_0_OR_GREATER
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MessageBoxLib.ShowAdminAlert(null, body, title, ex);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunInstaller(Configuration config)
|
private static void RunInstaller(Configuration config)
|
||||||
@ -229,7 +98,7 @@ namespace LibationWinForms
|
|||||||
static void CancelInstallation()
|
static void CancelInstallation()
|
||||||
{
|
{
|
||||||
MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
System.Windows.Forms.Application.Exit();
|
Application.Exit();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,23 +170,19 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
||||||
if (upgradeProperties is null)
|
if (upgradeProperties is null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
#if WINDOWS7_0_OR_GREATER
|
|
||||||
MessageBoxLib.ShowAdminAlert(null, "Error checking for update", "Error checking for update", ex);
|
MessageBoxLib.ShowAdminAlert(null, "Error checking for update", "Error checking for update", ex);
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upgradeProperties.ZipUrl is null)
|
if (upgradeProperties.ZipUrl is null)
|
||||||
{
|
{
|
||||||
#if WINDOWS7_0_OR_GREATER
|
|
||||||
MessageBox.Show(upgradeProperties.HtmlUrl, "New version available");
|
MessageBox.Show(upgradeProperties.HtmlUrl, "New version available");
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,10 +195,10 @@ namespace LibationWinForms
|
|||||||
AppDomain.CurrentDomain.UnhandledException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has crashed due to an unhandled error.", "Application crash!", (Exception)e.ExceptionObject);
|
AppDomain.CurrentDomain.UnhandledException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has crashed due to an unhandled error.", "Application crash!", (Exception)e.ExceptionObject);
|
||||||
|
|
||||||
// these 2 lines makes it graceful. sync (eg in main form's ctor) and thread exceptions will still crash us, but event (sync, void async, Task async) will not
|
// these 2 lines makes it graceful. sync (eg in main form's ctor) and thread exceptions will still crash us, but event (sync, void async, Task async) will not
|
||||||
System.Windows.Forms.Application.ThreadException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has encountered an unexpected error.", "Unexpected error", e.Exception);
|
Application.ThreadException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has encountered an unexpected error.", "Unexpected error", e.Exception);
|
||||||
// move to beginning of execution. crashes app if this is called post-RunInstaller: System.InvalidOperationException: 'Thread exception mode cannot be changed once any Controls are created on the thread.'
|
// move to beginning of execution. crashes app if this is called post-RunInstaller: System.InvalidOperationException: 'Thread exception mode cannot be changed once any Controls are created on the thread.'
|
||||||
//// I never found a case where including made a difference. I think this enum is default and including it will override app user config file
|
//// I never found a case where including made a difference. I think this enum is default and including it will override app user config file
|
||||||
//Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
//Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user