Browse Source

Fix win forms TryGetPlatformHandle usage + add missing docs and adjustments

pull/11488/head
Max Katz 3 years ago
parent
commit
b6ce709d97
  1. 2
      src/Avalonia.Controls/TopLevel.cs
  2. 3
      src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
  3. 37
      src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs
  4. 4
      src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs
  5. 10
      src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
  6. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs
  7. 33
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs
  8. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs
  9. 5
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs
  10. 6
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  11. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs

2
src/Avalonia.Controls/TopLevel.cs

@ -383,7 +383,7 @@ namespace Avalonia.Controls
/// An <see cref="IPlatformHandle"/> describing the window handle, or null if the handle /// An <see cref="IPlatformHandle"/> describing the window handle, or null if the handle
/// could not be retrieved. /// could not be retrieved.
/// </returns> /// </returns>
public IPlatformHandle? TryGetPlatformHandle() => ((IWindowBaseImpl?) PlatformImpl)?.Handle; public IPlatformHandle? TryGetPlatformHandle() => (PlatformImpl as IWindowBaseImpl)?.Handle;
/// <summary> /// <summary>
/// Gets the renderer for the window. /// Gets the renderer for the window.

3
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj

@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net461</TargetFramework> <TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseWpf>true</UseWpf> <UseWpf>true</UseWpf>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ExtrasEnableImplicitWinFormsReferences>true</ExtrasEnableImplicitWinFormsReferences>
<UseDirect3D9>true</UseDirect3D9> <UseDirect3D9>true</UseDirect3D9>
<PackageId>Avalonia.Win32.Interoperability</PackageId> <PackageId>Avalonia.Win32.Interoperability</PackageId>
</PropertyGroup> </PropertyGroup>

37
src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs

