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
/// could not be retrieved.
/// </returns>
public IPlatformHandle? TryGetPlatformHandle() => ((IWindowBaseImpl?) PlatformImpl)?.Handle;
public IPlatformHandle? TryGetPlatformHandle() => (PlatformImpl as IWindowBaseImpl)?.Handle;
/// <summary>
/// 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">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseWpf>true</UseWpf>
<UseWindowsForms>true</UseWindowsForms>
<ExtrasEnableImplicitWinFormsReferences>true</ExtrasEnableImplicitWinFormsReferences>
<UseDirect3D9>true</UseDirect3D9>
<PackageId>Avalonia.Win32.Interoperability</PackageId>
</PropertyGroup>

37
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
{
/// <summary>
/// An element that allows you to host a Avalonia control on a Windows Forms page.
/// </summary>
[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;
/// <summary>
/// Initializes a new instance of the <see cref="WinFormsAvaloniaControlHost"/> class.
/// </summary>
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();
}
/// <summary>
/// Gets or sets the Avalonia control hosted by the <see cref="WinFormsAvaloniaControlHost"/> element.
/// </summary>
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;
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (disposing)
@ -46,27 +53,27 @@ namespace Avalonia.Win32.Embedding
UnmanagedMethods.SetFocus(WindowHandle);
}
/// <inheritdoc />
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);
}
/// <inheritdoc />
protected override void OnResize(EventArgs e)
{
FixPosition();
base.OnResize(e);
}
/// <inheritdoc />
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
{
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)
{

10
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<T>(ref T d) where T : IDisposable
private static void RemoveAndDispose<T>(ref T d) where T : IDisposable
{
d?.Dispose();
d = default;
}
void Swap()
private void Swap()
{
_backBuffer.Flush();
_image.Lock();

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

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

33
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
{
/// <summary>
/// An element that allows you to host a Avalonia control on a WPF page.
/// </summary>
[ContentProperty("Content")]
public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild
{
private WpfTopLevelImpl _impl;
private readonly SynchronizationContext _sync;
private bool _hasChildren;
/// <summary>
/// Initializes a new instance of the <see cref="WpfAvaloniaHost"/> class.
/// </summary>
public WpfAvaloniaHost()
{
_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;
}
//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
}
}
/// <inheritdoc />
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
{
_impl.InvalidateMeasure();
@ -67,13 +80,17 @@ namespace Avalonia.Win32.Interop.Wpf
return _impl.DesiredSize;
}
/// <inheritdoc />
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
_impl.Arrange(new System.Windows.Rect(arrangeSize));
return arrangeSize;
}
/// <inheritdoc />
protected override int VisualChildrenCount => 1;
/// <inheritdoc />
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);
}
/// <inheritdoc />
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)

2
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);

5
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);
}
}
}
}

6
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)));

2
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;

Loading…
Cancel
Save