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;