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 StabilityMatrix.Avalonia.ViewModels; |
||||
|
||||
namespace StabilityMatrix.Avalonia.Controls; |
||||
|
||||
[SuppressMessage("ReSharper", "VirtualMemberNeverOverridden.Global")] |
||||
public class AppWindowBase : AppWindow |
||||
{ |
||||
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 |
||||
viewModel.OnLoaded(); |
||||
await viewModel.OnLoadedAsync(); |
||||
if (DataContext is ViewModelBase viewModel) |
||||
{ |
||||
// Run synchronous load then async load |
||||
viewModel.OnLoaded(); |
||||
|
||||
// Can't block here so we'll run as async on UI thread |
||||
Dispatcher.UIThread.InvokeAsync(async () => |
||||
{ |
||||
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