From 7c76b9516e9dde77e76db70f163dc02b185b6a79 Mon Sep 17 00:00:00 2001
From: myangelkamikaze <40002167+myangelkamikaze@users.noreply.github.com>
Date: Sat, 18 May 2024 18:19:06 +0900
Subject: [PATCH] Avalonia ship groups (#463)
---
.../Avalonia.Win32.Interoperability.csproj | 13 +
.../AvaloniaHwndHost.cs | 96 +++
.../UnmanagedMethods.cs | 14 +
Directory.Build.props | 6 +
ElectronicObserver.Avalonia.Samples/App.axaml | 11 +
.../App.axaml.cs | 42 ++
.../Assets/avalonia-logo.ico | Bin 0 -> 176111 bytes
...ElectronicObserver.Avalonia.Samples.csproj | 33 +
.../Program.cs | 21 +
.../ViewModels/MainViewModel.cs | 78 +++
.../ViewModels/ViewModelBase.cs | 7 +
.../Views/MainView.axaml | 69 ++
.../Views/MainView.axaml.cs | 71 ++
.../Views/MainWindow.axaml | 16 +
.../Views/MainWindow.axaml.cs | 16 +
.../app.manifest | 11 +
ElectronicObserver.Avalonia/App.xaml | 21 +
ElectronicObserver.Avalonia/App.xaml.cs | 52 ++
.../Behaviors/ColumnAutoSizeBehavior.cs | 97 +++
.../PersistentColumns/ColumnModel.cs | 15 +
.../PersistentColumnsBehavior.cs | 190 ++++++
.../PersistentColumns/SortDescriptionModel.cs | 9 +
.../ElectronicObserver.Avalonia.csproj | 46 ++
ElectronicObserver.Avalonia/Program.cs | 18 +
.../ShipGroup/IGroupItem.cs | 7 +
.../ShipGroup/ShipGroupDropHandler.cs | 68 ++
.../ShipGroup/ShipGroupItem.cs | 38 ++
.../ShipGroup/ShipGroupItemViewModel.cs | 85 +++
.../ShipGroup/ShipGroupResources.en.resx | 352 ++++++++++
.../ShipGroup/ShipGroupResources.resx | 338 ++++++++++
.../ShipGroupTranslationViewModel.cs | 106 +++
.../ShipGroup/ShipGroupView.xaml | 537 +++++++++++++++
.../ShipGroup/ShipGroupView.xaml.cs | 17 +
.../ShipGroup/ShipGroupViewModel.cs | 130 ++++
ElectronicObserver.sln | 108 +++
ElectronicObserver/App.xaml.cs | 51 +-
ElectronicObserver/AssemblyInfo.cs | 13 +
.../Common/Datagrid/ColumnSelectorView.xaml | 2 +-
.../Common/Datagrid/ColumnViewModel.cs | 46 +-
.../Common/Datagrid/DataGridViewModel.cs | 5 +-
ElectronicObserver/Data/ShipData.cs | 4 +-
ElectronicObserver/Data/ShipGroupData.cs | 58 +-
ElectronicObserver/ElectronicObserver.csproj | 2 +
ElectronicObserver/FormMainWpf.xaml | 10 +-
.../ViewModels/FormMainViewModel.cs | 79 +--
.../Window/Dialog/DialogTextSelect.cs | 18 +-
.../Wpf/ShipGroup/ShipGroupBindingProxy.cs | 7 -
.../Window/Wpf/ShipGroup/ShipGroupView.xaml | 388 -----------
.../Wpf/ShipGroup/ShipGroupView.xaml.cs | 23 -
.../Wpf/ShipGroup/ShipGroupViewModel.cs | 177 -----
.../ShipGroupAvaloniaView.xaml | 15 +
.../ShipGroupAvaloniaView.xaml.cs | 20 +
.../ShipGroupAvaloniaViewModel.cs | 616 ++++++++++++++++++
.../Wpf/ShipGroupWinforms/FormShipGroup.cs | 4 +
.../ShipGroupWinformsViewModel.cs | 2 +-
.../Window/Wpf/ViewTemplateSelector.cs | 7 +-
.../Window/Wpf/ViewTemplates.xaml | 10 +-
ElectronicObserverTypes/IShipData.cs | 8 +-
ElectronicObserverTypes/Mocks/ShipDataMock.cs | 1 +
59 files changed, 3578 insertions(+), 726 deletions(-)
create mode 100644 Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj
create mode 100644 Avalonia.Win32.Interoperability/AvaloniaHwndHost.cs
create mode 100644 Avalonia.Win32.Interoperability/UnmanagedMethods.cs
create mode 100644 Directory.Build.props
create mode 100644 ElectronicObserver.Avalonia.Samples/App.axaml
create mode 100644 ElectronicObserver.Avalonia.Samples/App.axaml.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/Assets/avalonia-logo.ico
create mode 100644 ElectronicObserver.Avalonia.Samples/ElectronicObserver.Avalonia.Samples.csproj
create mode 100644 ElectronicObserver.Avalonia.Samples/Program.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/ViewModels/MainViewModel.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/ViewModels/ViewModelBase.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/Views/MainView.axaml
create mode 100644 ElectronicObserver.Avalonia.Samples/Views/MainView.axaml.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/Views/MainWindow.axaml
create mode 100644 ElectronicObserver.Avalonia.Samples/Views/MainWindow.axaml.cs
create mode 100644 ElectronicObserver.Avalonia.Samples/app.manifest
create mode 100644 ElectronicObserver.Avalonia/App.xaml
create mode 100644 ElectronicObserver.Avalonia/App.xaml.cs
create mode 100644 ElectronicObserver.Avalonia/Behaviors/ColumnAutoSizeBehavior.cs
create mode 100644 ElectronicObserver.Avalonia/Behaviors/PersistentColumns/ColumnModel.cs
create mode 100644 ElectronicObserver.Avalonia/Behaviors/PersistentColumns/PersistentColumnsBehavior.cs
create mode 100644 ElectronicObserver.Avalonia/Behaviors/PersistentColumns/SortDescriptionModel.cs
create mode 100644 ElectronicObserver.Avalonia/ElectronicObserver.Avalonia.csproj
create mode 100644 ElectronicObserver.Avalonia/Program.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/IGroupItem.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupDropHandler.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupItem.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupItemViewModel.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupResources.en.resx
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupResources.resx
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupTranslationViewModel.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupView.xaml
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupView.xaml.cs
create mode 100644 ElectronicObserver.Avalonia/ShipGroup/ShipGroupViewModel.cs
create mode 100644 ElectronicObserver/AssemblyInfo.cs
delete mode 100644 ElectronicObserver/Window/Wpf/ShipGroup/ShipGroupBindingProxy.cs
delete mode 100644 ElectronicObserver/Window/Wpf/ShipGroup/ShipGroupView.xaml
delete mode 100644 ElectronicObserver/Window/Wpf/ShipGroup/ShipGroupView.xaml.cs
delete mode 100644 ElectronicObserver/Window/Wpf/ShipGroup/ShipGroupViewModel.cs
create mode 100644 ElectronicObserver/Window/Wpf/ShipGroupAvalonia/ShipGroupAvaloniaView.xaml
create mode 100644 ElectronicObserver/Window/Wpf/ShipGroupAvalonia/ShipGroupAvaloniaView.xaml.cs
create mode 100644 ElectronicObserver/Window/Wpf/ShipGroupAvalonia/ShipGroupAvaloniaViewModel.cs
diff --git a/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj
new file mode 100644
index 000000000..254788ab7
--- /dev/null
+++ b/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net8.0-windows
+ enable
+ true
+ true
+
+
+
+
+
+
diff --git a/Avalonia.Win32.Interoperability/AvaloniaHwndHost.cs b/Avalonia.Win32.Interoperability/AvaloniaHwndHost.cs
new file mode 100644
index 000000000..b61e6dd83
--- /dev/null
+++ b/Avalonia.Win32.Interoperability/AvaloniaHwndHost.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
+using System.Windows.Markup;
+using Avalonia.Controls.Embedding;
+using AvaloniaControl = Avalonia.Controls.Control;
+
+namespace Avalonia.Win32.Interoperability;
+
+///
+/// An element that allows you to host an Avalonia control on a WPF page.
+///
+///
+[ContentProperty("Content")]
+public class WpfAvaloniaHost : HwndHost
+{
+ private EmbeddableControlRoot? _root;
+ private AvaloniaControl? _content;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WpfAvaloniaHost()
+ {
+ DataContextChanged += AvaloniaHwndHost_DataContextChanged;
+ }
+
+ private void AvaloniaHwndHost_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ if (Content != null)
+ {
+ // todo: need to figure out what the best way is for setting the DataContext
+ // Content.DataContext = e.NewValue;
+ }
+ }
+
+ ///
+ /// Gets or sets the Avalonia control hosted by the element.
+ ///
+ public AvaloniaControl? Content
+ {
+ get => _content;
+ set
+ {
+ if (_content != value)
+ {
+ _content = value;
+
+ if (_root is not null)
+ {
+ _root.Content = value;
+ }
+
+ if (value != null)
+ {
+ // todo: need to figure out what the best way is for setting the DataContext
+ // value.DataContext = DataContext;
+ }
+ }
+ }
+ }
+
+ ///
+ protected override HandleRef BuildWindowCore(HandleRef hwndParent)
+ {
+ _root = new EmbeddableControlRoot
+ {
+ Content = _content,
+ };
+
+ _root.Prepare();
+ _root.StartRendering();
+
+ IntPtr handle = _root.TryGetPlatformHandle()?.Handle
+ ?? throw new InvalidOperationException("WpfAvaloniaHost is unable to create EmbeddableControlRoot.");
+
+ if (PresentationSource.FromVisual(this) is HwndSource source)
+ {
+ const int GWL_STYLE = -16;
+ const int WS_CHILD = 0x40000000;
+
+ _ = UnmanagedMethods.SetWindowLong(handle, GWL_STYLE, WS_CHILD);
+
+ _ = UnmanagedMethods.SetParent(handle, source.Handle);
+ }
+
+ return new HandleRef(_root, handle);
+ }
+
+ ///
+ protected override void DestroyWindowCore(HandleRef hwnd)
+ {
+ _root?.Dispose();
+ }
+}
diff --git a/Avalonia.Win32.Interoperability/UnmanagedMethods.cs b/Avalonia.Win32.Interoperability/UnmanagedMethods.cs
new file mode 100644
index 000000000..a6d9e60c2
--- /dev/null
+++ b/Avalonia.Win32.Interoperability/UnmanagedMethods.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Win32.Interoperability;
+
+internal static partial class UnmanagedMethods
+{
+ [LibraryImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static partial bool SetParent(IntPtr hWnd, IntPtr hWndNewParent);
+
+ [LibraryImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
+ public static partial uint SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
+}
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..5d8722ee0
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+ enable
+ 11.0.2
+
+
diff --git a/ElectronicObserver.Avalonia.Samples/App.axaml b/ElectronicObserver.Avalonia.Samples/App.axaml
new file mode 100644
index 000000000..d74c12231
--- /dev/null
+++ b/ElectronicObserver.Avalonia.Samples/App.axaml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/ElectronicObserver.Avalonia.Samples/App.axaml.cs b/ElectronicObserver.Avalonia.Samples/App.axaml.cs
new file mode 100644
index 000000000..5841cfbab
--- /dev/null
+++ b/ElectronicObserver.Avalonia.Samples/App.axaml.cs
@@ -0,0 +1,42 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Data.Core.Plugins;
+using Avalonia.Markup.Xaml;
+using ElectronicObserver.Avalonia.Samples.ViewModels;
+using ElectronicObserver.Avalonia.Samples.Views;
+using HotAvalonia;
+
+namespace ElectronicObserver.Avalonia.Samples;
+
+public partial class App : Application
+{
+ public override void Initialize()
+ {
+ this.EnableHotReload();
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ // Line below is needed to remove Avalonia data validation.
+ // Without this line you will get duplicate validations from both Avalonia and CT
+ BindingPlugins.DataValidators.RemoveAt(0);
+
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow
+ {
+ DataContext = new MainViewModel(),
+ };
+ }
+ else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
+ {
+ singleViewPlatform.MainView = new MainView
+ {
+ DataContext = new MainViewModel(),
+ };
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+}
diff --git a/ElectronicObserver.Avalonia.Samples/Assets/avalonia-logo.ico b/ElectronicObserver.Avalonia.Samples/Assets/avalonia-logo.ico
new file mode 100644
index 0000000000000000000000000000000000000000..da8d49ff9b94e52778f5324a1b87dd443a698b57
GIT binary patch
literal 176111
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