From b6ce709d97991596d70fc393e926af162dca4b2e Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 21:42:34 -0400 Subject: [PATCH 01/16] Fix win forms TryGetPlatformHandle usage + add missing docs and adjustments --- src/Avalonia.Controls/TopLevel.cs | 2 +- .../Avalonia.Win32.Interop.csproj | 3 +- .../WinForms/WinFormsAvaloniaControlHost.cs | 37 +++++++++++-------- .../Avalonia.Win32.Interop/Wpf/CursorShim.cs | 4 +- .../Wpf/Direct2DImageSurface.cs | 10 ++--- .../Avalonia.Win32.Interop/Wpf/IntSize.cs | 2 +- .../Wpf/WpfAvaloniaHost.cs | 33 ++++++++++++++--- .../Wpf/WpfInteropExtensions.cs | 2 +- .../Wpf/WpfMouseDevice.cs | 5 +-- .../Wpf/WpfTopLevelImpl.cs | 6 +-- .../Wpf/WritableBitmapSurface.cs | 2 +- 11 files changed, 66 insertions(+), 40 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 98c96e4974..c7f1f45b5d 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -383,7 +383,7 @@ namespace Avalonia.Controls /// An describing the window handle, or null if the handle /// could not be retrieved. /// - public IPlatformHandle? TryGetPlatformHandle() => ((IWindowBaseImpl?) PlatformImpl)?.Handle; + public IPlatformHandle? TryGetPlatformHandle() => (PlatformImpl as IWindowBaseImpl)?.Handle; /// /// Gets the renderer for the window. diff --git a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj b/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj index 60bb75a342..6ee33b370a 100644 --- a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj +++ b/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj @@ -1,10 +1,9 @@ - net461 + net461;net6.0-windows true true true - true true Avalonia.Win32.Interoperability diff --git a/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs index 8d73bde919..f61466ead3 100644 --- a/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs @@ -2,38 +2,45 @@ using System.ComponentModel; using System.Windows.Forms; using Avalonia.Controls.Embedding; -using Avalonia.Input; -using Avalonia.VisualTree; -using Avalonia.Win32.Interop; using WinFormsControl = System.Windows.Forms.Control; -namespace Avalonia.Win32.Embedding +namespace Avalonia.Win32.Interop { + /// + /// An element that allows you to host a Avalonia control on a Windows Forms page. + /// [ToolboxItem(true)] public class WinFormsAvaloniaControlHost : WinFormsControl { - private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot(); + private readonly EmbeddableControlRoot _root = new(); - private IntPtr WindowHandle => ((WindowImpl) _root?.PlatformImpl)?.Handle?.Handle ?? IntPtr.Zero; + private IntPtr WindowHandle => _root?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero; + /// + /// Initializes a new instance of the class. + /// public WinFormsAvaloniaControlHost() { SetStyle(ControlStyles.AllPaintingInWmPaint, true); UnmanagedMethods.SetParent(WindowHandle, Handle); _root.Prepare(); if (_root.IsFocused) - _root.FocusManager.ClearFocus(); + _root.FocusManager?.ClearFocus(); _root.GotFocus += RootGotFocus; FixPosition(); } + /// + /// Gets or sets the Avalonia control hosted by the element. + /// public Avalonia.Controls.Control Content { - get { return (Avalonia.Controls.Control)_root.Content; } - set { _root.Content = value; } + get => (Avalonia.Controls.Control)_root.Content; + set => _root.Content = value; } + /// protected override void Dispose(bool disposing) { if (disposing) @@ -46,27 +53,27 @@ namespace Avalonia.Win32.Embedding UnmanagedMethods.SetFocus(WindowHandle); } + /// protected override void OnGotFocus(EventArgs e) { if (_root != null) UnmanagedMethods.SetFocus(WindowHandle); } - - - void FixPosition() + + private void FixPosition() { if (_root != null && Width > 0 && Height > 0) UnmanagedMethods.MoveWindow(WindowHandle, 0, 0, Width, Height, true); } - - - + + /// protected override void OnResize(EventArgs e) { FixPosition(); base.OnResize(e); } + /// protected override void OnPaint(PaintEventArgs e) { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs index 2ad6287689..fb94509c16 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs @@ -7,7 +7,7 @@ using System.Windows.Input; namespace Avalonia.Win32.Interop.Wpf { - static class CursorShim + internal static class CursorShim { public static Cursor FromHCursor(IntPtr hcursor) { @@ -20,7 +20,7 @@ namespace Avalonia.Win32.Interop.Wpf return rv; } - class SafeHandleShim : SafeHandle + private class SafeHandleShim : SafeHandle { public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false) { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs index f900204504..f3c6d55444 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs @@ -18,9 +18,9 @@ using Usage = SharpDX.Direct3D9.Usage; namespace Avalonia.Win32.Interop.Wpf { - class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable + internal class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable { - class SwapBuffer: IDisposable + private class SwapBuffer: IDisposable { private readonly Query _event; private readonly SharpDX.Direct3D11.Resource _resource; @@ -114,7 +114,7 @@ namespace Avalonia.Win32.Interop.Wpf [DllImport("user32.dll", SetLastError = false)] private static extern IntPtr GetDesktopWindow(); - static void EnsureDirectX() + private static void EnsureDirectX() { if(s_d3DDevice != null) return; @@ -168,13 +168,13 @@ namespace Avalonia.Win32.Interop.Wpf return _backBuffer.Target; } - static void RemoveAndDispose(ref T d) where T : IDisposable + private static void RemoveAndDispose(ref T d) where T : IDisposable { d?.Dispose(); d = default; } - void Swap() + private void Swap() { _backBuffer.Flush(); _image.Lock(); diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs index 3bfbf4bd92..6feb204c52 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs @@ -2,7 +2,7 @@ namespace Avalonia.Win32.Interop.Wpf { - struct IntSize : IEquatable + internal struct IntSize : IEquatable { public bool Equals(IntSize other) { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs index 7883c28153..b2b53f301b 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs @@ -2,15 +2,24 @@ using System.Threading; using System.Windows; using System.Windows.Markup; +using Avalonia.Win32.Interop.Wpf; +using AvControl = Avalonia.Controls.Control; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interop { + /// + /// An element that allows you to host a Avalonia control on a WPF page. + /// [ContentProperty("Content")] public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild { private WpfTopLevelImpl _impl; private readonly SynchronizationContext _sync; private bool _hasChildren; + + /// + /// Initializes a new instance of the class. + /// public WpfAvaloniaHost() { _sync = SynchronizationContext.Current; @@ -38,14 +47,17 @@ namespace Avalonia.Win32.Interop.Wpf } } - public object Content + /// + /// Gets or sets the Avalonia control hosted by the element. + /// + public AvControl Content { - get => _impl.ControlRoot.Content; + get => (AvControl)_impl.ControlRoot.Content; set => _impl.ControlRoot.Content = value; } //Separate class is needed to prevent accidental resurrection - class Disposer + private class Disposer { private readonly WpfTopLevelImpl _impl; @@ -60,6 +72,7 @@ namespace Avalonia.Win32.Interop.Wpf } } + /// protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) { _impl.InvalidateMeasure(); @@ -67,13 +80,17 @@ namespace Avalonia.Win32.Interop.Wpf return _impl.DesiredSize; } + /// protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) { _impl.Arrange(new System.Windows.Rect(arrangeSize)); return arrangeSize; } + /// protected override int VisualChildrenCount => 1; + + /// protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl; ~WpfAvaloniaHost() @@ -82,6 +99,7 @@ namespace Avalonia.Win32.Interop.Wpf _sync.Post(new Disposer(_impl).Callback, null); } + /// public void Dispose() { if (_impl != null) @@ -97,9 +115,12 @@ namespace Avalonia.Win32.Interop.Wpf void IAddChild.AddChild(object value) { if (Content == null) - Content = value; + if (value is AvControl avControl) + Content = avControl; + else + throw new InvalidOperationException("WpfAvaloniaHost.Content only accepts value of Avalonia.Controls.Control type."); else - throw new InvalidOperationException(); + throw new InvalidOperationException("WpfAvaloniaHost.Content was already set."); } void IAddChild.AddText(string text) diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs index cbfc259eda..a9955e64cc 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs @@ -1,6 +1,6 @@ namespace Avalonia.Win32.Interop.Wpf { - static class WpfInteropExtensions + internal static class WpfInteropExtensions { public static System.Windows.Point ToWpfPoint(this Point pt) => new System.Windows.Point(pt.X, pt.Y); public static System.Windows.Point ToWpfPoint(this PixelPoint pt) => new System.Windows.Point(pt.X, pt.Y); diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs index 2be9c1a558..e13505fd39 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs @@ -5,7 +5,7 @@ using Avalonia.VisualTree; namespace Avalonia.Win32.Interop.Wpf { - class WpfMouseDevice : MouseDevice + internal class WpfMouseDevice : MouseDevice { private readonly WpfTopLevelImpl _impl; @@ -14,7 +14,7 @@ namespace Avalonia.Win32.Interop.Wpf _impl = impl; } - class WpfMousePointer : Pointer + private class WpfMousePointer : Pointer { private readonly WpfTopLevelImpl _impl; @@ -35,6 +35,5 @@ namespace Avalonia.Win32.Interop.Wpf System.Windows.Input.Mouse.Capture(_impl); } } - } } diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs index 8025779c90..d554451ba4 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs @@ -19,7 +19,7 @@ using MouseButton = System.Windows.Input.MouseButton; namespace Avalonia.Win32.Interop.Wpf { - class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl + internal class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl { private HwndSource _currentHwndSource; private readonly HwndSourceHook _hook; @@ -137,7 +137,7 @@ namespace Avalonia.Win32.Interop.Wpf protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); - static RawInputModifiers GetModifiers(MouseEventArgs e) + private static RawInputModifiers GetModifiers(MouseEventArgs e) { var state = Keyboard.Modifiers; var rv = default(RawInputModifiers); @@ -161,7 +161,7 @@ namespace Avalonia.Win32.Interop.Wpf return rv; } - void MouseEvent(RawPointerEventType type, MouseEventArgs e) + private void MouseEvent(RawPointerEventType type, MouseEventArgs e) => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type, e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e))); diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs index 04b4a53580..8aed6be15b 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs @@ -8,7 +8,7 @@ using PixelFormat = Avalonia.Platform.PixelFormat; namespace Avalonia.Win32.Interop.Wpf { - class WritableBitmapSurface : IFramebufferPlatformSurface + internal class WritableBitmapSurface : IFramebufferPlatformSurface { private readonly WpfTopLevelImpl _impl; private WriteableBitmap _bitmap; From 4be09e3063bd1addf1b3d26e5323eadd43099dd7 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 21:44:54 -0400 Subject: [PATCH 02/16] Move to Avalonia.Win32.Interoperability project for correctness --- Avalonia.sln | 3 ++- samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml | 2 +- samples/interop/WindowsInteropTest/WindowsInteropTest.csproj | 2 +- src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj | 2 +- .../Avalonia.Win32.Interoperability.csproj} | 1 - .../WinForms/WinFormsAvaloniaControlHost.cs | 3 ++- .../Wpf/CursorShim.cs | 2 +- .../Wpf/Direct2DImageSurface.cs | 2 +- .../Wpf/IntSize.cs | 2 +- .../Wpf/WpfAvaloniaHost.cs | 4 ++-- .../Wpf/WpfInteropExtensions.cs | 2 +- .../Wpf/WpfMouseDevice.cs | 2 +- .../Wpf/WpfTopLevelImpl.cs | 3 ++- .../Wpf/WritableBitmapSurface.cs | 2 +- src/Windows/Avalonia.Win32/Avalonia.Win32.csproj | 2 +- 15 files changed, 18 insertions(+), 16 deletions(-) rename src/Windows/{Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj => Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj} (91%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/WinForms/WinFormsAvaloniaControlHost.cs (97%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/CursorShim.cs (95%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/Direct2DImageSurface.cs (99%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/IntSize.cs (96%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/WpfAvaloniaHost.cs (97%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/WpfInteropExtensions.cs (93%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/WpfMouseDevice.cs (96%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/WpfTopLevelImpl.cs (99%) rename src/Windows/{Avalonia.Win32.Interop => Avalonia.Win32.Interoperability}/Wpf/WritableBitmapSurface.cs (98%) diff --git a/Avalonia.sln b/Avalonia.sln index 9670327d67..0bae725d33 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -135,7 +135,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interoperability", "src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}" EndProject @@ -251,6 +251,7 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}" diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml index 1d8dc32a69..f7ad18d569 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml +++ b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml @@ -6,7 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WindowsInteropTest" xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32" - xmlns:wpf="clr-namespace:Avalonia.Win32.Interop.Wpf;assembly=Avalonia.Win32.Interop" + xmlns:wpf="clr-namespace:Avalonia.Win32.Interop.Wpf;assembly=Avalonia.Win32.Interoperability" mc:Ignorable="d" d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400"> diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index 95f77f6df9..e33091680e 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index 3c2d7b3322..bbe2a92074 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj similarity index 91% rename from src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj rename to src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index 6ee33b370a..9565bd86be 100644 --- a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -5,7 +5,6 @@ true true true - Avalonia.Win32.Interoperability diff --git a/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs similarity index 97% rename from src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs rename to src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs index f61466ead3..d04984811a 100644 --- a/src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs @@ -2,9 +2,10 @@ using System.ComponentModel; using System.Windows.Forms; using Avalonia.Controls.Embedding; +using Avalonia.Win32.Interop; using WinFormsControl = System.Windows.Forms.Control; -namespace Avalonia.Win32.Interop +namespace Avalonia.Win32.Interoperability { /// /// An element that allows you to host a Avalonia control on a Windows Forms page. diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs similarity index 95% rename from src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs index fb94509c16..a019f72cd8 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Windows.Input; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal static class CursorShim { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs similarity index 99% rename from src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs index f3c6d55444..a19fd4d3a6 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs @@ -16,7 +16,7 @@ using RenderTarget = SharpDX.Direct2D1.RenderTarget; using Surface = SharpDX.DXGI.Surface; using Usage = SharpDX.Direct3D9.Usage; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs similarity index 96% rename from src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs index 6feb204c52..a65313b6a9 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs @@ -1,6 +1,6 @@ using System; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal struct IntSize : IEquatable { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs similarity index 97% rename from src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs index b2b53f301b..1ca6abe033 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs @@ -2,10 +2,10 @@ using System.Threading; using System.Windows; using System.Windows.Markup; -using Avalonia.Win32.Interop.Wpf; +using Avalonia.Win32.Interoperability.Wpf; using AvControl = Avalonia.Controls.Control; -namespace Avalonia.Win32.Interop +namespace Avalonia.Win32.Interoperability { /// /// An element that allows you to host a Avalonia control on a WPF page. diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs similarity index 93% rename from src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs index a9955e64cc..a2d7c5dcd7 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs @@ -1,4 +1,4 @@ -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal static class WpfInteropExtensions { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs similarity index 96% rename from src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs index e13505fd39..e47631c06f 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs @@ -3,7 +3,7 @@ using Avalonia.Controls.Embedding; using Avalonia.Input; using Avalonia.VisualTree; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal class WpfMouseDevice : MouseDevice { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs similarity index 99% rename from src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs index d554451ba4..e46f029089 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs @@ -13,11 +13,12 @@ using Avalonia.Layout; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Composition; +using Avalonia.Win32.Interop; using Key = Avalonia.Input.Key; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using MouseButton = System.Windows.Input.MouseButton; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl { diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs similarity index 98% rename from src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs rename to src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs index 8aed6be15b..6a0fac3472 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs @@ -6,7 +6,7 @@ using Avalonia.Controls.Platform.Surfaces; using Avalonia.Platform; using PixelFormat = Avalonia.Platform.PixelFormat; -namespace Avalonia.Win32.Interop.Wpf +namespace Avalonia.Win32.Interoperability.Wpf { internal class WritableBitmapSurface : IFramebufferPlatformSurface { diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index 61f5996a94..2384ef6b6c 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -27,7 +27,7 @@ $(NoWarn);CA1416 - + From 79ed3b2536fe4789522b6221cfd77dd239372cdf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 22:08:42 -0400 Subject: [PATCH 03/16] Add nullable and trimming attributes --- .../Avalonia.Win32.Interoperability.csproj | 3 ++ .../WinForms/WinFormsAvaloniaControlHost.cs | 17 +++--- .../Wpf/CursorShim.cs | 2 +- .../Wpf/Direct2DImageSurface.cs | 30 ++++++----- .../Wpf/IntSize.cs | 54 ++----------------- .../Wpf/WpfAvaloniaHost.cs | 25 +++++---- .../Wpf/WpfMouseDevice.cs | 2 +- .../Wpf/WpfTopLevelImpl.cs | 42 +++++++-------- .../Wpf/WritableBitmapSurface.cs | 2 +- 9 files changed, 72 insertions(+), 105 deletions(-) diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index 9565bd86be..74b578ded4 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -5,6 +5,7 @@ true true true + true @@ -13,5 +14,7 @@ + + diff --git a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs index d04984811a..12c8d201a8 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using Avalonia.Controls.Embedding; using Avalonia.Win32.Interop; using WinFormsControl = System.Windows.Forms.Control; +using AvControl = Avalonia.Controls.Control; namespace Avalonia.Win32.Interoperability { @@ -35,9 +36,9 @@ namespace Avalonia.Win32.Interoperability /// /// Gets or sets the Avalonia control hosted by the element. /// - public Avalonia.Controls.Control Content + public AvControl? Content { - get => (Avalonia.Controls.Control)_root.Content; + get => (AvControl?)_root.Content; set => _root.Content = value; } @@ -49,7 +50,7 @@ namespace Avalonia.Win32.Interoperability base.Dispose(disposing); } - private void RootGotFocus(object sender, Interactivity.RoutedEventArgs e) + private void RootGotFocus(object? sender, Interactivity.RoutedEventArgs e) { UnmanagedMethods.SetFocus(WindowHandle); } @@ -57,14 +58,16 @@ namespace Avalonia.Win32.Interoperability /// protected override void OnGotFocus(EventArgs e) { - if (_root != null) - UnmanagedMethods.SetFocus(WindowHandle); + var handle = WindowHandle; + if (handle != default) + UnmanagedMethods.SetFocus(handle); } private void FixPosition() { - if (_root != null && Width > 0 && Height > 0) - UnmanagedMethods.MoveWindow(WindowHandle, 0, 0, Width, Height, true); + var handle = WindowHandle; + if (handle != default && Width > 0 && Height > 0) + UnmanagedMethods.MoveWindow(handle, 0, 0, Width, Height, true); } /// diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs index a019f72cd8..8719d8d1cf 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs @@ -9,7 +9,7 @@ namespace Avalonia.Win32.Interoperability.Wpf { internal static class CursorShim { - public static Cursor FromHCursor(IntPtr hcursor) + public static Cursor? FromHCursor(IntPtr hcursor) { var field = typeof(Cursor).GetFields(BindingFlags.NonPublic | BindingFlags.Instance) .FirstOrDefault(f => f.FieldType == typeof(SafeHandle)); diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs index a19fd4d3a6..76f262e17b 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs @@ -95,19 +95,19 @@ namespace Avalonia.Win32.Interoperability.Wpf public void Flush() { - s_dxDevice.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm); + s_dxDevice!.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm); s_dxDevice.ImmediateContext.Flush(); s_dxDevice.ImmediateContext.End(_event); s_dxDevice.ImmediateContext.GetData(_event).Dispose(); } } - private D3DImage _image; - private SwapBuffer _backBuffer; + private D3DImage? _image; + private SwapBuffer? _backBuffer; private readonly WpfTopLevelImpl _impl; - private static Device s_dxDevice; - private static Direct3DEx s_d3DContext; - private static DeviceEx s_d3DDevice; + private static Device? s_dxDevice; + private static Direct3DEx? s_d3DContext; + private static DeviceEx? s_d3DDevice; private Vector _oldDpi; @@ -138,7 +138,7 @@ namespace Avalonia.Win32.Interoperability.Wpf _impl = impl; } - public RenderTarget GetOrCreateRenderTarget() + public RenderTarget? GetOrCreateRenderTarget() { EnsureDirectX(); var scale = _impl.GetScaling(); @@ -168,7 +168,7 @@ namespace Avalonia.Win32.Interoperability.Wpf return _backBuffer.Target; } - private static void RemoveAndDispose(ref T d) where T : IDisposable + private static void RemoveAndDispose(ref T? d) where T : IDisposable { d?.Dispose(); d = default; @@ -176,11 +176,15 @@ namespace Avalonia.Win32.Interoperability.Wpf private void Swap() { - _backBuffer.Flush(); - _image.Lock(); - _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true); - _image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight)); - _image.Unlock(); + _backBuffer?.Flush(); + if (_image is not null) + { + _image.Lock(); + _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, + _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true); + _image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight)); + _image.Unlock(); + } } public void DestroyRenderTarget() diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs index a65313b6a9..5b156c69e2 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs @@ -1,55 +1,9 @@ -using System; +namespace Avalonia.Win32.Interoperability.Wpf; -namespace Avalonia.Win32.Interoperability.Wpf +internal record struct IntSize(double Width, double Height) { - internal struct IntSize : IEquatable + public static implicit operator IntSize(System.Windows.Size size) { - public bool Equals(IntSize other) - { - return Width == other.Width && Height == other.Height; - } - - public IntSize(int width, int height) - { - Width = width; - Height = height; - } - - public IntSize(double width, double height) : this((int) width, (int) height) - { - - } - - public static implicit operator IntSize(System.Windows.Size size) - { - return new IntSize {Width = (int) size.Width, Height = (int) size.Height}; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is IntSize size && Equals(size); - } - - public override int GetHashCode() - { - unchecked - { - return (Width * 397) ^ Height; - } - } - - public static bool operator ==(IntSize left, IntSize right) - { - return left.Equals(right); - } - - public static bool operator !=(IntSize left, IntSize right) - { - return !left.Equals(right); - } - - public int Width { get; set; } - public int Height { get; set; } + return new IntSize {Width = (int) size.Width, Height = (int) size.Height}; } } diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs index 1ca6abe033..e8beea5c4b 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs @@ -13,16 +13,18 @@ namespace Avalonia.Win32.Interoperability [ContentProperty("Content")] public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild { - private WpfTopLevelImpl _impl; + private WpfTopLevelImpl? _impl; private readonly SynchronizationContext _sync; private bool _hasChildren; + private WpfTopLevelImpl Impl => _impl ?? throw new ObjectDisposedException("WpfAvaloniaHost was already disposed."); + /// /// Initializes a new instance of the class. /// public WpfAvaloniaHost() { - _sync = SynchronizationContext.Current; + _sync = SynchronizationContext.Current!; _impl = new WpfTopLevelImpl(); _impl.ControlRoot.Prepare(); _impl.Visibility = Visibility.Visible; @@ -50,10 +52,10 @@ namespace Avalonia.Win32.Interoperability /// /// Gets or sets the Avalonia control hosted by the element. /// - public AvControl Content + public AvControl? Content { - get => (AvControl)_impl.ControlRoot.Content; - set => _impl.ControlRoot.Content = value; + get => (AvControl?)Impl.ControlRoot.Content; + set => Impl.ControlRoot.Content = value; } //Separate class is needed to prevent accidental resurrection @@ -66,7 +68,7 @@ namespace Avalonia.Win32.Interoperability _impl = impl; } - public void Callback(object state) + public void Callback(object? state) { _impl.Dispose(); } @@ -75,15 +77,16 @@ namespace Avalonia.Win32.Interoperability /// protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) { - _impl.InvalidateMeasure(); - _impl.Measure(constraint); - return _impl.DesiredSize; + var impl = Impl; + impl.InvalidateMeasure(); + impl.Measure(constraint); + return impl.DesiredSize; } /// protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) { - _impl.Arrange(new System.Windows.Rect(arrangeSize)); + Impl.Arrange(new System.Windows.Rect(arrangeSize)); return arrangeSize; } @@ -91,7 +94,7 @@ namespace Avalonia.Win32.Interoperability protected override int VisualChildrenCount => 1; /// - protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl; + protected override System.Windows.Media.Visual GetVisualChild(int index) => Impl; ~WpfAvaloniaHost() { diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs index e47631c06f..f66b17fc89 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs @@ -23,7 +23,7 @@ namespace Avalonia.Win32.Interoperability.Wpf _impl = impl; } - protected override void PlatformCapture(IInputElement control) + protected override void PlatformCapture(IInputElement? control) { if (control == null) { diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs index e46f029089..8b87e2d9d5 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs @@ -22,17 +22,17 @@ namespace Avalonia.Win32.Interoperability.Wpf { internal class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl { - private HwndSource _currentHwndSource; + private HwndSource? _currentHwndSource; + private IInputRoot? _inputRoot; private readonly HwndSourceHook _hook; private readonly ITopLevelImpl _ttl; - private IInputRoot _inputRoot; private readonly IEnumerable _surfaces; private readonly IMouseDevice _mouse; private readonly IKeyboardDevice _keyboard; private Size _finalSize; public EmbeddableControlRoot ControlRoot { get; } - internal ImageSource ImageSource { get; set; } + internal ImageSource? ImageSource { get; set; } public class CustomControlRoot : EmbeddableControlRoot, IEmbeddedLayoutRoot { @@ -43,7 +43,7 @@ namespace Avalonia.Win32.Interoperability.Wpf protected override void OnMeasureInvalidated() { - ((FrameworkElement)PlatformImpl)?.InvalidateMeasure(); + ((FrameworkElement?)PlatformImpl)?.InvalidateMeasure(); } public Size AllocatedSize => ClientSize; @@ -56,7 +56,7 @@ namespace Avalonia.Win32.Interoperability.Wpf _ttl = this; _surfaces = new object[] {new WritableBitmapSurface(this), new Direct2DImageSurface(this)}; _mouse = new WpfMouseDevice(this); - _keyboard = AvaloniaLocator.Current.GetService(); + _keyboard = AvaloniaLocator.Current.GetRequiredService(); ControlRoot = new CustomControlRoot(this); SnapsToDevicePixels = true; @@ -138,7 +138,7 @@ namespace Avalonia.Win32.Interoperability.Wpf protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); - private static RawInputModifiers GetModifiers(MouseEventArgs e) + private static RawInputModifiers GetModifiers(MouseEventArgs? e) { var state = Keyboard.Modifiers; var rv = default(RawInputModifiers); @@ -163,7 +163,7 @@ namespace Avalonia.Win32.Interoperability.Wpf } private void MouseEvent(RawPointerEventType type, MouseEventArgs e) - => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type, + => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot!, type, e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e))); protected override void OnMouseDown(MouseButtonEventArgs e) @@ -202,25 +202,25 @@ namespace Avalonia.Win32.Interoperability.Wpf } protected override void OnMouseWheel(MouseWheelEventArgs e) => - _ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot, + _ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot!, e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers(e))); protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, e); protected override void OnKeyDown(KeyEventArgs e) - => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, RawKeyEventType.KeyDown, + => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot!, RawKeyEventType.KeyDown, (Key) e.Key, GetModifiers(null))); protected override void OnKeyUp(KeyEventArgs e) - => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, _inputRoot, RawKeyEventType.KeyUp, + => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, _inputRoot!, RawKeyEventType.KeyUp, (Key)e.Key, GetModifiers(null))); protected override void OnTextInput(TextCompositionEventArgs e) - => _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, e.Text)); + => _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot!, e.Text)); - void ITopLevelImpl.SetCursor(ICursorImpl cursor) + void ITopLevelImpl.SetCursor(ICursorImpl? cursor) { if (cursor == null) Cursor = Cursors.Arrow; @@ -228,15 +228,15 @@ namespace Avalonia.Win32.Interoperability.Wpf Cursor = CursorShim.FromHCursor(handle.Handle); } - Action ITopLevelImpl.Input { get; set; } //TODO - Action ITopLevelImpl.Paint { get; set; } - Action ITopLevelImpl.Resized { get; set; } - Action ITopLevelImpl.ScalingChanged { get; set; } + Action? ITopLevelImpl.Input { get; set; } //TODO + Action? ITopLevelImpl.Paint { get; set; } + Action? ITopLevelImpl.Resized { get; set; } + Action? ITopLevelImpl.ScalingChanged { get; set; } - Action ITopLevelImpl.TransparencyLevelChanged { get; set; } + Action? ITopLevelImpl.TransparencyLevelChanged { get; set; } - Action ITopLevelImpl.Closed { get; set; } - public new Action LostFocus { get; set; } + Action? ITopLevelImpl.Closed { get; set; } + public new Action? LostFocus { get; set; } internal Vector GetScaling() { @@ -246,7 +246,7 @@ namespace Avalonia.Win32.Interoperability.Wpf return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22); } - public IPopupImpl CreatePopup() => null; + public IPopupImpl? CreatePopup() => null; public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { } @@ -256,6 +256,6 @@ namespace Avalonia.Win32.Interoperability.Wpf public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); - public object TryGetFeature(Type featureType) => null; + public object? TryGetFeature(Type featureType) => null; } } diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs index 6a0fac3472..bf824c9ea5 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs @@ -11,7 +11,7 @@ namespace Avalonia.Win32.Interoperability.Wpf internal class WritableBitmapSurface : IFramebufferPlatformSurface { private readonly WpfTopLevelImpl _impl; - private WriteableBitmap _bitmap; + private WriteableBitmap? _bitmap; public WritableBitmapSurface(WpfTopLevelImpl impl) { _impl = impl; From 691ff9f33a6e832abfdeda32ee321a2122134d1f Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 22:10:12 -0400 Subject: [PATCH 04/16] Make Avalonia.Win32.Interoperability build again on CI --- dirs.proj | 6 +++--- nukebuild/_build.csproj | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dirs.proj b/dirs.proj index d29aa61fcb..120212bd9f 100644 --- a/dirs.proj +++ b/dirs.proj @@ -14,11 +14,11 @@ + - - + + - diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 8999b7ca76..30e1200220 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -35,6 +35,12 @@ + + + + dirs.proj + + From c3738875e67bfe21ea15ffef68c10d96e7958481 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 22:14:06 -0400 Subject: [PATCH 05/16] Migrate to net462 --- build/SampleApp.props | 2 +- samples/BindingDemo/BindingDemo.csproj | 2 +- .../ControlCatalog.Desktop/ControlCatalog.Desktop.csproj | 2 +- samples/RenderDemo/RenderDemo.csproj | 2 +- samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml | 2 +- .../interop/WindowsInteropTest/WindowsInteropTest.csproj | 2 +- .../Avalonia.Win32.Interoperability.csproj | 2 +- .../Avalonia.Designer.HostApp.csproj | 2 +- src/tools/Avalonia.Designer.HostApp/Program.cs | 2 +- tests/Avalonia.UnitTests/InvariantCultureFixture.cs | 9 --------- 10 files changed, 9 insertions(+), 18 deletions(-) diff --git a/build/SampleApp.props b/build/SampleApp.props index 285f880129..6a7548e717 100644 --- a/build/SampleApp.props +++ b/build/SampleApp.props @@ -1,5 +1,5 @@ - + WinExe diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj index f094c0081c..ad89120522 100644 --- a/samples/BindingDemo/BindingDemo.csproj +++ b/samples/BindingDemo/BindingDemo.csproj @@ -13,7 +13,7 @@ - + diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index c6405dabb6..40c96a44d1 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -2,7 +2,7 @@ Exe - net461 + net462 x64 diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj index b37ecf01b9..af746e0aa5 100644 --- a/samples/RenderDemo/RenderDemo.csproj +++ b/samples/RenderDemo/RenderDemo.csproj @@ -21,7 +21,7 @@ - + diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml index f7ad18d569..27bb57afdf 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml +++ b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml @@ -6,7 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WindowsInteropTest" xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32" - xmlns:wpf="clr-namespace:Avalonia.Win32.Interop.Wpf;assembly=Avalonia.Win32.Interoperability" + xmlns:wpf="clr-namespace:Avalonia.Win32.Interopiblity;assembly=Avalonia.Win32.Interoperability" mc:Ignorable="d" d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400"> diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index e33091680e..58a58df46b 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -1,7 +1,7 @@  WinExe - net461 + net462 x64 true true diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index 74b578ded4..d6dcae1cf4 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -1,6 +1,6 @@ - net461;net6.0-windows + net462;net6.0-windows true true true diff --git a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj index f3af312d1a..20b5323ed0 100644 --- a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj +++ b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj @@ -1,7 +1,7 @@  Exe - net461;netcoreapp2.0 + net462;netcoreapp2.0 diff --git a/src/tools/Avalonia.Designer.HostApp/Program.cs b/src/tools/Avalonia.Designer.HostApp/Program.cs index 4472dac4e3..43e6101446 100644 --- a/src/tools/Avalonia.Designer.HostApp/Program.cs +++ b/src/tools/Avalonia.Designer.HostApp/Program.cs @@ -8,7 +8,7 @@ namespace Avalonia.Designer.HostApp { class Program { -#if NET461 +#if NETFRAMEWORK private static string s_appDir; private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) diff --git a/tests/Avalonia.UnitTests/InvariantCultureFixture.cs b/tests/Avalonia.UnitTests/InvariantCultureFixture.cs index 6dfc6d4202..c46dca5de6 100644 --- a/tests/Avalonia.UnitTests/InvariantCultureFixture.cs +++ b/tests/Avalonia.UnitTests/InvariantCultureFixture.cs @@ -17,22 +17,13 @@ namespace Avalonia.UnitTests public InvariantCultureFixture() { -#if NET461 - _restore = Thread.CurrentThread.CurrentCulture; - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; -#else _restore = CultureInfo.CurrentCulture; CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; -#endif } public void Dispose() { -#if NET461 - Thread.CurrentThread.CurrentCulture = _restore; -#else CultureInfo.CurrentCulture = _restore; -#endif } } } From 7618cd74c3fb710f5db7fe58af08828db7fc7177 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 22:23:43 -0400 Subject: [PATCH 06/16] Fix some minor issues with ControlCatalog on NetFramework --- .../ControlCatalog.Desktop.csproj | 7 +++++++ samples/ControlCatalog.Desktop/Program.cs | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 40c96a44d1..77b3515164 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -4,10 +4,17 @@ Exe net462 x64 + true + ../ControlCatalog.NetCore/app.manifest + + + + + diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 4d28f15e2c..eeb2095201 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -3,6 +3,8 @@ using System.Linq; using Avalonia; using Avalonia.Controls; using Avalonia.Platform; +using ControlCatalog.NetCore; +using ControlCatalog.Pages; namespace ControlCatalog { @@ -18,6 +20,15 @@ namespace ControlCatalog public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .LogToTrace() + .AfterSetup(builder => + { + builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() + { + StartupScreenIndex = 1, + }); + + EmbedSample.Implementation = new EmbedSampleWin(); + }) .UsePlatformDetect(); private static void ConfigureAssetAssembly(AppBuilder builder) From f31b42d9010ba8f3721d5eda2684e3d8c9367d93 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 23:01:19 -0400 Subject: [PATCH 07/16] Start WF control render timer when handle is created and stop when handle is destroyed --- .../WindowsInteropTest/EmbedToWinFormsDemo.cs | 23 +-- .../WinForms/WinFormsAvaloniaControlHost.cs | 147 +++++++++++------- 2 files changed, 89 insertions(+), 81 deletions(-) diff --git a/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs b/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs index e6603a817b..d37ed13559 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs +++ b/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs @@ -1,35 +1,14 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using Avalonia.Controls; -using Avalonia.Rendering; -using Avalonia.VisualTree; +using System.Windows.Forms; using ControlCatalog; namespace WindowsInteropTest { public partial class EmbedToWinFormsDemo : Form { - private readonly IRenderer _renderer; - public EmbedToWinFormsDemo() { InitializeComponent(); avaloniaHost.Content = new MainView(); - _renderer = ((TopLevel)avaloniaHost.Content.GetVisualRoot()).Renderer; - _renderer.Start(); - } - - protected override void OnClosed(EventArgs e) - { - _renderer.Stop(); - base.OnClosed(e); } } } diff --git a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs index 12c8d201a8..9ac00a8b8d 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs @@ -6,81 +6,110 @@ using Avalonia.Win32.Interop; using WinFormsControl = System.Windows.Forms.Control; using AvControl = Avalonia.Controls.Control; -namespace Avalonia.Win32.Interoperability +namespace Avalonia.Win32.Interoperability; + +/// +/// An element that allows you to host a Avalonia control on a Windows Forms page. +/// +[ToolboxItem(true)] +public class WinFormsAvaloniaControlHost : WinFormsControl { + private AvControl? _content; + private EmbeddableControlRoot? _root; + + private IntPtr WindowHandle => _root?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero; + /// - /// An element that allows you to host a Avalonia control on a Windows Forms page. + /// Initializes a new instance of the class. /// - [ToolboxItem(true)] - public class WinFormsAvaloniaControlHost : WinFormsControl + public WinFormsAvaloniaControlHost() { - private readonly EmbeddableControlRoot _root = new(); - - private IntPtr WindowHandle => _root?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero; + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + } - /// - /// Initializes a new instance of the class. - /// - public WinFormsAvaloniaControlHost() + /// + /// Gets or sets the Avalonia control hosted by the element. + /// + public AvControl? Content + { + get => _content; + set { - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - UnmanagedMethods.SetParent(WindowHandle, Handle); - _root.Prepare(); - if (_root.IsFocused) - _root.FocusManager?.ClearFocus(); - _root.GotFocus += RootGotFocus; - - FixPosition(); + if (_content != value) + { + _content = value; + if (_root is not null) + { + _root.Content = value; + } + } } + } - /// - /// Gets or sets the Avalonia control hosted by the element. - /// - public AvControl? Content - { - get => (AvControl?)_root.Content; - set => _root.Content = value; - } + /// + protected override void OnHandleCreated(EventArgs e) + { + _root = new(); + _root.Content = _content; + _root.Prepare(); + _root.Renderer.Start(); + _root.GotFocus += RootGotFocus; - /// - protected override void Dispose(bool disposing) - { - if (disposing) - _root.Dispose(); - base.Dispose(disposing); - } + FixPosition(); + + UnmanagedMethods.SetParent(WindowHandle, Handle); + base.OnHandleCreated(e); + } - private void RootGotFocus(object? sender, Interactivity.RoutedEventArgs e) - { - UnmanagedMethods.SetFocus(WindowHandle); - } + /// + protected override void OnHandleDestroyed(EventArgs e) + { + _root?.Dispose(); + _root = null; + base.OnHandleDestroyed(e); + } - /// - protected override void OnGotFocus(EventArgs e) + /// + protected override void Dispose(bool disposing) + { + if (disposing) { - var handle = WindowHandle; - if (handle != default) - UnmanagedMethods.SetFocus(handle); + _root?.Dispose(); + _root = null; } + base.Dispose(disposing); + } + + private void RootGotFocus(object? sender, Interactivity.RoutedEventArgs e) + { + UnmanagedMethods.SetFocus(WindowHandle); + } + + /// + protected override void OnGotFocus(EventArgs e) + { + var handle = WindowHandle; + if (handle != default) + UnmanagedMethods.SetFocus(handle); + } - private void FixPosition() - { - var handle = WindowHandle; - if (handle != default && Width > 0 && Height > 0) - UnmanagedMethods.MoveWindow(handle, 0, 0, Width, Height, true); - } + private void FixPosition() + { + var handle = WindowHandle; + if (handle != default && Width > 0 && Height > 0) + UnmanagedMethods.MoveWindow(handle, 0, 0, Width, Height, true); + } - /// - protected override void OnResize(EventArgs e) - { - FixPosition(); - base.OnResize(e); - } + /// + protected override void OnResize(EventArgs e) + { + FixPosition(); + base.OnResize(e); + } - /// - protected override void OnPaint(PaintEventArgs e) - { + /// + protected override void OnPaint(PaintEventArgs e) + { - } } } From d97b9acb4705d04f582d6fc71ee4370a88778117 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 23:27:39 -0400 Subject: [PATCH 08/16] Reimplement WpfAvaloniaHost to use HwndHost --- .../Avalonia.Win32.Interoperability.csproj | 3 +- .../Wpf/CursorShim.cs | 35 --- .../Wpf/Direct2DImageSurface.cs | 206 -------------- .../Wpf/IntSize.cs | 9 - .../Wpf/WpfAvaloniaHost.cs | 166 ++++------- .../Wpf/WpfInteropExtensions.cs | 12 - .../Wpf/WpfMouseDevice.cs | 39 --- .../Wpf/WpfTopLevelImpl.cs | 261 ------------------ .../Wpf/WritableBitmapSurface.cs | 67 ----- 9 files changed, 59 insertions(+), 739 deletions(-) delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index d6dcae1cf4..b967cfd5f2 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -4,16 +4,15 @@ true true true - true true + - diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs deleted file mode 100644 index 8719d8d1cf..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/CursorShim.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Windows.Input; - -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal static class CursorShim - { - public static Cursor? FromHCursor(IntPtr hcursor) - { - var field = typeof(Cursor).GetFields(BindingFlags.NonPublic | BindingFlags.Instance) - .FirstOrDefault(f => f.FieldType == typeof(SafeHandle)); - if (field == null) - return null; - var rv = (Cursor) FormatterServices.GetUninitializedObject(typeof(Cursor)); - field.SetValue(rv, new SafeHandleShim(hcursor)); - return rv; - } - - private class SafeHandleShim : SafeHandle - { - public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false) - { - this.handle = hcursor; - } - - protected override bool ReleaseHandle() => true; - - public override bool IsInvalid => false; - } - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs deleted file mode 100644 index 76f262e17b..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/Direct2DImageSurface.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Interop; -using Avalonia.Direct2D1; -using SharpDX.Direct2D1; -using SharpDX.Direct3D11; -using SharpDX.Direct3D9; -using SharpDX.DXGI; -using AlphaMode = SharpDX.Direct2D1.AlphaMode; -using Device = SharpDX.Direct3D11.Device; -using Format = SharpDX.DXGI.Format; -using Query = SharpDX.Direct3D11.Query; -using QueryType = SharpDX.Direct3D11.QueryType; -using RenderTarget = SharpDX.Direct2D1.RenderTarget; -using Surface = SharpDX.DXGI.Surface; -using Usage = SharpDX.Direct3D9.Usage; - -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable - { - private class SwapBuffer: IDisposable - { - private readonly Query _event; - private readonly SharpDX.Direct3D11.Resource _resource; - private readonly SharpDX.Direct3D11.Resource _sharedResource; - public SharpDX.Direct3D9.Surface Texture { get; } - public RenderTarget Target { get;} - public IntSize Size { get; } - - public SwapBuffer(IntSize size, Vector dpi) - { - int width = (int) size.Width; - int height = (int) size.Height; - _event = new Query(s_dxDevice, new QueryDescription {Type = QueryType.Event}); - using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription - { - Width = width, - Height = height, - ArraySize = 1, - MipLevels = 1, - Format = Format.B8G8R8A8_UNorm, - Usage = ResourceUsage.Default, - SampleDescription = new SampleDescription(2, 0), - BindFlags = BindFlags.RenderTarget, - })) - using (var surface = texture.QueryInterface()) - - { - _resource = texture.QueryInterface(); - - Target = new RenderTarget(Direct2D1Platform.Direct2D1Factory, surface, - new RenderTargetProperties - { - DpiX = (float) dpi.X, - DpiY = (float) dpi.Y, - MinLevel = FeatureLevel.Level_10, - PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied), - - }); - } - using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription - { - Width = width, - Height = height, - ArraySize = 1, - MipLevels = 1, - Format = Format.B8G8R8A8_UNorm, - Usage = ResourceUsage.Default, - SampleDescription = new SampleDescription(1, 0), - BindFlags = BindFlags.RenderTarget|BindFlags.ShaderResource, - OptionFlags = ResourceOptionFlags.Shared, - })) - using (var resource = texture.QueryInterface()) - { - _sharedResource = texture.QueryInterface(); - var handle = resource.SharedHandle; - using (var texture9 = new Texture(s_d3DDevice, texture.Description.Width, - texture.Description.Height, 1, - Usage.RenderTarget, SharpDX.Direct3D9.Format.A8R8G8B8, Pool.Default, ref handle)) - Texture = texture9.GetSurfaceLevel(0); - } - Size = size; - } - - public void Dispose() - { - Texture?.Dispose(); - Target?.Dispose(); - _resource?.Dispose(); - _sharedResource?.Dispose(); - _event?.Dispose(); - } - - public void Flush() - { - s_dxDevice!.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm); - s_dxDevice.ImmediateContext.Flush(); - s_dxDevice.ImmediateContext.End(_event); - s_dxDevice.ImmediateContext.GetData(_event).Dispose(); - } - } - - private D3DImage? _image; - private SwapBuffer? _backBuffer; - private readonly WpfTopLevelImpl _impl; - private static Device? s_dxDevice; - private static Direct3DEx? s_d3DContext; - private static DeviceEx? s_d3DDevice; - private Vector _oldDpi; - - - [DllImport("user32.dll", SetLastError = false)] - private static extern IntPtr GetDesktopWindow(); - - private static void EnsureDirectX() - { - if(s_d3DDevice != null) - return; - s_d3DContext = new Direct3DEx(); - - SharpDX.Direct3D9.PresentParameters presentparams = new SharpDX.Direct3D9.PresentParameters - { - Windowed = true, - SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard, - DeviceWindowHandle = GetDesktopWindow(), - PresentationInterval = PresentInterval.Default - }; - s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetRequiredService() - .QueryInterface(); - s_d3DDevice = new DeviceEx(s_d3DContext, 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, presentparams); - - } - - public Direct2DImageSurface(WpfTopLevelImpl impl) - { - _impl = impl; - } - - public RenderTarget? GetOrCreateRenderTarget() - { - EnsureDirectX(); - var scale = _impl.GetScaling(); - var size = new IntSize(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y); - var dpi = scale * 96; - - if (_backBuffer!=null && _backBuffer.Size == size) - return _backBuffer.Target; - - if (_image == null || _oldDpi.X != dpi.X || _oldDpi.Y != dpi.Y) - { - _image = new D3DImage(dpi.X, dpi.Y); - _oldDpi = dpi; - } - _impl.ImageSource = _image; - - RemoveAndDispose(ref _backBuffer); - if (size == default) - { - _image.Lock(); - _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero); - _image.Unlock(); - return null; - } - _backBuffer = new SwapBuffer(size, dpi); - - return _backBuffer.Target; - } - - private static void RemoveAndDispose(ref T? d) where T : IDisposable - { - d?.Dispose(); - d = default; - } - - private void Swap() - { - _backBuffer?.Flush(); - if (_image is not null) - { - _image.Lock(); - _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, - _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true); - _image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight)); - _image.Unlock(); - } - } - - public void DestroyRenderTarget() - { - RemoveAndDispose(ref _backBuffer); - } - - public void BeforeDrawing() - { - - } - - public void AfterDrawing() => Swap(); - public void Dispose() - { - RemoveAndDispose(ref _backBuffer); - } - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs deleted file mode 100644 index 5b156c69e2..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/IntSize.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Avalonia.Win32.Interoperability.Wpf; - -internal record struct IntSize(double Width, double Height) -{ - public static implicit operator IntSize(System.Windows.Size size) - { - return new IntSize {Width = (int) size.Width, Height = (int) size.Height}; - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs index e8beea5c4b..d9dfa6b5d0 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs @@ -1,134 +1,84 @@ using System; -using System.Threading; +using System.Runtime.InteropServices; using System.Windows; +using System.Windows.Interop; using System.Windows.Markup; -using Avalonia.Win32.Interoperability.Wpf; +using Avalonia.Controls.Embedding; +using Avalonia.Win32.Interop; using AvControl = Avalonia.Controls.Control; -namespace Avalonia.Win32.Interoperability +namespace Avalonia.Win32.Interoperability; + +/// +/// An element that allows you to host a Avalonia control on a WPF page. +/// +[ContentProperty("Content")] +public class WpfAvaloniaHost : HwndHost { + private EmbeddableControlRoot? _root; + private AvControl? _content; + /// - /// An element that allows you to host a Avalonia control on a WPF page. + /// Initializes a new instance of the class. /// - [ContentProperty("Content")] - public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild + public WpfAvaloniaHost() { - private WpfTopLevelImpl? _impl; - private readonly SynchronizationContext _sync; - private bool _hasChildren; + DataContextChanged += AvaloniaHwndHost_DataContextChanged; + } - private WpfTopLevelImpl Impl => _impl ?? throw new ObjectDisposedException("WpfAvaloniaHost was already disposed."); - - /// - /// Initializes a new instance of the class. - /// - public WpfAvaloniaHost() + private void AvaloniaHwndHost_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) + { + if (Content != null) { - _sync = SynchronizationContext.Current!; - _impl = new WpfTopLevelImpl(); - _impl.ControlRoot.Prepare(); - _impl.Visibility = Visibility.Visible; - SnapsToDevicePixels = true; - UseLayoutRounding = true; - PresentationSource.AddSourceChangedHandler(this, OnSourceChanged); + Content.DataContext = e.NewValue; } + } - private void OnSourceChanged(object sender, SourceChangedEventArgs e) + /// + /// Gets or sets the Avalonia control hosted by the element. + /// + public AvControl? Content + { + get => _content; + set { - if (e.NewSource != null && !_hasChildren) - { - AddLogicalChild(_impl); - AddVisualChild(_impl); - _hasChildren = true; - } - else + if (_content != value) { - RemoveVisualChild(_impl); - RemoveLogicalChild(_impl); - _hasChildren = false; + _content = value; + if (_root is not null) + { + _root.Content = value; + } + if (value != null) + { + value.DataContext = DataContext; + } } } + } - /// - /// Gets or sets the Avalonia control hosted by the element. - /// - public AvControl? Content - { - get => (AvControl?)Impl.ControlRoot.Content; - set => Impl.ControlRoot.Content = value; - } - - //Separate class is needed to prevent accidental resurrection - private class Disposer - { - private readonly WpfTopLevelImpl _impl; - - public Disposer(WpfTopLevelImpl impl) - { - _impl = impl; - } - - public void Callback(object? state) - { - _impl.Dispose(); - } - } + /// + protected override HandleRef BuildWindowCore(HandleRef hwndParent) + { + _root = new EmbeddableControlRoot(); + _root.Content = _content; + _root.Prepare(); + _root.Renderer.Start(); - /// - protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) - { - var impl = Impl; - impl.InvalidateMeasure(); - impl.Measure(constraint); - return impl.DesiredSize; - } + var handle = _root.TryGetPlatformHandle()?.Handle + ?? throw new InvalidOperationException("WpfAvaloniaHost is unable to create EmbeddableControlRoot."); - /// - protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) + if (PresentationSource.FromVisual(this) is HwndSource source) { - Impl.Arrange(new System.Windows.Rect(arrangeSize)); - return arrangeSize; + _ = UnmanagedMethods.SetParent(handle, source.Handle); } - /// - protected override int VisualChildrenCount => 1; - - /// - protected override System.Windows.Media.Visual GetVisualChild(int index) => Impl; - - ~WpfAvaloniaHost() - { - if (_impl != null) - _sync.Post(new Disposer(_impl).Callback, null); - } - - /// - public void Dispose() - { - if (_impl != null) - { - RemoveVisualChild(_impl); - RemoveLogicalChild(_impl); - _impl.Dispose(); - _impl = null; - GC.SuppressFinalize(this); - } - } - - void IAddChild.AddChild(object value) - { - if (Content == null) - if (value is AvControl avControl) - Content = avControl; - else - throw new InvalidOperationException("WpfAvaloniaHost.Content only accepts value of Avalonia.Controls.Control type."); - else - throw new InvalidOperationException("WpfAvaloniaHost.Content was already set."); - } + return new HandleRef(_root, handle); + } - void IAddChild.AddText(string text) - { - // - } + /// + protected override void DestroyWindowCore(HandleRef hwnd) + { + _root?.Dispose(); } } diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs deleted file mode 100644 index a2d7c5dcd7..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfInteropExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal static class WpfInteropExtensions - { - public static System.Windows.Point ToWpfPoint(this Point pt) => new System.Windows.Point(pt.X, pt.Y); - public static System.Windows.Point ToWpfPoint(this PixelPoint pt) => new System.Windows.Point(pt.X, pt.Y); - public static Point ToAvaloniaPoint(this System.Windows.Point pt) => new Point(pt.X, pt.Y); - public static PixelPoint ToAvaloniaPixelPoint(this System.Windows.Point pt) => new PixelPoint((int)pt.X, (int)pt.Y); - public static System.Windows.Size ToWpfSize(this Size pt) => new System.Windows.Size(pt.Width, pt.Height); - public static Size ToAvaloniaSize(this System.Windows.Size pt) => new Size(pt.Width, pt.Height); - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs deleted file mode 100644 index f66b17fc89..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfMouseDevice.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using Avalonia.Controls.Embedding; -using Avalonia.Input; -using Avalonia.VisualTree; - -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal class WpfMouseDevice : MouseDevice - { - private readonly WpfTopLevelImpl _impl; - - public WpfMouseDevice(WpfTopLevelImpl impl) : base(new WpfMousePointer(impl)) - { - _impl = impl; - } - - private class WpfMousePointer : Pointer - { - private readonly WpfTopLevelImpl _impl; - - public WpfMousePointer(WpfTopLevelImpl impl) : base(Pointer.GetNextFreeId(), PointerType.Mouse, true) - { - _impl = impl; - } - - protected override void PlatformCapture(IInputElement? control) - { - if (control == null) - { - System.Windows.Input.Mouse.Capture(null); - } - else if (((control as Visual)?.GetVisualRoot() as EmbeddableControlRoot)?.PlatformImpl != _impl) - throw new ArgumentException("Visual belongs to unknown toplevel"); - else - System.Windows.Input.Mouse.Capture(_impl); - } - } - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs deleted file mode 100644 index 8b87e2d9d5..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfTopLevelImpl.cs +++ /dev/null @@ -1,261 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using Avalonia.Controls; -using Avalonia.Controls.Embedding; -using Avalonia.Input; -using Avalonia.Input.Raw; -using Avalonia.Layout; -using Avalonia.Platform; -using Avalonia.Rendering; -using Avalonia.Rendering.Composition; -using Avalonia.Win32.Interop; -using Key = Avalonia.Input.Key; -using KeyEventArgs = System.Windows.Input.KeyEventArgs; -using MouseButton = System.Windows.Input.MouseButton; - -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl - { - private HwndSource? _currentHwndSource; - private IInputRoot? _inputRoot; - private readonly HwndSourceHook _hook; - private readonly ITopLevelImpl _ttl; - private readonly IEnumerable _surfaces; - private readonly IMouseDevice _mouse; - private readonly IKeyboardDevice _keyboard; - private Size _finalSize; - - public EmbeddableControlRoot ControlRoot { get; } - internal ImageSource? ImageSource { get; set; } - - public class CustomControlRoot : EmbeddableControlRoot, IEmbeddedLayoutRoot - { - public CustomControlRoot(WpfTopLevelImpl impl) : base(impl) - { - EnforceClientSize = false; - } - - protected override void OnMeasureInvalidated() - { - ((FrameworkElement?)PlatformImpl)?.InvalidateMeasure(); - } - - public Size AllocatedSize => ClientSize; - } - - public WpfTopLevelImpl() - { - PresentationSource.AddSourceChangedHandler(this, OnSourceChanged); - _hook = WndProc; - _ttl = this; - _surfaces = new object[] {new WritableBitmapSurface(this), new Direct2DImageSurface(this)}; - _mouse = new WpfMouseDevice(this); - _keyboard = AvaloniaLocator.Current.GetRequiredService(); - - ControlRoot = new CustomControlRoot(this); - SnapsToDevicePixels = true; - Focusable = true; - DataContextChanged += delegate - { - ControlRoot.DataContext = DataContext; - }; - } - - private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) - { - if (msg == (int)UnmanagedMethods.WindowsMessage.WM_DPICHANGED) - _ttl.ScalingChanged?.Invoke(_ttl.RenderScaling); - return IntPtr.Zero; - } - - private void OnSourceChanged(object sender, SourceChangedEventArgs e) - { - _currentHwndSource?.RemoveHook(_hook); - _currentHwndSource = e.NewSource as HwndSource; - _currentHwndSource?.AddHook(_hook); - _ttl.ScalingChanged?.Invoke(_ttl.RenderScaling); - } - - - public IRenderer CreateRenderer(IRenderRoot root) - { - return new CompositingRenderer(root, Win32Platform.Compositor, () => _surfaces); - } - - public void Dispose() - { - _ttl.Closed?.Invoke(); - foreach(var d in _surfaces.OfType()) - d.Dispose(); - } - - Size ITopLevelImpl.ClientSize => _finalSize; - Size? ITopLevelImpl.FrameSize => null; - - double ITopLevelImpl.RenderScaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1; - - IEnumerable ITopLevelImpl.Surfaces => _surfaces; - - private Size _previousSize; - protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize) - { - _finalSize = finalSize.ToAvaloniaSize(); - if (_finalSize == _previousSize) - return finalSize; - _previousSize = _finalSize; - _ttl.Resized?.Invoke(finalSize.ToAvaloniaSize(), WindowResizeReason.Unspecified); - return base.ArrangeOverride(finalSize); - } - - protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize) - { - ControlRoot.Measure(availableSize.ToAvaloniaSize()); - return ControlRoot.DesiredSize.ToWpfSize(); - } - - protected override void OnRender(DrawingContext drawingContext) - { - if(ActualHeight == 0 || ActualWidth == 0) - return; - _ttl.Paint?.Invoke(new Rect(0, 0, ActualWidth, ActualHeight)); - if (ImageSource != null) - drawingContext.DrawImage(ImageSource, new System.Windows.Rect(0, 0, ActualWidth, ActualHeight)); - } - - - - void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot; - - Point ITopLevelImpl.PointToClient(PixelPoint point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint(); - - PixelPoint ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPixelPoint(); - - protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); - - private static RawInputModifiers GetModifiers(MouseEventArgs? e) - { - var state = Keyboard.Modifiers; - var rv = default(RawInputModifiers); - if (state.HasFlag(ModifierKeys.Windows)) - rv |= RawInputModifiers.Meta; - if (state.HasFlag(ModifierKeys.Alt)) - rv |= RawInputModifiers.Alt; - if (state.HasFlag(ModifierKeys.Control)) - rv |= RawInputModifiers.Control; - if (state.HasFlag(ModifierKeys.Shift)) - rv |= RawInputModifiers.Shift; - if (e != null) - { - if (e.LeftButton == MouseButtonState.Pressed) - rv |= RawInputModifiers.LeftMouseButton; - if (e.RightButton == MouseButtonState.Pressed) - rv |= RawInputModifiers.RightMouseButton; - if (e.MiddleButton == MouseButtonState.Pressed) - rv |= RawInputModifiers.MiddleMouseButton; - } - return rv; - } - - private void MouseEvent(RawPointerEventType type, MouseEventArgs e) - => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot!, type, - e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e))); - - protected override void OnMouseDown(MouseButtonEventArgs e) - { - RawPointerEventType type; - if(e.ChangedButton == MouseButton.Left) - type = RawPointerEventType.LeftButtonDown; - else if (e.ChangedButton == MouseButton.Middle) - type = RawPointerEventType.MiddleButtonDown; - else if (e.ChangedButton == MouseButton.Right) - type = RawPointerEventType.RightButtonDown; - else - return; - MouseEvent(type, e); - Focus(); - } - - protected override void OnMouseUp(MouseButtonEventArgs e) - { - RawPointerEventType type; - if (e.ChangedButton == MouseButton.Left) - type = RawPointerEventType.LeftButtonUp; - else if (e.ChangedButton == MouseButton.Middle) - type = RawPointerEventType.MiddleButtonUp; - else if (e.ChangedButton == MouseButton.Right) - type = RawPointerEventType.RightButtonUp; - else - return; - MouseEvent(type, e); - Focus(); - } - - protected override void OnMouseMove(MouseEventArgs e) - { - MouseEvent(RawPointerEventType.Move, e); - } - - protected override void OnMouseWheel(MouseWheelEventArgs e) => - _ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot!, - e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers(e))); - - protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, e); - - protected override void OnKeyDown(KeyEventArgs e) - => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot!, RawKeyEventType.KeyDown, - (Key) e.Key, - GetModifiers(null))); - - protected override void OnKeyUp(KeyEventArgs e) - => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, _inputRoot!, RawKeyEventType.KeyUp, - (Key)e.Key, - GetModifiers(null))); - - protected override void OnTextInput(TextCompositionEventArgs e) - => _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot!, e.Text)); - - void ITopLevelImpl.SetCursor(ICursorImpl? cursor) - { - if (cursor == null) - Cursor = Cursors.Arrow; - else if (cursor is IPlatformHandle handle) - Cursor = CursorShim.FromHCursor(handle.Handle); - } - - Action? ITopLevelImpl.Input { get; set; } //TODO - Action? ITopLevelImpl.Paint { get; set; } - Action? ITopLevelImpl.Resized { get; set; } - Action? ITopLevelImpl.ScalingChanged { get; set; } - - Action? ITopLevelImpl.TransparencyLevelChanged { get; set; } - - Action? ITopLevelImpl.Closed { get; set; } - public new Action? LostFocus { get; set; } - - internal Vector GetScaling() - { - var src = PresentationSource.FromVisual(this)?.CompositionTarget; - if (src == null) - return new Vector(1, 1); - return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22); - } - - public IPopupImpl? CreatePopup() => null; - - public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { } - - public WindowTransparencyLevel TransparencyLevel { get; private set; } - - public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { } - - public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); - - public object? TryGetFeature(Type featureType) => null; - } -} diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs deleted file mode 100644 index bf824c9ea5..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WritableBitmapSurface.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using Avalonia.Controls.Platform.Surfaces; -using Avalonia.Platform; -using PixelFormat = Avalonia.Platform.PixelFormat; - -namespace Avalonia.Win32.Interoperability.Wpf -{ - internal class WritableBitmapSurface : IFramebufferPlatformSurface - { - private readonly WpfTopLevelImpl _impl; - private WriteableBitmap? _bitmap; - public WritableBitmapSurface(WpfTopLevelImpl impl) - { - _impl = impl; - } - - public ILockedFramebuffer Lock() - { - var scale = _impl.GetScaling(); - var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y); - var dpi = scale * 96; - if (_bitmap == null || _bitmap.PixelWidth != (int) size.Width || _bitmap.PixelHeight != (int) size.Height) - { - _bitmap = new WriteableBitmap((int) size.Width, (int) size.Height, dpi.X, dpi.Y, - System.Windows.Media.PixelFormats.Bgra32, null); - } - return new LockedFramebuffer(_impl, _bitmap, dpi); - } - - internal class LockedFramebuffer : ILockedFramebuffer - { - private readonly WpfTopLevelImpl _impl; - private readonly WriteableBitmap _bitmap; - - public LockedFramebuffer(WpfTopLevelImpl impl, WriteableBitmap bitmap, Vector dpi) - { - _impl = impl; - _bitmap = bitmap; - Dpi = dpi; - _bitmap.Lock(); - } - - public void Dispose() - { - _bitmap.AddDirtyRect(new Int32Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight)); - _bitmap.Unlock(); - /* - using (var fileStream = new FileStream("c:\\tools\\wat.png", FileMode.Create)) - { - BitmapEncoder encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(_bitmap)); - encoder.Save(fileStream); - }*/ - _impl.ImageSource = _bitmap; - } - - public IntPtr Address => _bitmap.BackBuffer; - public PixelSize Size => new PixelSize(_bitmap.PixelWidth, _bitmap.PixelHeight); - public int RowBytes => _bitmap.BackBufferStride; - public Vector Dpi { get; } - public PixelFormat Format => PixelFormat.Bgra8888; - } - } -} From da157ff509f058aa5bbcb4ee2898e5314d742050 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 23:28:01 -0400 Subject: [PATCH 09/16] Fix WindowsInteropTest --- .../EmbedToWinFormsDemo.Designer.cs | 4 +- .../WindowsInteropTest/EmbedToWpfDemo.xaml | 14 +++---- .../WindowsInteropTest/EmbedToWpfDemo.xaml.cs | 39 ++++--------------- .../WindowsInteropTest.csproj | 3 +- 4 files changed, 17 insertions(+), 43 deletions(-) diff --git a/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs b/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs index b5dccffd4d..d8b0724520 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs +++ b/samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs @@ -1,4 +1,4 @@ -using Avalonia.Win32.Embedding; +using Avalonia.Win32.Interoperability; namespace WindowsInteropTest { @@ -116,4 +116,4 @@ namespace WindowsInteropTest private System.Windows.Forms.GroupBox groupBox2; private WinFormsAvaloniaControlHost avaloniaHost; } -} \ No newline at end of file +} diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml index 27bb57afdf..4d043f780c 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml +++ b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml @@ -4,9 +4,7 @@ xmlns:av="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:WindowsInteropTest" - xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32" - xmlns:wpf="clr-namespace:Avalonia.Win32.Interopiblity;assembly=Avalonia.Win32.Interoperability" + xmlns:avalonia="clr-namespace:Avalonia.Win32.Interoperability;assembly=Avalonia.Win32.Interoperability" mc:Ignorable="d" d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400"> @@ -17,17 +15,17 @@ - + - + - + - + - + diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs index e1476106ee..e21ed72fa5 100644 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs +++ b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs @@ -1,52 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; +using System.Windows; using Avalonia; using Avalonia.Controls; -using Avalonia.Rendering; -using Avalonia.VisualTree; using ControlCatalog; -using Window = System.Windows.Window; namespace WindowsInteropTest { - /// - /// Interaction logic for EmbedToWpfDemo.xaml - /// - public partial class EmbedToWpfDemo : Window + public partial class EmbedToWpfDemo { - private IRenderer _renderer; public EmbedToWpfDemo() { InitializeComponent(); - var view = new MainView(); - Host.Content = view; - var tl = (TopLevel)view.GetVisualRoot(); - tl.AttachDevTools(); - _renderer = tl.Renderer; - _renderer.Start(); - var btn = (Avalonia.Controls.Button) RightBtn.Content; + Host.Content = new MainView(); + + var btn = (Button) RightBtn.Content!; btn.Click += delegate { btn.Content += "!"; }; + Loaded += OnLoaded; } - protected override void OnClosed(EventArgs e) + private void OnLoaded(object sender, RoutedEventArgs e) { - _renderer.Stop(); - base.OnClosed(e); + TopLevel.GetTopLevel((MainView)Host.Content)!.AttachDevTools(); } } } diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index 58a58df46b..6a9098b203 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -1,8 +1,7 @@  WinExe - net462 - x64 + net462;net6.0-windows true true From 7bf2b7668c583620466312ec4ae8f6d851c962df Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 22 May 2023 23:39:03 -0400 Subject: [PATCH 10/16] Use Skia in windows interop test + remove old hacks for old wpf control --- samples/interop/WindowsInteropTest/Program.cs | 7 +------ .../interop/WindowsInteropTest/WindowsInteropTest.csproj | 1 + .../Avalonia.Win32.Interoperability.csproj | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/samples/interop/WindowsInteropTest/Program.cs b/samples/interop/WindowsInteropTest/Program.cs index c2d30c67bb..830082aafe 100644 --- a/samples/interop/WindowsInteropTest/Program.cs +++ b/samples/interop/WindowsInteropTest/Program.cs @@ -16,12 +16,7 @@ namespace WindowsInteropTest System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); AppBuilder.Configure() .UseWin32() - .UseDirect2D1() - .With(new Win32PlatformOptions - { - UseWindowsUIComposition = false, - ShouldRenderOnUIThread = true // necessary for WPF - }) + .UseSkia() .SetupWithoutStarting(); System.Windows.Forms.Application.Run(new SelectorForm()); } diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index 6a9098b203..ce82403bc5 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index b967cfd5f2..74e9610ad6 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -10,7 +10,6 @@ - From 0e436dc9c1ac34c928a8825894940092423f5b39 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 23 May 2023 00:07:49 -0400 Subject: [PATCH 11/16] Fix AvaloniaPreviewerNetFullToolPath --- packages/Avalonia/Avalonia.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/Avalonia/Avalonia.props b/packages/Avalonia/Avalonia.props index a2da228887..f1dae1089b 100644 --- a/packages/Avalonia/Avalonia.props +++ b/packages/Avalonia/Avalonia.props @@ -1,7 +1,7 @@ $(MSBuildThisFileDirectory)\..\tools\netcoreapp2.0\designer\Avalonia.Designer.HostApp.dll - $(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe + $(MSBuildThisFileDirectory)\..\tools\net462\designer\Avalonia.Designer.HostApp.exe $(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll false $(UsedAvaloniaProducts);AvaloniaUI From 5c53e0cd1883fb1eb76c36ee5bed8d3cc41e4ce1 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 23 May 2023 00:44:27 -0400 Subject: [PATCH 12/16] Fix missing net461 --- packages/Avalonia/Avalonia.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj index 8f1b39ae12..ea7524fecd 100644 --- a/packages/Avalonia/Avalonia.csproj +++ b/packages/Avalonia/Avalonia.csproj @@ -1,6 +1,6 @@  - net6.0;netstandard2.0;net461;netcoreapp2.0 + net6.0;netstandard2.0;net462;netcoreapp2.0 Avalonia @@ -35,8 +35,8 @@ false None - <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net461/Avalonia.Designer.HostApp.exe"> - tools/net461/designer + <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net462/Avalonia.Designer.HostApp.exe"> + tools/net462/designer false None From 82501a689a96808fe72e00d798eba7e19e624a13 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 23 May 2023 00:47:10 -0400 Subject: [PATCH 13/16] Update PackageTags --- build/SharedVersion.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 2849262591..b7dccb1cf8 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -12,7 +12,7 @@ MIT Icon.png Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly. - avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin + avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net462;uwp;xamarin https://github.com/AvaloniaUI/Avalonia/releases git $(MSBuildThisFileDirectory)\avalonia.snk From c406b51cd01d6c44994fcbf3383934758b274ad2 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 23 May 2023 02:53:41 -0400 Subject: [PATCH 14/16] Remove WPF integration after internal discussion --- .../WindowsInteropTest/EmbedToWpfDemo.xaml | 31 ----- .../WindowsInteropTest/EmbedToWpfDemo.xaml.cs | 29 ----- samples/interop/WindowsInteropTest/Program.cs | 2 +- .../SelectorForm.Designer.cs | 76 ----------- .../WindowsInteropTest/SelectorForm.cs | 30 ----- .../WindowsInteropTest/SelectorForm.resx | 120 ------------------ .../Wpf/WpfAvaloniaHost.cs | 84 ------------ 7 files changed, 1 insertion(+), 371 deletions(-) delete mode 100644 samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml delete mode 100644 samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs delete mode 100644 samples/interop/WindowsInteropTest/SelectorForm.Designer.cs delete mode 100644 samples/interop/WindowsInteropTest/SelectorForm.cs delete mode 100644 samples/interop/WindowsInteropTest/SelectorForm.resx delete mode 100644 src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml deleted file mode 100644 index 4d043f780c..0000000000 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs b/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs deleted file mode 100644 index e21ed72fa5..0000000000 --- a/samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Windows; -using Avalonia; -using Avalonia.Controls; -using ControlCatalog; - -namespace WindowsInteropTest -{ - public partial class EmbedToWpfDemo - { - public EmbedToWpfDemo() - { - InitializeComponent(); - Host.Content = new MainView(); - - var btn = (Button) RightBtn.Content!; - btn.Click += delegate - { - btn.Content += "!"; - }; - - Loaded += OnLoaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - TopLevel.GetTopLevel((MainView)Host.Content)!.AttachDevTools(); - } - } -} diff --git a/samples/interop/WindowsInteropTest/Program.cs b/samples/interop/WindowsInteropTest/Program.cs index 830082aafe..4ebb88642b 100644 --- a/samples/interop/WindowsInteropTest/Program.cs +++ b/samples/interop/WindowsInteropTest/Program.cs @@ -18,7 +18,7 @@ namespace WindowsInteropTest .UseWin32() .UseSkia() .SetupWithoutStarting(); - System.Windows.Forms.Application.Run(new SelectorForm()); + System.Windows.Forms.Application.Run(new EmbedToWinFormsDemo()); } } } diff --git a/samples/interop/WindowsInteropTest/SelectorForm.Designer.cs b/samples/interop/WindowsInteropTest/SelectorForm.Designer.cs deleted file mode 100644 index 7cf402913e..0000000000 --- a/samples/interop/WindowsInteropTest/SelectorForm.Designer.cs +++ /dev/null @@ -1,76 +0,0 @@ -namespace WindowsInteropTest -{ - partial class SelectorForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.btnEmbedToWinForms = new System.Windows.Forms.Button(); - this.btnEmbedToWpf = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // btnEmbedToWinForms - // - this.btnEmbedToWinForms.Location = new System.Drawing.Point(12, 12); - this.btnEmbedToWinForms.Name = "btnEmbedToWinForms"; - this.btnEmbedToWinForms.Size = new System.Drawing.Size(201, 86); - this.btnEmbedToWinForms.TabIndex = 0; - this.btnEmbedToWinForms.Text = "Embed to WinForms"; - this.btnEmbedToWinForms.UseVisualStyleBackColor = true; - this.btnEmbedToWinForms.Click += new System.EventHandler(this.btnEmbedToWinForms_Click); - // - // btnEmbedToWpf - // - this.btnEmbedToWpf.Location = new System.Drawing.Point(219, 12); - this.btnEmbedToWpf.Name = "btnEmbedToWpf"; - this.btnEmbedToWpf.Size = new System.Drawing.Size(201, 86); - this.btnEmbedToWpf.TabIndex = 1; - this.btnEmbedToWpf.Text = "Embed to WPF"; - this.btnEmbedToWpf.UseVisualStyleBackColor = true; - this.btnEmbedToWpf.Click += new System.EventHandler(this.btnEmbedToWpf_Click); - // - // SelectorForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(432, 284); - this.Controls.Add(this.btnEmbedToWpf); - this.Controls.Add(this.btnEmbedToWinForms); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; - this.MaximizeBox = false; - this.Name = "SelectorForm"; - this.Text = "Interop"; - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button btnEmbedToWinForms; - private System.Windows.Forms.Button btnEmbedToWpf; - } -} - diff --git a/samples/interop/WindowsInteropTest/SelectorForm.cs b/samples/interop/WindowsInteropTest/SelectorForm.cs deleted file mode 100644 index 6430694f79..0000000000 --- a/samples/interop/WindowsInteropTest/SelectorForm.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace WindowsInteropTest -{ - public partial class SelectorForm : Form - { - public SelectorForm() - { - InitializeComponent(); - } - - private void btnEmbedToWinForms_Click(object sender, EventArgs e) - { - new EmbedToWinFormsDemo().ShowDialog(this); - } - - private void btnEmbedToWpf_Click(object sender, EventArgs e) - { - new EmbedToWpfDemo().ShowDialog(); - } - } -} diff --git a/samples/interop/WindowsInteropTest/SelectorForm.resx b/samples/interop/WindowsInteropTest/SelectorForm.resx deleted file mode 100644 index 1af7de150c..0000000000 --- a/samples/interop/WindowsInteropTest/SelectorForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs b/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs deleted file mode 100644 index d9dfa6b5d0..0000000000 --- a/src/Windows/Avalonia.Win32.Interoperability/Wpf/WpfAvaloniaHost.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Interop; -using System.Windows.Markup; -using Avalonia.Controls.Embedding; -using Avalonia.Win32.Interop; -using AvControl = Avalonia.Controls.Control; - -namespace Avalonia.Win32.Interoperability; - -/// -/// An element that allows you to host a Avalonia control on a WPF page. -/// -[ContentProperty("Content")] -public class WpfAvaloniaHost : HwndHost -{ - private EmbeddableControlRoot? _root; - private AvControl? _content; - - /// - /// Initializes a new instance of the class. - /// - public WpfAvaloniaHost() - { - DataContextChanged += AvaloniaHwndHost_DataContextChanged; - } - - private void AvaloniaHwndHost_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) - { - if (Content != null) - { - Content.DataContext = e.NewValue; - } - } - - /// - /// Gets or sets the Avalonia control hosted by the element. - /// - public AvControl? Content - { - get => _content; - set - { - if (_content != value) - { - _content = value; - if (_root is not null) - { - _root.Content = value; - } - if (value != null) - { - value.DataContext = DataContext; - } - } - } - } - - /// - protected override HandleRef BuildWindowCore(HandleRef hwndParent) - { - _root = new EmbeddableControlRoot(); - _root.Content = _content; - _root.Prepare(); - _root.Renderer.Start(); - - var handle = _root.TryGetPlatformHandle()?.Handle - ?? throw new InvalidOperationException("WpfAvaloniaHost is unable to create EmbeddableControlRoot."); - - if (PresentationSource.FromVisual(this) is HwndSource source) - { - _ = UnmanagedMethods.SetParent(handle, source.Handle); - } - - return new HandleRef(_root, handle); - } - - /// - protected override void DestroyWindowCore(HandleRef hwnd) - { - _root?.Dispose(); - } -} From 59ffdd99502dbe36dd6b6767e8ed1ea55b58c8da Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 23 May 2023 03:14:11 -0400 Subject: [PATCH 15/16] Revert to net461 --- build/SampleApp.props | 2 +- build/SharedVersion.props | 2 +- packages/Avalonia/Avalonia.csproj | 6 +++--- packages/Avalonia/Avalonia.props | 2 +- samples/BindingDemo/BindingDemo.csproj | 2 +- .../ControlCatalog.Desktop/ControlCatalog.Desktop.csproj | 2 +- samples/RenderDemo/RenderDemo.csproj | 2 +- .../interop/WindowsInteropTest/WindowsInteropTest.csproj | 2 +- .../Avalonia.Win32.Interoperability.csproj | 2 +- .../Avalonia.Designer.HostApp.csproj | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/SampleApp.props b/build/SampleApp.props index 6a7548e717..285f880129 100644 --- a/build/SampleApp.props +++ b/build/SampleApp.props @@ -1,5 +1,5 @@ - + WinExe diff --git a/build/SharedVersion.props b/build/SharedVersion.props index b7dccb1cf8..2849262591 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -12,7 +12,7 @@ MIT Icon.png Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly. - avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net462;uwp;xamarin + avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin https://github.com/AvaloniaUI/Avalonia/releases git $(MSBuildThisFileDirectory)\avalonia.snk diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj index ea7524fecd..8f1b39ae12 100644 --- a/packages/Avalonia/Avalonia.csproj +++ b/packages/Avalonia/Avalonia.csproj @@ -1,6 +1,6 @@  - net6.0;netstandard2.0;net462;netcoreapp2.0 + net6.0;netstandard2.0;net461;netcoreapp2.0 Avalonia @@ -35,8 +35,8 @@ false None - <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net462/Avalonia.Designer.HostApp.exe"> - tools/net462/designer + <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net461/Avalonia.Designer.HostApp.exe"> + tools/net461/designer false None diff --git a/packages/Avalonia/Avalonia.props b/packages/Avalonia/Avalonia.props index f1dae1089b..a2da228887 100644 --- a/packages/Avalonia/Avalonia.props +++ b/packages/Avalonia/Avalonia.props @@ -1,7 +1,7 @@ $(MSBuildThisFileDirectory)\..\tools\netcoreapp2.0\designer\Avalonia.Designer.HostApp.dll - $(MSBuildThisFileDirectory)\..\tools\net462\designer\Avalonia.Designer.HostApp.exe + $(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe $(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll false $(UsedAvaloniaProducts);AvaloniaUI diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj index ad89120522..f094c0081c 100644 --- a/samples/BindingDemo/BindingDemo.csproj +++ b/samples/BindingDemo/BindingDemo.csproj @@ -13,7 +13,7 @@ - + diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 77b3515164..2c47effa38 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -2,7 +2,7 @@ Exe - net462 + net461 x64 true ../ControlCatalog.NetCore/app.manifest diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj index af746e0aa5..b37ecf01b9 100644 --- a/samples/RenderDemo/RenderDemo.csproj +++ b/samples/RenderDemo/RenderDemo.csproj @@ -21,7 +21,7 @@ - + diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index ce82403bc5..22387c5a05 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -1,7 +1,7 @@  WinExe - net462;net6.0-windows + net461;net6.0-windows true true diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index 74e9610ad6..bf1e83fb66 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -1,6 +1,6 @@ - net462;net6.0-windows + net461;net6.0-windows true true true diff --git a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj index 20b5323ed0..f3af312d1a 100644 --- a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj +++ b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj @@ -1,7 +1,7 @@  Exe - net462;netcoreapp2.0 + net461;netcoreapp2.0 From 9b95fa58030634faa2d3e8aabed202d797d1f82a Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 30 May 2023 11:12:19 -0400 Subject: [PATCH 16/16] Make it work after merge conflicts --- .../Avalonia.Win32.Interoperability.csproj | 4 ---- .../WinForms/WinFormsAvaloniaControlHost.cs | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj index cc1dfb385c..68c6fa69c9 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj +++ b/src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj @@ -2,12 +2,8 @@ net461;net6.0-windows true - true true true - true - true - true Avalonia.Win32.Interoperability diff --git a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs index 9ac00a8b8d..1f8c30030c 100644 --- a/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs @@ -52,7 +52,7 @@ public class WinFormsAvaloniaControlHost : WinFormsControl _root = new(); _root.Content = _content; _root.Prepare(); - _root.Renderer.Start(); + _root.StartRendering(); _root.GotFocus += RootGotFocus; FixPosition(); @@ -64,6 +64,7 @@ public class WinFormsAvaloniaControlHost : WinFormsControl /// protected override void OnHandleDestroyed(EventArgs e) { + _root?.StopRendering(); _root?.Dispose(); _root = null; base.OnHandleDestroyed(e);