Ionite
1 year ago
9 changed files with 313 additions and 18 deletions
@ -1,22 +1,33 @@ |
|||||||
using Avalonia.Interactivity; |
using System.Diagnostics.CodeAnalysis; |
||||||
|
using AsyncAwaitBestPractices; |
||||||
|
using Avalonia.Interactivity; |
||||||
|
using Avalonia.Threading; |
||||||
using FluentAvalonia.UI.Windowing; |
using FluentAvalonia.UI.Windowing; |
||||||
using StabilityMatrix.Avalonia.ViewModels; |
using StabilityMatrix.Avalonia.ViewModels; |
||||||
|
|
||||||
namespace StabilityMatrix.Avalonia.Controls; |
namespace StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "VirtualMemberNeverOverridden.Global")] |
||||||
public class AppWindowBase : AppWindow |
public class AppWindowBase : AppWindow |
||||||
{ |
{ |
||||||
protected AppWindowBase() |
protected AppWindowBase() |
||||||
{ |
{ |
||||||
AddHandler(LoadedEvent, OnLoaded); |
|
||||||
} |
} |
||||||
|
|
||||||
public virtual async void OnLoaded(object? sender, RoutedEventArgs e) |
protected override void OnLoaded(RoutedEventArgs e) |
||||||
{ |
{ |
||||||
if (DataContext is not ViewModelBase viewModel) return; |
base.OnLoaded(e); |
||||||
|
|
||||||
// ReSharper disable once MethodHasAsyncOverload |
if (DataContext is ViewModelBase viewModel) |
||||||
|
{ |
||||||
|
// Run synchronous load then async load |
||||||
viewModel.OnLoaded(); |
viewModel.OnLoaded(); |
||||||
|
|
||||||
|
// Can't block here so we'll run as async on UI thread |
||||||
|
Dispatcher.UIThread.InvokeAsync(async () => |
||||||
|
{ |
||||||
await viewModel.OnLoadedAsync(); |
await viewModel.OnLoadedAsync(); |
||||||
|
}).SafeFireAndForget(); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,16 @@ |
|||||||
|
using System; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using StabilityMatrix.Avalonia.Views.Dialogs; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; |
||||||
|
|
||||||
|
[View(typeof(ExceptionDialog))] |
||||||
|
public partial class ExceptionViewModel : ViewModelBase |
||||||
|
{ |
||||||
|
public Exception? Exception { get; set; } |
||||||
|
|
||||||
|
public string? Message => Exception?.Message; |
||||||
|
|
||||||
|
public string? ExceptionType => Exception?.GetType().Name ?? ""; |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
<controls:AppWindowBase 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" |
||||||
|
xmlns:dialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" |
||||||
|
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
|
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
|
d:DataContext="{x:Static mocks:DesignData.ExceptionViewModel}" |
||||||
|
x:DataType="dialogs:ExceptionViewModel" |
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550" |
||||||
|
Icon="/Assets/Icon.ico" |
||||||
|
Width="800" |
||||||
|
Height="550" |
||||||
|
Title="Stability Matrix - Unexpected Error" |
||||||
|
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.ExceptionDialog"> |
||||||
|
|
||||||
|
<Grid RowDefinitions="auto,*,auto"> |
||||||
|
<Grid Grid.Row="1" RowDefinitions="auto,*,auto"> |
||||||
|
<!-- Info --> |
||||||
|
<TextBlock |
||||||
|
Grid.Row="0" |
||||||
|
Theme="{DynamicResource SubtitleTextBlockStyle}" |
||||||
|
Margin="16" |
||||||
|
Text="An unexpected error occured" |
||||||
|
TextWrapping="Wrap" |
||||||
|
VerticalAlignment="Top" /> |
||||||
|
|
||||||
|
<!-- Exception details --> |
||||||
|
<DockPanel Grid.Row="1"> |
||||||
|
<Expander |
||||||
|
VerticalAlignment="Top" |
||||||
|
Header="{Binding ExceptionType, Mode=OneWay, TargetNullValue=-, FallbackValue=Unknown Exception}" |
||||||
|
IsExpanded="True" |
||||||
|
Padding="12,12,12,12" |
||||||
|
Margin="16,0,16,0"> |
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto"> |
||||||
|
<StackPanel DataContext="{Binding Exception}" Spacing="4"> |
||||||
|
<!-- Exception Message --> |
||||||
|
<TextBlock Theme="{DynamicResource BodyStrongTextBlockStyle}" Text="Details" /> |
||||||
|
<SelectableTextBlock Text="{Binding Message}" Margin="0,0,0,8" /> |
||||||
|
<!-- Callstack --> |
||||||
|
<TextBlock Theme="{DynamicResource BodyStrongTextBlockStyle}" Text="Callstack" /> |
||||||
|
<controls:Card |
||||||
|
Margin="0,0,0,8" |
||||||
|
Background="{DynamicResource ComboBoxDropDownBackground}"> |
||||||
|
<SelectableTextBlock |
||||||
|
FontSize="13" |
||||||
|
FontFamily="Cascadia Code,Consolas,Menlo,Monospace" |
||||||
|
TextWrapping="Wrap" |
||||||
|
Text="{Binding StackTrace}" /> |
||||||
|
</controls:Card> |
||||||
|
<!-- Inner exception --> |
||||||
|
<TextBlock |
||||||
|
Theme="{DynamicResource BodyStrongTextBlockStyle}" |
||||||
|
IsVisible="{Binding InnerException, Converter={x:Static ObjectConverters.IsNotNull}}" |
||||||
|
Text="Inner exception" /> |
||||||
|
<controls:Card Background="{DynamicResource ComboBoxDropDownBackground}"> |
||||||
|
<SelectableTextBlock |
||||||
|
FontSize="13" |
||||||
|
FontFamily="Cascadia Code,Consolas,Menlo,Monospace" |
||||||
|
TextWrapping="Wrap" |
||||||
|
IsVisible="{Binding InnerException, Converter={x:Static ObjectConverters.IsNotNull}}" |
||||||
|
Text="{Binding InnerException}" /> |
||||||
|
</controls:Card> |
||||||
|
</StackPanel> |
||||||
|
</ScrollViewer> |
||||||
|
</Expander> |
||||||
|
</DockPanel> |
||||||
|
<!-- Close Button --> |
||||||
|
<Button |
||||||
|
Name="ExitButton" |
||||||
|
IsDefault="True" |
||||||
|
Content="Exit Application" |
||||||
|
Click="ExitButton_OnClick" |
||||||
|
Grid.Row="2" |
||||||
|
HorizontalAlignment="Right" |
||||||
|
Margin="16" |
||||||
|
Padding="8"> |
||||||
|
</Button> |
||||||
|
</Grid> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
</controls:AppWindowBase> |
@ -0,0 +1,25 @@ |
|||||||
|
using System.Diagnostics.CodeAnalysis; |
||||||
|
using Avalonia.Interactivity; |
||||||
|
using Avalonia.Markup.Xaml; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Views.Dialogs; |
||||||
|
|
||||||
|
public partial class ExceptionDialog : AppWindowBase |
||||||
|
{ |
||||||
|
public ExceptionDialog() |
||||||
|
{ |
||||||
|
InitializeComponent(); |
||||||
|
} |
||||||
|
|
||||||
|
private void InitializeComponent() |
||||||
|
{ |
||||||
|
AvaloniaXamlLoader.Load(this); |
||||||
|
} |
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "UnusedParameter.Local")] |
||||||
|
private void ExitButton_OnClick(object? sender, RoutedEventArgs e) |
||||||
|
{ |
||||||
|
Close(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue