diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d34d9e3..26fc2fc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,10 +19,10 @@ jobs: dotnet-version: '9.0.x' - name: Build and Publish AvaloniaVisualBasic.Desktop (Windows) - run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/windows/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/windows/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Build and Publish AvaloniaVisualBasic.Standalone (Windows) - run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/windows/standalone/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/windows/standalone/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Remove Debug Symbols (Windows) run: | @@ -66,10 +66,10 @@ jobs: java-version: '21' - name: Build and Publish AvaloniaVisualBasic.Desktop (Linux) - run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/linux/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/linux/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Build and Publish AvaloniaVisualBasic.Standalone (Linux) - run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/linux/standalone/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/linux/standalone/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Remove Debug Symbols (Linux) run: | @@ -112,10 +112,10 @@ jobs: dotnet-version: '9.0.x' - name: Build and Publish AvaloniaVisualBasic.Desktop (macOS) - run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/macos/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Desktop -f net9.0 -o bin/macos/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Build and Publish AvaloniaVisualBasic.Standalone (macOS) - run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/macos/standalone/ -p:PublishAot=true -p:PublishTrimmed=true + run: dotnet publish AvaloniaVisualBasic.Standalone -f net9.0 -o bin/macos/standalone/ -p:PublishAot=true -p:PublishTrimmed=true -p:WarningAsErrors=false - name: Remove Debug Symbols (macOS) run: | diff --git a/AvaloniaVisualBasic.Browser/AvaloniaVisualBasic.Browser.csproj b/AvaloniaVisualBasic.Browser/AvaloniaVisualBasic.Browser.csproj index 28fd1ab..3076b1e 100644 --- a/AvaloniaVisualBasic.Browser/AvaloniaVisualBasic.Browser.csproj +++ b/AvaloniaVisualBasic.Browser/AvaloniaVisualBasic.Browser.csproj @@ -28,21 +28,4 @@ - - - - - <_WasmLinkStepArgs Remove="@(_EmccLinkStepArgs)" /> - <_EmccLinkStepArgs Remove=""%(_WasmNativeFileForLinking.Identity)"" /> - <_WasmLinkDependencies Remove="@(_WasmNativeFileForLinking)" /> - - <_SkiaSharpToReorder Include="@(_WasmNativeFileForLinking)" Condition="$([System.String]::Copy('%(FullPath)').Contains('SkiaSharp'))" /> - <_WasmNativeFileForLinking Remove="@(_SkiaSharpToReorder)" /> - <_WasmNativeFileForLinking Include="@(_SkiaSharpToReorder)" /> - - <_EmccLinkStepArgs Include=""%(_WasmNativeFileForLinking.Identity)"" /> - <_WasmLinkDependencies Include="@(_WasmNativeFileForLinking)" /> - <_WasmLinkStepArgs Include="@(_EmccLinkStepArgs)" /> - - diff --git a/AvaloniaVisualBasic.Desktop/AvaloniaVisualBasic.Desktop.csproj b/AvaloniaVisualBasic.Desktop/AvaloniaVisualBasic.Desktop.csproj index 12e80af..ab67893 100644 --- a/AvaloniaVisualBasic.Desktop/AvaloniaVisualBasic.Desktop.csproj +++ b/AvaloniaVisualBasic.Desktop/AvaloniaVisualBasic.Desktop.csproj @@ -7,6 +7,9 @@ enable true vb6icon.ico + true + $(NoWarn);CS1998 + IL2026;IL3053;IL2104; @@ -15,6 +18,7 @@ + diff --git a/AvaloniaVisualBasic.Runtime/AvaloniaInterop/AvaloniaMethodsInteroperability.cs b/AvaloniaVisualBasic.Runtime/AvaloniaInterop/AvaloniaMethodsInteroperability.cs index c01f8b5..097a23b 100644 --- a/AvaloniaVisualBasic.Runtime/AvaloniaInterop/AvaloniaMethodsInteroperability.cs +++ b/AvaloniaVisualBasic.Runtime/AvaloniaInterop/AvaloniaMethodsInteroperability.cs @@ -24,6 +24,5 @@ public static Vb6Value Call(this Control c, string method, IReadOnlyListnullable true full + true + $(NoWarn);CS1998 diff --git a/AvaloniaVisualBasic.Runtime/BuiltinControls/VBLabel.axaml.cs b/AvaloniaVisualBasic.Runtime/BuiltinControls/VBLabel.axaml.cs index 70bcfae..891ef5a 100644 --- a/AvaloniaVisualBasic.Runtime/BuiltinControls/VBLabel.axaml.cs +++ b/AvaloniaVisualBasic.Runtime/BuiltinControls/VBLabel.axaml.cs @@ -80,8 +80,6 @@ public bool RecognizesAccessKey } private ClassicBorderDecorator? decorator; - private TextBlock? textblock; - private AccessText? accessText; protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { diff --git a/AvaloniaVisualBasic.Runtime/Interpreter/ExpressionExecutor.cs b/AvaloniaVisualBasic.Runtime/Interpreter/ExpressionExecutor.cs index caf57f7..6eec115 100644 --- a/AvaloniaVisualBasic.Runtime/Interpreter/ExpressionExecutor.cs +++ b/AvaloniaVisualBasic.Runtime/Interpreter/ExpressionExecutor.cs @@ -285,7 +285,7 @@ public async Task ExtractIdentifier(VB6Parser.ICS_S_VariableOrProcedureC { return array.GetValue(AsType(args)); } - catch (IndexOutOfRangeException _) + catch (IndexOutOfRangeException) { throw new VBRunTimeException(procOrArrayCall, VBStandardError.SubscriptOutOfRange); } diff --git a/AvaloniaVisualBasic.Runtime/Interpreter/StatementExecutor.cs b/AvaloniaVisualBasic.Runtime/Interpreter/StatementExecutor.cs index 41c9d60..6860853 100644 --- a/AvaloniaVisualBasic.Runtime/Interpreter/StatementExecutor.cs +++ b/AvaloniaVisualBasic.Runtime/Interpreter/StatementExecutor.cs @@ -450,8 +450,6 @@ public override async Task VisitLetStmt(VB6Parser.LetStmtContext co { throw new NotImplementedException($"{context.implicitCallStmt_InStmt()} is not supported"); } - - return default; } public override async Task VisitLineInputStmt(VB6Parser.LineInputStmtContext context) diff --git a/AvaloniaVisualBasic.Runtime/Interpreter/VB6Visitor.cs b/AvaloniaVisualBasic.Runtime/Interpreter/VB6Visitor.cs index 408fd89..81ec3ca 100644 --- a/AvaloniaVisualBasic.Runtime/Interpreter/VB6Visitor.cs +++ b/AvaloniaVisualBasic.Runtime/Interpreter/VB6Visitor.cs @@ -6,76 +6,76 @@ namespace AvaloniaVisualBasic.Runtime.Interpreter; public abstract class VB6Visitor : VB6BaseVisitor { - public T AsType(Vb6Value value) + public TT AsType(Vb6Value value) { - if (!TryUnpack(value, out T val)) + if (!TryUnpack(value, out TT val)) throw new VBCompileErrorException("Type mismatch"); return val; } - public List AsType(IReadOnlyList indexes) + public List AsType(IReadOnlyList indexes) { - return indexes.Select(AsType).ToList(); + return indexes.Select(AsType).ToList(); } - public bool TryUnpack(Vb6Value val, out T tout) + public bool TryUnpack(Vb6Value val, out TT tout) { tout = default!; - if (typeof(T) == typeof(int)) + if (typeof(TT) == typeof(int)) { if (val.Type == Vb6Value.ValueType.Integer) { - tout = (T)(object)(int)val.Value!; + tout = (TT)(object)(int)val.Value!; return true; } if (val.Type == Vb6Value.ValueType.String) { if (int.TryParse((string?)val.Value ?? "", out var asInt)) { - tout = (T)(object)asInt; + tout = (TT)(object)asInt; return true; } } return false; } - if (typeof(T) == typeof(bool)) + if (typeof(TT) == typeof(bool)) { if (val.Type == Vb6Value.ValueType.Boolean) { - tout = (T)(object)(bool)val.Value!; + tout = (TT)(object)(bool)val.Value!; return true; } return false; } - if (typeof(T) == typeof(float)) + if (typeof(TT) == typeof(float)) { if (val.Type == Vb6Value.ValueType.Integer) { - tout = (T)(object)(float)(int)val.Value!; + tout = (TT)(object)(float)(int)val.Value!; return true; } if (val.Type == Vb6Value.ValueType.Single) { - tout = (T)(object)(float)val.Value!; + tout = (TT)(object)(float)val.Value!; return true; } return false; } - if (typeof(T) == typeof(double)) + if (typeof(TT) == typeof(double)) { if (val.Type == Vb6Value.ValueType.Integer) { - tout = (T)(object)(double)(int)val.Value!; + tout = (TT)(object)(double)(int)val.Value!; return true; } if (val.Type == Vb6Value.ValueType.Single) { - tout = (T)(object)(float)val.Value!; + tout = (TT)(object)(float)val.Value!; return true; } if (val.Type == Vb6Value.ValueType.Double) { - tout = (T)(object)(double)val.Value!; + tout = (TT)(object)(double)val.Value!; return true; } return false; @@ -84,7 +84,7 @@ public bool TryUnpack(Vb6Value val, out T tout) return false; } - public bool TryUnpack(Vb6Value left, Vb6Value right, out T tleft, out T tright) + public bool TryUnpack(Vb6Value left, Vb6Value right, out TT tleft, out TT tright) { tright = default!; return TryUnpack(left, out tleft) && TryUnpack(right, out tright); diff --git a/AvaloniaVisualBasic.Standalone/AvaloniaVisualBasic.Standalone.csproj b/AvaloniaVisualBasic.Standalone/AvaloniaVisualBasic.Standalone.csproj index dc9cbb1..dc9be27 100644 --- a/AvaloniaVisualBasic.Standalone/AvaloniaVisualBasic.Standalone.csproj +++ b/AvaloniaVisualBasic.Standalone/AvaloniaVisualBasic.Standalone.csproj @@ -11,6 +11,8 @@ False None form.ico + true + $(NoWarn);CS1998 @@ -26,6 +28,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/AvaloniaVisualBasic/App.axaml.cs b/AvaloniaVisualBasic/App.axaml.cs index d1c56d0..a538423 100644 --- a/AvaloniaVisualBasic/App.axaml.cs +++ b/AvaloniaVisualBasic/App.axaml.cs @@ -28,6 +28,7 @@ public override void Initialize() public override void OnFrameworkInitializationCompleted() { var rootViewModel = new DISetup().Root; + Static.RootViewModel = rootViewModel; if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { diff --git a/AvaloniaVisualBasic/ApplicationCommands.cs b/AvaloniaVisualBasic/ApplicationCommands.cs index ba2bb14..7c33b30 100644 --- a/AvaloniaVisualBasic/ApplicationCommands.cs +++ b/AvaloniaVisualBasic/ApplicationCommands.cs @@ -95,7 +95,9 @@ private class BaseDisabledCommand : ICommand { public bool CanExecute(object? parameter) => false; public void Execute(object? parameter) { } +#pragma warning disable CS0067 public event EventHandler? CanExecuteChanged; +#pragma warning restore CS0067 } private static KeyModifiers GetPlatformCommandKey() diff --git a/AvaloniaVisualBasic/AvaloniaVisualBasic.csproj b/AvaloniaVisualBasic/AvaloniaVisualBasic.csproj index 08d4f24..527804b 100644 --- a/AvaloniaVisualBasic/AvaloniaVisualBasic.csproj +++ b/AvaloniaVisualBasic/AvaloniaVisualBasic.csproj @@ -5,6 +5,9 @@ latest true full + true + $(NoWarn);CS1998 + IL2026;IL3053;IL2104; @@ -32,6 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/AvaloniaVisualBasic/Controls/MDI/MDICaptionButtons.cs b/AvaloniaVisualBasic/Controls/MDI/MDICaptionButtons.cs index 921bed2..c4a8540 100644 --- a/AvaloniaVisualBasic/Controls/MDI/MDICaptionButtons.cs +++ b/AvaloniaVisualBasic/Controls/MDI/MDICaptionButtons.cs @@ -33,7 +33,7 @@ private void Attach(MDIWindow hostWindow) } } - private void Detach() + private new void Detach() { if (disposables != null) { diff --git a/AvaloniaVisualBasic/Controls/MDI/MDIHost.axaml.cs b/AvaloniaVisualBasic/Controls/MDI/MDIHost.axaml.cs index 28590fd..ae4c45d 100644 --- a/AvaloniaVisualBasic/Controls/MDI/MDIHost.axaml.cs +++ b/AvaloniaVisualBasic/Controls/MDI/MDIHost.axaml.cs @@ -54,6 +54,8 @@ public void Tile(Orientation orientation) for (int i = 0; i < windowCount; ++i) { var container = ContainerFromIndex(i); + if (container == null) + continue; MDIHostPanel.SetWindowState(container, WindowState.Normal); MDIHostPanel.SetWindowLocation(container, orientation == Orientation.Horizontal ? new Point(x, 0) : new Point(0, y)); MDIHostPanel.SetWindowSize(container, windowSize); @@ -77,6 +79,8 @@ public void Cascade() x += 20; y += 20; var container = ContainerFromIndex(i); + if (container == null) + continue; MDIHostPanel.SetWindowState(container, WindowState.Normal); MDIHostPanel.SetWindowLocation(container, new Point(x, y)); MDIHostPanel.SetWindowSize(container, windowSize); diff --git a/AvaloniaVisualBasic/Controls/MDI/MDIWindow.axaml.cs b/AvaloniaVisualBasic/Controls/MDI/MDIWindow.axaml.cs index d42b04d..90c5fa9 100644 --- a/AvaloniaVisualBasic/Controls/MDI/MDIWindow.axaml.cs +++ b/AvaloniaVisualBasic/Controls/MDI/MDIWindow.axaml.cs @@ -17,8 +17,8 @@ namespace AvaloniaVisualBasic.Controls; public class MDIWindow : ContentControl { - private ClassicBorderDecorator border; - private Border titleBar; + private ClassicBorderDecorator? border; + private Border? titleBar; public static readonly StyledProperty IconProperty = AvaloniaProperty.Register("Icon"); public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register("Title"); @@ -79,15 +79,16 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) var contentPresenter = e.NameScope.Get("PART_ContentPresenter"); contentPresenter.GetObservable(ContentPresenter.ChildProperty) - .Subscribe(new ActionObserver(control => + .Subscribe(new ActionObserver(control => { var child = contentPresenter.Child; if (child != null) { child.GetObservable(CommandManager.CommandBindingsProperty) - .Subscribe(new ActionObserver>(bindings => + .Subscribe(new ActionObserver?>(bindings => { - CommandManager.SetCommandBindings(this, bindings); + if (bindings != null) + CommandManager.SetCommandBindings(this, bindings); })); } })); @@ -134,7 +135,8 @@ private void SetResizeCursor(PointerEventArgs e) } } - border.Cursor = new Cursor(cursor); + if (border != null) + border.Cursor = new Cursor(cursor); } private void OnBorderReleased(object? sender, PointerReleasedEventArgs e) diff --git a/AvaloniaVisualBasic/Controls/Properties/PropertyColorBox.cs b/AvaloniaVisualBasic/Controls/Properties/PropertyColorBox.cs index c595f4c..be262ea 100644 --- a/AvaloniaVisualBasic/Controls/Properties/PropertyColorBox.cs +++ b/AvaloniaVisualBasic/Controls/Properties/PropertyColorBox.cs @@ -11,8 +11,6 @@ namespace AvaloniaVisualBasic.Controls; public class PropertyColorBox : TemplatedControl { private ListBox? paletteListBox, systemColorsListBox; - private bool systemColorListBoxSetting; - private bool paletteListBoxSetting; private bool syncing; public static readonly StyledProperty ColorProperty = AvaloniaProperty.Register(nameof(Color), defaultBindingMode: BindingMode.TwoWay); diff --git a/AvaloniaVisualBasic/Controls/Properties/PropertyFontBox.cs b/AvaloniaVisualBasic/Controls/Properties/PropertyFontBox.cs index 1cb80f3..7be0040 100644 --- a/AvaloniaVisualBasic/Controls/Properties/PropertyFontBox.cs +++ b/AvaloniaVisualBasic/Controls/Properties/PropertyFontBox.cs @@ -5,6 +5,7 @@ using Avalonia.Data; using Avalonia.Interactivity; using AvaloniaVisualBasic.Runtime.BuiltinTypes; +using AvaloniaVisualBasic.Utils; using Classic.CommonControls.Dialogs; namespace AvaloniaVisualBasic.Controls; @@ -36,15 +37,14 @@ private void OnButtonClick(object? sender, RoutedEventArgs e) { async Task OpenFontWindow() { - var result = await FontDialog.ShowDialog(this.VisualRoot as Window, new FontDialogResult( - Font.FontFamily, Font.Style, Font.Weight, Font.Size)); + var result = await Static.RootViewModel.WindowManager.ShowFontDialog(new FontDialogResult(Font.FontFamily, Font.Style, Font.Weight, Font.Size)); if (result != null) { SetCurrentValue(FontProperty, new VBFont(result.Family, (int)result.Size, result.Weight, result.Style)); } } - OpenFontWindow(); + OpenFontWindow().ListenErrors(); } static PropertyFontBox() diff --git a/AvaloniaVisualBasic/Converters/StringMultiplierConverter.cs b/AvaloniaVisualBasic/Converters/StringMultiplierConverter.cs index 529c9db..4b6efe1 100644 --- a/AvaloniaVisualBasic/Converters/StringMultiplierConverter.cs +++ b/AvaloniaVisualBasic/Converters/StringMultiplierConverter.cs @@ -7,7 +7,7 @@ namespace AvaloniaVisualBasic.Converters; public class StringMultiplierConverter : IValueConverter { - public string String { get; set; } + public string String { get; set; } = ""; public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { diff --git a/AvaloniaVisualBasic/Forms/ViewModels/CodeEditorViewModel.cs b/AvaloniaVisualBasic/Forms/ViewModels/CodeEditorViewModel.cs index 6b7b265..b744766 100644 --- a/AvaloniaVisualBasic/Forms/ViewModels/CodeEditorViewModel.cs +++ b/AvaloniaVisualBasic/Forms/ViewModels/CodeEditorViewModel.cs @@ -76,14 +76,14 @@ public CodeEditorViewModel(IWindowManager windowManager, })); AutoDispose(this.eventBus.Subscribe(e => { - formDefinition.UpdateCode(Document.Text); + formDefinition?.UpdateCode(Document.Text); })); AutoDispose(this.eventBus.Subscribe(e => { if (e.Form == formDefinition) RequestClose(); })); - AutoDispose(new ActionDisposable(() => formDefinition.UpdateCode(Document.Text))); + AutoDispose(new ActionDisposable(() => formDefinition?.UpdateCode(Document.Text))); } public CodeEditorViewModel Initialize(FormDefinition formElement) @@ -110,9 +110,9 @@ public void CheckSyntax(int onlyLine) } } - public void SaveForm() => projectService.SaveForm(formDefinition, false).ListenErrors(); + public void SaveForm() => projectService.SaveForm(formDefinition!, false).ListenErrors(); - public void SaveFormAs() => projectService.SaveForm(formDefinition, true).ListenErrors(); + public void SaveFormAs() => projectService.SaveForm(formDefinition!, true).ListenErrors(); public void ViewCode() => editorService.EditCode(formDefinition); diff --git a/AvaloniaVisualBasic/Forms/Views/CodeEditorView.axaml.cs b/AvaloniaVisualBasic/Forms/Views/CodeEditorView.axaml.cs index 994a8cd..2e40f1d 100644 --- a/AvaloniaVisualBasic/Forms/Views/CodeEditorView.axaml.cs +++ b/AvaloniaVisualBasic/Forms/Views/CodeEditorView.axaml.cs @@ -94,6 +94,9 @@ public async Task InsertFile() // Get top level from the current control. Alternatively, you can use Window reference instead. var topLevel = TopLevel.GetTopLevel(this); + if (topLevel == null) + return; + // Start async operation to open the dialog. var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { diff --git a/AvaloniaVisualBasic/IDE/EventBus.cs b/AvaloniaVisualBasic/IDE/EventBus.cs index b983c54..8dbcd09 100644 --- a/AvaloniaVisualBasic/IDE/EventBus.cs +++ b/AvaloniaVisualBasic/IDE/EventBus.cs @@ -44,8 +44,8 @@ private abstract class BaseHandler : System.IDisposable private class Handler : BaseHandler where T : IEvent { - private List list; - private Action action; + private List? list; + private Action? action; public Handler(List list, Action action) { @@ -55,12 +55,12 @@ public Handler(List list, Action action) public void Execute(T @event) { - action(@event); + action?.Invoke(@event); } public override void Dispose() { - list.Remove(this); + list?.Remove(this); list = null; action = null; } diff --git a/AvaloniaVisualBasic/IDE/IWindowManager.cs b/AvaloniaVisualBasic/IDE/IWindowManager.cs index 14226b2..faf9e5a 100644 --- a/AvaloniaVisualBasic/IDE/IWindowManager.cs +++ b/AvaloniaVisualBasic/IDE/IWindowManager.cs @@ -15,4 +15,6 @@ public interface IWindowManager Task InputBox(string prompt, string? caption, string defaultText); Task?> OpenFilePickerAsync(FilePickerOpenOptions options); Task SaveFilePickerAsync(FilePickerSaveOptions options); + Task ShowAbout(AboutDialogOptions options); + Task ShowFontDialog(FontDialogResult? initial = null); } \ No newline at end of file diff --git a/AvaloniaVisualBasic/IDE/ManagedWindow.cs b/AvaloniaVisualBasic/IDE/ManagedWindow.cs index 28c0082..cd79a18 100644 --- a/AvaloniaVisualBasic/IDE/ManagedWindow.cs +++ b/AvaloniaVisualBasic/IDE/ManagedWindow.cs @@ -8,7 +8,6 @@ namespace AvaloniaVisualBasic.IDE; public class ManagedWindow : MDIWindow { protected override Type StyleKeyOverride => typeof(MDIWindow); - public event Action? RequestClose; protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { diff --git a/AvaloniaVisualBasic/IDE/WindowManager.cs b/AvaloniaVisualBasic/IDE/WindowManager.cs index 61d48f2..e36ecd0 100644 --- a/AvaloniaVisualBasic/IDE/WindowManager.cs +++ b/AvaloniaVisualBasic/IDE/WindowManager.cs @@ -10,13 +10,12 @@ using AvaloniaVisualBasic.Controls; using AvaloniaVisualBasic.Utils; using Classic.CommonControls.Dialogs; -using Pure.DI; namespace AvaloniaVisualBasic.IDE; public class WindowManager : IWindowManager { - private Window? GetTopWindow(IClassicDesktopStyleApplicationLifetime lifetime) + private Window GetTopWindow(IClassicDesktopStyleApplicationLifetime lifetime) { foreach (var window in lifetime.Windows) { @@ -24,7 +23,7 @@ public class WindowManager : IWindowManager return window; } - return lifetime.MainWindow; + return lifetime.MainWindow ?? throw new Exception("No main window and trying to open a window, fatal error"); } public Task ShowManagedWindow(MDIWindow window) @@ -77,7 +76,7 @@ public async Task ShowWindow(IDialog dialog) dialog.CloseRequested -= DialogOnCloseRequested; } - else if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var window = new DialogWindow() { @@ -127,7 +126,7 @@ void InputBoxOnCloseRequested(string? result) return ret[0]; } - else if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return await Classic.CommonControls.Dialogs.InputBox.ShowDialog(GetTopWindow(desktop), prompt, caption, defaultText); } @@ -164,7 +163,7 @@ void MessageBoxOnCloseRequested(MessageBoxResult result) return ret[0]; } - else if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return await Classic.CommonControls.Dialogs.MessageBox.ShowDialog(GetTopWindow(desktop), text, caption, buttons, icon); } @@ -172,12 +171,86 @@ void MessageBoxOnCloseRequested(MessageBoxResult result) throw new NotImplementedException(); } + public async Task ShowAbout(AboutDialogOptions options) + { + if (Static.SingleView) + { + AboutDialogViewModel aboutDialogViewModel = new AboutDialogViewModel(options); + var aboutDialog = new AboutDialog() + { + DataContext = aboutDialogViewModel + }; + var task = ShowManagedWindow(out var window, "About " + options.Title, aboutDialog, false); + + aboutDialogViewModel.CloseRequested += MessageBoxOnCloseRequested; + + void MessageBoxOnCloseRequested() + { + window.CloseCommand.Execute(window.CloseCommandParameter); + } + + await task; + + aboutDialogViewModel.CloseRequested -= MessageBoxOnCloseRequested; + } + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + await AboutDialog.ShowDialog(GetTopWindow(desktop), options); + } + else + throw new NotImplementedException(); + } + + public async Task ShowFontDialog(FontDialogResult? initial = null) + { + if (Static.SingleView) + { + FontDialogViewModel fontDialogViewModel = new FontDialogViewModel(initial); + + var messageBox = new FontDialog() + { + DataContext = fontDialogViewModel + }; + var task = ShowManagedWindow(out var window, "Font", messageBox, false); + + FontDialogResult?[] ret = new FontDialogResult?[1]; + + fontDialogViewModel.AcceptRequested += Accept; + fontDialogViewModel.CancelRequested += Cancel; + + void Accept(FontDialogResult? result) + { + ret[0] = result; + window.CloseCommand.Execute(window.CloseCommandParameter); + } + + void Cancel() + { + ret[0] = null; + window.CloseCommand.Execute(window.CloseCommandParameter); + } + + await task; + + fontDialogViewModel.AcceptRequested -= Accept; + fontDialogViewModel.CancelRequested -= Cancel; + + return ret[0]; + } + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + return await FontDialog.ShowDialog(GetTopWindow(desktop), initial); + } + else + throw new NotImplementedException(); + } + public async Task?> OpenFilePickerAsync(FilePickerOpenOptions options) { - if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) + if (Application.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) throw new Exception("This is supported only for desktop apps"); - var topLevel = TopLevel.GetTopLevel(GetTopWindow(classic)); + var topLevel = TopLevel.GetTopLevel(GetTopWindow(classic))!; var files = await topLevel.StorageProvider.OpenFilePickerAsync(options); @@ -189,10 +262,10 @@ void MessageBoxOnCloseRequested(MessageBoxResult result) public async Task SaveFilePickerAsync(FilePickerSaveOptions options) { - if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) + if (Application.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) throw new Exception("This is supported only for desktop apps"); - var topLevel = TopLevel.GetTopLevel(GetTopWindow(classic)); + var topLevel = TopLevel.GetTopLevel(GetTopWindow(classic))!; var file = await topLevel.StorageProvider.SaveFilePickerAsync(options); @@ -221,7 +294,7 @@ void DialogOnCloseRequested(bool result) return ret[0]; } - else if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + else if (Application.Current!.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var window = new DialogWindow() { diff --git a/AvaloniaVisualBasic/MainView.axaml b/AvaloniaVisualBasic/MainView.axaml index a4adfdf..a6d8a83 100644 --- a/AvaloniaVisualBasic/MainView.axaml +++ b/AvaloniaVisualBasic/MainView.axaml @@ -16,15 +16,15 @@ x:Class="AvaloniaVisualBasic.MainView"> + ExecutingCommand="{CompiledBinding NYI}" /> + Executed="AvaloniaOnWeb"/> + ExecutingCommand="{CompiledBinding About}" /> windowManager; + public ToolBoxToolViewModel ToolBox { get; } public PropertiesToolViewModel Properties { get; } @@ -286,7 +290,7 @@ public void OnInitialized() public void NYI() { - MessageBox.ShowDialog((Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow, "This feature is not yet implemented.", "NYI", MessageBoxButtons.Ok, MessageBoxIcon.Information); + windowManager.MessageBox("This feature is not yet implemented", "NYI", MessageBoxButtons.Ok, MessageBoxIcon.Information); } public void SaveProject() => projectService.SaveAllProjects(false).ListenErrors(); @@ -305,6 +309,17 @@ public void NYI() public void OpenOptions() => windowManager.ShowDialog(new OptionsViewModel()); + public void About() + { + windowManager.ShowAbout(new AboutDialogOptions() + { + Copyright = "Copyleft BAndysc 2024", + Title = "Avalonia Visual Basic 6", + SubTitle = "For 32-bit and 64-bit cross-platform Development", + Icon = new Bitmap(AssetLoader.Open(new Uri("avares://AvaloniaVisualBasic/Icons/about.gif"))) + }).ListenErrors(); + } + public async Task NewProject() { await projectService.UnloadAllProjects(); @@ -341,7 +356,7 @@ public async Task OpenGithubRepo() buttons: MessageBoxButtons.YesNo) == MessageBoxResult.No) return; - TopLevel.GetTopLevel(Static.MainView).Launcher.LaunchUriAsync(new Uri("https://github.com/BAndysc/AvaloniaVisualBasic6")); + TopLevel.GetTopLevel(Static.MainView)!.Launcher.LaunchUriAsync(new Uri("https://github.com/BAndysc/AvaloniaVisualBasic6")).ListenErrors(); } public void TileHorizontally() => eventBus.Publish(new RearrangeMDIEvent(MDIRearrangeKind.TileHorizontally)); @@ -371,17 +386,18 @@ private void OpenOrActivateTool(Tool tool, bool right) var opened = FindDock(x => ReferenceEquals(x, tool)); if (opened != null) { - dockFactory.SetFocusedDockable(opened.Owner as IDock, opened); + dockFactory.SetFocusedDockable((IDock)opened.Owner!, opened); return; } - var middle = FindDock(x => x.Context?.Equals(right ? nameof(DockFactory.RightDock) : nameof(DockFactory.MiddleDock)) ?? false); + var middle = FindDock(x => x.Context?.Equals(right ? nameof(DockFactory.RightDock) : nameof(DockFactory.MiddleDock)) ?? false)!; var toolDock = dockFactory.CreateToolDock(); toolDock.ActiveDockable = tool; toolDock.Factory = dockFactory; toolDock.Proportion = 0.3; toolDock.VisibleDockables = dockFactory.CreateList(tool); toolDock.Alignment = right ? Alignment.Right : Alignment.Bottom; + middle.VisibleDockables ??= dockFactory.CreateList(); middle.VisibleDockables.Add(new ProportionalDockSplitter()); middle.VisibleDockables.Add(toolDock); dockFactory.InitDockable(toolDock, middle); diff --git a/AvaloniaVisualBasic/Static.cs b/AvaloniaVisualBasic/Static.cs index c53a69b..ec598f9 100644 --- a/AvaloniaVisualBasic/Static.cs +++ b/AvaloniaVisualBasic/Static.cs @@ -14,5 +14,7 @@ public class Static public static bool SingleView { get; set; } - public static MainView MainView { get; set; } + public static MainView MainView { get; set; } = null!; + + public static MainViewViewModel RootViewModel { get; set; } = null!; } \ No newline at end of file diff --git a/AvaloniaVisualBasic/Utils/DelegateCommand.cs b/AvaloniaVisualBasic/Utils/DelegateCommand.cs index 69ae46d..5aa5be3 100644 --- a/AvaloniaVisualBasic/Utils/DelegateCommand.cs +++ b/AvaloniaVisualBasic/Utils/DelegateCommand.cs @@ -30,6 +30,11 @@ public void Execute(object? parameter) } public event EventHandler? CanExecuteChanged; + + public void RaiseCanExecutedChanged() + { + CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } } public class DelegateCommand : ICommand diff --git a/AvaloniaVisualBasic/VisualDesigner/ViewModels/FormEditViewModel.cs b/AvaloniaVisualBasic/VisualDesigner/ViewModels/FormEditViewModel.cs index 75931c5..be474cd 100644 --- a/AvaloniaVisualBasic/VisualDesigner/ViewModels/FormEditViewModel.cs +++ b/AvaloniaVisualBasic/VisualDesigner/ViewModels/FormEditViewModel.cs @@ -84,7 +84,7 @@ public FormEditViewModel(ToolBoxToolViewModel toolsBoxToolViewModel, { orderedComponents.Add(component.Instance); } - formDefinition.UpdateComponents(orderedComponents); + formDefinition?.UpdateComponents(orderedComponents); })); AutoDispose(this.eventBus.Subscribe(e => { @@ -117,6 +117,7 @@ public FormEditViewModel Initialize(FormDefinition formElement) return this; } + /* ctr only for the previewer! */ public FormEditViewModel() { Form = new ComponentInstanceViewModel(this, new ComponentInstance(FormComponentClass.Instance, "Form1") @@ -124,6 +125,11 @@ public FormEditViewModel() .SetProperty(VBProperties.HeightProperty, 300) .SetProperty(VBProperties.CaptionProperty, "Form1")); AllComponents.Add(Form); + eventBus = null!; + projectService = null!; + editorService = null!; + windowManager = null!; + ToolsBoxToolViewModel = null!; } public void SpawnControlCenter(ComponentBaseClass componentClass) @@ -220,9 +226,9 @@ public void DeleteSelected() AllComponents.Remove(component); } - public void SaveForm() => projectService.SaveForm(formDefinition, false).ListenErrors(); + public void SaveForm() => projectService.SaveForm(formDefinition!, false).ListenErrors(); - public void SaveFormAs() => projectService.SaveForm(formDefinition, true).ListenErrors(); + public void SaveFormAs() => projectService.SaveForm(formDefinition!, true).ListenErrors(); public void ViewCode() => editorService.EditCode(formDefinition); @@ -291,7 +297,7 @@ public void RequestCode(string? subName) // this is a hack, the following line can be executed only after the window is created, it should be solved in a better way. DispatcherTimer.RunOnce(() => { - eventBus.Publish(new CreateOrNavigateToSubEvent(formDefinition, subName)); + eventBus.Publish(new CreateOrNavigateToSubEvent(formDefinition!, subName)); }, TimeSpan.FromMilliseconds(16)); } } \ No newline at end of file diff --git a/AvaloniaVisualBasic/VisualDesigner/ViewModels/MenuEditorViewModel.cs b/AvaloniaVisualBasic/VisualDesigner/ViewModels/MenuEditorViewModel.cs index b5a3ceb..bfac3b9 100644 --- a/AvaloniaVisualBasic/VisualDesigner/ViewModels/MenuEditorViewModel.cs +++ b/AvaloniaVisualBasic/VisualDesigner/ViewModels/MenuEditorViewModel.cs @@ -144,13 +144,15 @@ public partial class MenuViewModel : ObservableObject public MenuViewModel() { + caption = ""; + name = ""; } public MenuViewModel(ComponentInstance menu) { Menu = menu; caption = menu.GetPropertyOrDefault(VBProperties.CaptionProperty) ?? ""; - name = menu.GetPropertyOrDefault(VBProperties.NameProperty); + name = menu.GetPropertyOrDefault(VBProperties.NameProperty) ?? ""; isChecked = menu.GetPropertyOrDefault(VBProperties.CheckedProperty); isEnable = menu.GetPropertyOrDefault(VBProperties.EnabledProperty); isVisible = menu.GetPropertyOrDefault(VBProperties.VisibleProperty); diff --git a/AvaloniaVisualBasic/VisualDesigner/ViewModels/PropertiesToolViewModel.cs b/AvaloniaVisualBasic/VisualDesigner/ViewModels/PropertiesToolViewModel.cs index 3af3c33..cb87ac6 100644 --- a/AvaloniaVisualBasic/VisualDesigner/ViewModels/PropertiesToolViewModel.cs +++ b/AvaloniaVisualBasic/VisualDesigner/ViewModels/PropertiesToolViewModel.cs @@ -172,6 +172,7 @@ public void UpdateValue(PropertyClass propertyClass, object? value) } catch (Exception e) { + Console.WriteLine(e); windowManager.MessageBox("Invalid property value", icon: MessageBoxIcon.Error).ListenErrors(); } } diff --git a/Directory.Build.props b/Directory.Build.props index d954cbc..96ab1b8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 11.2.0 + 11.2.1 11.2.0.6 net8.0;net9.0 net9.0