@ -2,38 +2,45 @@
using System.ComponentModel; using System.ComponentModel;
using System.Windows.Forms; using System.Windows.Forms;
using Avalonia.Controls.Embedding; using Avalonia.Controls.Embedding;
using Avalonia.Input;
using Avalonia.VisualTree;
using Avalonia.Win32.Interop;
using WinFormsControl = System.Windows.Forms.Control; using WinFormsControl = System.Windows.Forms.Control;
namespace Avalonia.Win32.Embedding namespace Avalonia.Win32.Interop
{ {
/// <summary>
/// An element that allows you to host a Avalonia control on a Windows Forms page.
/// </summary>
[ToolboxItem(true)] [ToolboxItem(true)]
public class WinFormsAvaloniaControlHost : WinFormsControl 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;
/// <summary>
/// Initializes a new instance of the <see cref="WinFormsAvaloniaControlHost"/> class.
/// </summary>
public WinFormsAvaloniaControlHost() public WinFormsAvaloniaControlHost()
{ {
SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true);
UnmanagedMethods.SetParent(WindowHandle, Handle); UnmanagedMethods.SetParent(WindowHandle, Handle);
_root.Prepare(); _root.Prepare();
if (_root.IsFocused) if (_root.IsFocused)
_root.FocusManager.ClearFocus(); _root.FocusManager?.ClearFocus();
_root.GotFocus += RootGotFocus; _root.GotFocus += RootGotFocus;
FixPosition(); FixPosition();
} }
/// <summary>
/// Gets or sets the Avalonia control hosted by the <see cref="WinFormsAvaloniaControlHost"/> element.
/// </summary>
public Avalonia.Controls.Control Content public Avalonia.Controls.Control Content
{ {
get { return (Avalonia.Controls.Control)_root.Content; } get => (Avalonia.Controls.Control)_root.Content;
set { _root.Content = value; } set => _root.Content = value;
} }
/// <inheritdoc />
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing) if (disposing)
@ -46,27 +53,27 @@ namespace Avalonia.Win32.Embedding
UnmanagedMethods.SetFocus(WindowHandle); UnmanagedMethods.SetFocus(WindowHandle);
} }
/// <inheritdoc />
protected override void OnGotFocus(EventArgs e) protected override void OnGotFocus(EventArgs e)
{ {
if (_root != null) if (_root != null)
UnmanagedMethods.SetFocus(WindowHandle); UnmanagedMethods.SetFocus(WindowHandle);
} }
private void FixPosition()
void FixPosition()
{ {
if (_root != null && Width > 0 && Height > 0) if (_root != null && Width > 0 && Height > 0)
UnmanagedMethods.MoveWindow(WindowHandle, 0, 0, Width, Height, true); UnmanagedMethods.MoveWindow(WindowHandle, 0, 0, Width, Height, true);
} }
/// <inheritdoc />
protected override void OnResize(EventArgs e) protected override void OnResize(EventArgs e)
{ {
FixPosition(); FixPosition();
base.OnResize(e); base.OnResize(e);
} }
/// <inheritdoc />
protected override void OnPaint(PaintEventArgs e) protected override void OnPaint(PaintEventArgs e)
{ {

4
src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs

@ -7,7 +7,7 @@ using System.Windows.Input;
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop.Wpf
{ {
static class CursorShim internal static class CursorShim
{ {
public static Cursor FromHCursor(IntPtr hcursor) public static Cursor FromHCursor(IntPtr hcursor)
{ {
@ -20,7 +20,7 @@ namespace Avalonia.Win32.Interop.Wpf
return rv; return rv;
} }
class SafeHandleShim : SafeHandle private class SafeHandleShim : SafeHandle
{ {
public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false) public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false)
{ {

10
src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs

@ -18,9 +18,9 @@ using Usage = SharpDX.Direct3D9.Usage;
namespace Avalonia.Win32.Interop.Wpf 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 Query _event;
private readonly SharpDX.Direct3D11.Resource _resource; private readonly SharpDX.Direct3D11.Resource _resource;
@ -114,7 +114,7 @@ namespace Avalonia.Win32.Interop.Wpf
[DllImport("user32.dll", SetLastError = false)] [DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr GetDesktopWindow(); private static extern IntPtr GetDesktopWindow();
static void EnsureDirectX() private static void EnsureDirectX()
{ {
if(s_d3DDevice != null) if(s_d3DDevice != null)
return; return;
@ -168,13 +168,13 @@ namespace Avalonia.Win32.Interop.Wpf
return _backBuffer.Target; return _backBuffer.Target;
} }
static void RemoveAndDispose<T>(ref T d) where T : IDisposable private static void RemoveAndDispose<T>(ref T d) where T : IDisposable
{ {
d?.Dispose(); d?.Dispose();
d = default; d = default;
} }
void Swap() private void Swap()
{ {
_backBuffer.Flush(); _backBuffer.Flush();
_image.Lock(); _image.Lock();

2
src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs

@ -2,7 +2,7 @@
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop.Wpf
{ {
struct IntSize : IEquatable<IntSize> internal struct IntSize : IEquatable<IntSize>
{ {
public bool Equals(IntSize other) public bool Equals(IntSize other)
{ {

33
src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs

@ -2,15 +2,24 @@
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Markup; using System.Windows.Markup;
using Avalonia.Win32.Interop.Wpf;
using AvControl = Avalonia.Controls.Control;
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop
{ {
/// <summary>
/// An element that allows you to host a Avalonia control on a WPF page.
/// </summary>
[ContentProperty("Content")] [ContentProperty("Content")]
public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild
{ {
private WpfTopLevelImpl _impl; private WpfTopLevelImpl _impl;
private readonly SynchronizationContext _sync; private readonly SynchronizationContext _sync;
private bool _hasChildren; private bool _hasChildren;
/// <summary>
/// Initializes a new instance of the <see cref="WpfAvaloniaHost"/> class.
/// </summary>
public WpfAvaloniaHost() public WpfAvaloniaHost()
{ {
_sync = SynchronizationContext.Current; _sync = SynchronizationContext.Current;
@ -38,14 +47,17 @@ namespace Avalonia.Win32.Interop.Wpf
} }
} }
public object Content /// <summary>
/// Gets or sets the Avalonia control hosted by the <see cref="WpfAvaloniaHost"/> element.
/// </summary>
public AvControl Content
{ {
get => _impl.ControlRoot.Content; get => (AvControl)_impl.ControlRoot.Content;
set => _impl.ControlRoot.Content = value; set => _impl.ControlRoot.Content = value;
} }
//Separate class is needed to prevent accidental resurrection //Separate class is needed to prevent accidental resurrection
class Disposer private class Disposer
{ {
private readonly WpfTopLevelImpl _impl; private readonly WpfTopLevelImpl _impl;
@ -60,6 +72,7 @@ namespace Avalonia.Win32.Interop.Wpf
} }
} }
/// <inheritdoc />
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
{ {
_impl.InvalidateMeasure(); _impl.InvalidateMeasure();
@ -67,13 +80,17 @@ namespace Avalonia.Win32.Interop.Wpf
return _impl.DesiredSize; return _impl.DesiredSize;
} }
/// <inheritdoc />
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) 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; return arrangeSize;
} }
/// <inheritdoc />
protected override int VisualChildrenCount => 1; protected override int VisualChildrenCount => 1;
/// <inheritdoc />
protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl; protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl;
~WpfAvaloniaHost() ~WpfAvaloniaHost()
@ -82,6 +99,7 @@ namespace Avalonia.Win32.Interop.Wpf
_sync.Post(new Disposer(_impl).Callback, null); _sync.Post(new Disposer(_impl).Callback, null);
} }
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
if (_impl != null) if (_impl != null)
@ -97,9 +115,12 @@ namespace Avalonia.Win32.Interop.Wpf
void IAddChild.AddChild(object value) void IAddChild.AddChild(object value)
{ {
if (Content == null) 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 else
throw new InvalidOperationException(); throw new InvalidOperationException("WpfAvaloniaHost.Content was already set.");
} }
void IAddChild.AddText(string text) void IAddChild.AddText(string text)

2
src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs

@ -1,6 +1,6 @@
namespace Avalonia.Win32.Interop.Wpf 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 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 System.Windows.Point ToWpfPoint(this PixelPoint pt) => new System.Windows.Point(pt.X, pt.Y);

5
src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs

@ -5,7 +5,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop.Wpf
{ {
class WpfMouseDevice : MouseDevice internal class WpfMouseDevice : MouseDevice
{ {
private readonly WpfTopLevelImpl _impl; private readonly WpfTopLevelImpl _impl;
@ -14,7 +14,7 @@ namespace Avalonia.Win32.Interop.Wpf
_impl = impl; _impl = impl;
} }
class WpfMousePointer : Pointer private class WpfMousePointer : Pointer
{ {
private readonly WpfTopLevelImpl _impl; private readonly WpfTopLevelImpl _impl;
@ -35,6 +35,5 @@ namespace Avalonia.Win32.Interop.Wpf
System.Windows.Input.Mouse.Capture(_impl); System.Windows.Input.Mouse.Capture(_impl);
} }
} }
} }
} }

6
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -19,7 +19,7 @@ using MouseButton = System.Windows.Input.MouseButton;
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop.Wpf
{ {
class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl internal class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl
{ {
private HwndSource _currentHwndSource; private HwndSource _currentHwndSource;
private readonly HwndSourceHook _hook; private readonly HwndSourceHook _hook;
@ -137,7 +137,7 @@ namespace Avalonia.Win32.Interop.Wpf
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke();
static RawInputModifiers GetModifiers(MouseEventArgs e) private static RawInputModifiers GetModifiers(MouseEventArgs e)
{ {
var state = Keyboard.Modifiers; var state = Keyboard.Modifiers;
var rv = default(RawInputModifiers); var rv = default(RawInputModifiers);
@ -161,7 +161,7 @@ namespace Avalonia.Win32.Interop.Wpf
return rv; 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, => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type,
e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e))); e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e)));

2
src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs

@ -8,7 +8,7 @@ using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Win32.Interop.Wpf namespace Avalonia.Win32.Interop.Wpf
{ {
class WritableBitmapSurface : IFramebufferPlatformSurface internal class WritableBitmapSurface : IFramebufferPlatformSurface
{ {
private readonly WpfTopLevelImpl _impl; private readonly WpfTopLevelImpl _impl;
private WriteableBitmap _bitmap; private WriteableBitmap _bitmap;

Loading…
Cancel
Save