committed by
GitHub
37 changed files with 1195 additions and 154 deletions
@ -0,0 +1,5 @@ |
|||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="System.ValueTuple" Version="4.3.1" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,5 @@ |
|||||
|
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\ |
||||
|
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.1\ |
||||
|
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.1\ |
||||
|
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\ |
||||
|
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.1\ |
||||
@ -0,0 +1,7 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/ |
||||
|
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/ |
||||
|
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/ |
||||
|
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/ |
||||
|
|
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Avalonia.Layout |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A special layout root with enforced size for Arrange pass
|
||||
|
/// </summary>
|
||||
|
public interface IEmbeddedLayoutRoot : ILayoutRoot |
||||
|
{ |
||||
|
Size AllocatedSize { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,123 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> |
||||
|
<PropertyGroup> |
||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
|
<ProjectGuid>{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}</ProjectGuid> |
||||
|
<OutputType>Library</OutputType> |
||||
|
<AppDesignerFolder>Properties</AppDesignerFolder> |
||||
|
<RootNamespace>Avalonia.Win32.Interop</RootNamespace> |
||||
|
<AssemblyName>Avalonia.Win32.Interop</AssemblyName> |
||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> |
||||
|
<FileAlignment>512</FileAlignment> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
|
<DebugSymbols>true</DebugSymbols> |
||||
|
<DebugType>full</DebugType> |
||||
|
<Optimize>false</Optimize> |
||||
|
<OutputPath>bin\Debug\</OutputPath> |
||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
|
<ErrorReport>prompt</ErrorReport> |
||||
|
<WarningLevel>4</WarningLevel> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
|
<DebugType>pdbonly</DebugType> |
||||
|
<Optimize>true</Optimize> |
||||
|
<OutputPath>bin\Release\</OutputPath> |
||||
|
<DefineConstants>TRACE</DefineConstants> |
||||
|
<ErrorReport>prompt</ErrorReport> |
||||
|
<WarningLevel>4</WarningLevel> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<Reference Include="PresentationCore" /> |
||||
|
<Reference Include="PresentationFramework" /> |
||||
|
<Reference Include="System" /> |
||||
|
<Reference Include="System.Core" /> |
||||
|
<Reference Include="System.Xaml" /> |
||||
|
<Reference Include="System.Xml.Linq" /> |
||||
|
<Reference Include="System.Data.DataSetExtensions" /> |
||||
|
<Reference Include="Microsoft.CSharp" /> |
||||
|
<Reference Include="System.Data" /> |
||||
|
<Reference Include="System.Net.Http" /> |
||||
|
<Reference Include="System.Xml" /> |
||||
|
<Reference Include="WindowsBase" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<Compile Include="..\Avalonia.Win32\Interop\UnmanagedMethods.cs"> |
||||
|
<Link>UnmanagedMethods.cs</Link> |
||||
|
</Compile> |
||||
|
<Compile Include="Properties\AssemblyInfo.cs" /> |
||||
|
<Compile Include="Wpf\CursorShim.cs" /> |
||||
|
<Compile Include="Wpf\Direct2DImageSurface.cs" /> |
||||
|
<Compile Include="Wpf\IntSize.cs" /> |
||||
|
<Compile Include="Wpf\WpfInteropExtensions.cs" /> |
||||
|
<Compile Include="Wpf\WpfAvaloniaHost.cs" /> |
||||
|
<Compile Include="Wpf\WpfMouseDevice.cs" /> |
||||
|
<Compile Include="Wpf\WpfTopLevelImpl.cs" /> |
||||
|
<Compile Include="Wpf\WritableBitmapSurface.cs" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj"> |
||||
|
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project> |
||||
|
<Name>Avalonia.Animation</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj"> |
||||
|
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project> |
||||
|
<Name>Avalonia.Base</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj"> |
||||
|
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project> |
||||
|
<Name>Avalonia.Controls</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj"> |
||||
|
<Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project> |
||||
|
<Name>Avalonia.DotNetFrameworkRuntime</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj"> |
||||
|
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project> |
||||
|
<Name>Avalonia.Input</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj"> |
||||
|
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project> |
||||
|
<Name>Avalonia.Interactivity</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj"> |
||||
|
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project> |
||||
|
<Name>Avalonia.Layout</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj"> |
||||
|
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project> |
||||
|
<Name>Avalonia.Styling</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj"> |
||||
|
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project> |
||||
|
<Name>Avalonia.Visuals</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj"> |
||||
|
<Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project> |
||||
|
<Name>Avalonia.Cairo</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj"> |
||||
|
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project> |
||||
|
<Name>Avalonia.Markup.Xaml</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Markup\Avalonia.Markup\Avalonia.Markup.csproj"> |
||||
|
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project> |
||||
|
<Name>Avalonia.Markup</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj"> |
||||
|
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project> |
||||
|
<Name>Avalonia.Direct2D1</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\Avalonia.Win32\Avalonia.Win32.csproj"> |
||||
|
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project> |
||||
|
<Name>Avalonia.Win32</Name> |
||||
|
</ProjectReference> |
||||
|
</ItemGroup> |
||||
|
<PropertyGroup> |
||||
|
<UseDirect3D9>true</UseDirect3D9> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="..\..\..\build\SharpDX.props" /> |
||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
||||
|
</Project> |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System.Reflection; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
// General Information about an assembly is controlled through the following
|
||||
|
// set of attributes. Change these attribute values to modify the information
|
||||
|
// associated with an assembly.
|
||||
|
[assembly: AssemblyTitle("Avalonia.Win32.Interop")] |
||||
|
[assembly: AssemblyDescription("")] |
||||
|
[assembly: AssemblyConfiguration("")] |
||||
|
[assembly: AssemblyCompany("")] |
||||
|
[assembly: AssemblyProduct("Avalonia.Win32.Interop")] |
||||
|
[assembly: AssemblyCopyright("Copyright © 2017")] |
||||
|
[assembly: AssemblyTrademark("")] |
||||
|
[assembly: AssemblyCulture("")] |
||||
|
|
||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
|
// to COM components. If you need to access a type in this assembly from
|
||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||
|
[assembly: ComVisible(false)] |
||||
|
|
||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
|
[assembly: Guid("cbc4ff2f-92d4-420b-be21-9fe0b930b04e")] |
||||
|
|
||||
|
// Version information for an assembly consists of the following four values:
|
||||
|
//
|
||||
|
// Major Version
|
||||
|
// Minor Version
|
||||
|
// Build Number
|
||||
|
// Revision
|
||||
|
//
|
||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
|
// by using the '*' as shown below:
|
||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
[assembly: AssemblyVersion("1.0.0.0")] |
||||
|
[assembly: AssemblyFileVersion("1.0.0.0")] |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Runtime.Serialization; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows.Input; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,208 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Interop; |
||||
|
using Avalonia.Direct2D1; |
||||
|
using SharpDX; |
||||
|
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 MapFlags = SharpDX.Direct3D11.MapFlags; |
||||
|
using PresentParameters = SharpDX.DXGI.PresentParameters; |
||||
|
using Query = SharpDX.Direct3D11.Query; |
||||
|
using QueryType = SharpDX.Direct3D11.QueryType; |
||||
|
using RenderTarget = SharpDX.Direct2D1.RenderTarget; |
||||
|
using Surface = SharpDX.DXGI.Surface; |
||||
|
using SwapEffect = SharpDX.DXGI.SwapEffect; |
||||
|
using Usage = SharpDX.Direct3D9.Usage; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable |
||||
|
{ |
||||
|
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<Surface>()) |
||||
|
|
||||
|
{ |
||||
|
_resource = texture.QueryInterface<SharpDX.Direct3D11.Resource>(); |
||||
|
|
||||
|
Target = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>(), 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<SharpDX.DXGI.Resource>()) |
||||
|
{ |
||||
|
_sharedResource = texture.QueryInterface<SharpDX.Direct3D11.Resource>(); |
||||
|
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(); |
||||
|
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.GetService<SharpDX.DXGI.Device>() |
||||
|
.QueryInterface<SharpDX.Direct3D11.Device>(); |
||||
|
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); |
||||
|
} |
||||
|
_impl.ImageSource = _image; |
||||
|
|
||||
|
RemoveAndDispose(ref _backBuffer); |
||||
|
if (size == default(IntSize)) |
||||
|
{ |
||||
|
_image.Lock(); |
||||
|
_image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero); |
||||
|
_image.Unlock(); |
||||
|
return null; |
||||
|
} |
||||
|
_backBuffer = new SwapBuffer(size, dpi); |
||||
|
|
||||
|
return _backBuffer.Target; |
||||
|
} |
||||
|
|
||||
|
void RemoveAndDispose<T>(ref T d) where T : IDisposable |
||||
|
{ |
||||
|
d?.Dispose(); |
||||
|
d = default(T); |
||||
|
} |
||||
|
|
||||
|
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(); |
||||
|
} |
||||
|
|
||||
|
public void DestroyRenderTarget() |
||||
|
{ |
||||
|
RemoveAndDispose(ref _backBuffer); |
||||
|
} |
||||
|
|
||||
|
public void BeforeDrawing() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void AfterDrawing() => Swap(); |
||||
|
public void Dispose() |
||||
|
{ |
||||
|
RemoveAndDispose(ref _backBuffer); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
struct IntSize : IEquatable<IntSize> |
||||
|
{ |
||||
|
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 && Equals((IntSize) obj); |
||||
|
} |
||||
|
|
||||
|
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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Markup; |
||||
|
using System.Windows.Media; |
||||
|
using Avalonia.Markup.Xaml.Styling; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Styling; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
[ContentProperty("Content")] |
||||
|
public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild |
||||
|
{ |
||||
|
private WpfTopLevelImpl _impl; |
||||
|
private readonly SynchronizationContext _sync; |
||||
|
private bool _hasChildren; |
||||
|
public WpfAvaloniaHost() |
||||
|
{ |
||||
|
_sync = SynchronizationContext.Current; |
||||
|
_impl = new WpfTopLevelImpl(); |
||||
|
_impl.ControlRoot.Prepare(); |
||||
|
_impl.Visibility = Visibility.Visible; |
||||
|
SnapsToDevicePixels = true; |
||||
|
UseLayoutRounding = true; |
||||
|
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged); |
||||
|
} |
||||
|
|
||||
|
private void OnSourceChanged(object sender, SourceChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.NewSource != null && !_hasChildren) |
||||
|
{ |
||||
|
AddLogicalChild(_impl); |
||||
|
AddVisualChild(_impl); |
||||
|
_hasChildren = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
RemoveVisualChild(_impl); |
||||
|
RemoveLogicalChild(_impl); |
||||
|
_hasChildren = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public object Content |
||||
|
{ |
||||
|
get => _impl.ControlRoot.Content; |
||||
|
set => _impl.ControlRoot.Content = value; |
||||
|
} |
||||
|
|
||||
|
//Separate class is needed to prevent accidential resurrection
|
||||
|
class Disposer |
||||
|
{ |
||||
|
private readonly WpfTopLevelImpl _impl; |
||||
|
|
||||
|
public Disposer(WpfTopLevelImpl impl) |
||||
|
{ |
||||
|
_impl = impl; |
||||
|
} |
||||
|
|
||||
|
public void Callback(object state) |
||||
|
{ |
||||
|
_impl.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) |
||||
|
{ |
||||
|
_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)); |
||||
|
return arrangeSize; |
||||
|
} |
||||
|
|
||||
|
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) |
||||
|
Content = value; |
||||
|
else |
||||
|
throw new InvalidOperationException(); |
||||
|
} |
||||
|
|
||||
|
void IAddChild.AddText(string text) |
||||
|
{ |
||||
|
//
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
static class WpfInteropExtensions |
||||
|
{ |
||||
|
public static System.Windows.Point ToWpfPoint(this Point 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 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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls.Embedding; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.VisualTree; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
class WpfMouseDevice : MouseDevice |
||||
|
{ |
||||
|
private readonly WpfTopLevelImpl _impl; |
||||
|
|
||||
|
public WpfMouseDevice(WpfTopLevelImpl impl) |
||||
|
{ |
||||
|
_impl = impl; |
||||
|
} |
||||
|
|
||||
|
public override void Capture(IInputElement control) |
||||
|
{ |
||||
|
if (control == null) |
||||
|
{ |
||||
|
System.Windows.Input.Mouse.Capture(null); |
||||
|
} |
||||
|
else if ((control.GetVisualRoot() as EmbeddableControlRoot)?.PlatformImpl != _impl) |
||||
|
throw new ArgumentException("Visual belongs to unknown toplevel"); |
||||
|
else |
||||
|
System.Windows.Input.Mouse.Capture(_impl); |
||||
|
base.Capture(control); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,241 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Input; |
||||
|
using System.Windows.Interop; |
||||
|
using System.Windows.Media; |
||||
|
using Avalonia.Controls.Embedding; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Input.Raw; |
||||
|
using Avalonia.Layout; |
||||
|
using Avalonia.Platform; |
||||
|
using Key = Avalonia.Input.Key; |
||||
|
using KeyEventArgs = System.Windows.Input.KeyEventArgs; |
||||
|
using MouseButton = System.Windows.Input.MouseButton; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Wpf |
||||
|
{ |
||||
|
class WpfTopLevelImpl : FrameworkElement, IEmbeddableWindowImpl |
||||
|
{ |
||||
|
private HwndSource _currentHwndSource; |
||||
|
private readonly HwndSourceHook _hook; |
||||
|
private readonly IEmbeddableWindowImpl _ttl; |
||||
|
private IInputRoot _inputRoot; |
||||
|
private readonly IEnumerable<object> _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(); |
||||
|
} |
||||
|
|
||||
|
protected override void HandleResized(Size clientSize) |
||||
|
{ |
||||
|
ClientSize = clientSize; |
||||
|
LayoutManager.Instance.ExecuteLayoutPass(); |
||||
|
Renderer?.Resized(clientSize); |
||||
|
} |
||||
|
|
||||
|
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.GetService<IKeyboardDevice>(); |
||||
|
|
||||
|
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.Scaling); |
||||
|
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.Scaling); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
_ttl.Closed?.Invoke(); |
||||
|
foreach(var d in _surfaces.OfType<IDisposable>()) |
||||
|
d.Dispose(); |
||||
|
} |
||||
|
|
||||
|
Size ITopLevelImpl.ClientSize => _finalSize; |
||||
|
IMouseDevice ITopLevelImpl.MouseDevice => _mouse; |
||||
|
|
||||
|
double ITopLevelImpl.Scaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1; |
||||
|
|
||||
|
IEnumerable<object> 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()); |
||||
|
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.Invalidate(Rect rect) => InvalidateVisual(); |
||||
|
|
||||
|
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot; |
||||
|
|
||||
|
Point ITopLevelImpl.PointToClient(Point point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint(); |
||||
|
|
||||
|
Point ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPoint(); |
||||
|
|
||||
|
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); |
||||
|
|
||||
|
|
||||
|
InputModifiers GetModifiers() |
||||
|
{ |
||||
|
var state = Keyboard.Modifiers; |
||||
|
var rv = default(InputModifiers); |
||||
|
if (state.HasFlag(ModifierKeys.Windows)) |
||||
|
rv |= InputModifiers.Windows; |
||||
|
if (state.HasFlag(ModifierKeys.Alt)) |
||||
|
rv |= InputModifiers.Alt; |
||||
|
if (state.HasFlag(ModifierKeys.Control)) |
||||
|
rv |= InputModifiers.Control; |
||||
|
if (state.HasFlag(ModifierKeys.Shift)) |
||||
|
rv |= InputModifiers.Shift; |
||||
|
//TODO: mouse modifiers
|
||||
|
|
||||
|
|
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
void MouseEvent(RawMouseEventType type, MouseEventArgs e) |
||||
|
=> _ttl.Input?.Invoke(new RawMouseEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type, |
||||
|
e.GetPosition(this).ToAvaloniaPoint(), GetModifiers())); |
||||
|
|
||||
|
protected override void OnMouseDown(MouseButtonEventArgs e) |
||||
|
{ |
||||
|
RawMouseEventType type; |
||||
|
if(e.ChangedButton == MouseButton.Left) |
||||
|
type = RawMouseEventType.LeftButtonDown; |
||||
|
else if (e.ChangedButton == MouseButton.Middle) |
||||
|
type = RawMouseEventType.MiddleButtonDown; |
||||
|
else if (e.ChangedButton == MouseButton.Right) |
||||
|
type = RawMouseEventType.RightButtonDown; |
||||
|
else |
||||
|
return; |
||||
|
MouseEvent(type, e); |
||||
|
Focus(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnMouseUp(MouseButtonEventArgs e) |
||||
|
{ |
||||
|
RawMouseEventType type; |
||||
|
if (e.ChangedButton == MouseButton.Left) |
||||
|
type = RawMouseEventType.LeftButtonUp; |
||||
|
else if (e.ChangedButton == MouseButton.Middle) |
||||
|
type = RawMouseEventType.MiddleButtonUp; |
||||
|
else if (e.ChangedButton == MouseButton.Right) |
||||
|
type = RawMouseEventType.RightButtonUp; |
||||
|
else |
||||
|
return; |
||||
|
MouseEvent(type, e); |
||||
|
Focus(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnMouseMove(MouseEventArgs e) |
||||
|
{ |
||||
|
MouseEvent(RawMouseEventType.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())); |
||||
|
|
||||
|
protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawMouseEventType.LeaveWindow, e); |
||||
|
|
||||
|
protected override void OnKeyDown(KeyEventArgs e) |
||||
|
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, RawKeyEventType.KeyDown, |
||||
|
(Key) e.Key, |
||||
|
GetModifiers())); |
||||
|
|
||||
|
protected override void OnKeyUp(KeyEventArgs e) |
||||
|
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, RawKeyEventType.KeyUp, |
||||
|
(Key)e.Key, |
||||
|
GetModifiers())); |
||||
|
|
||||
|
protected override void OnTextInput(TextCompositionEventArgs e) |
||||
|
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, e.Text)); |
||||
|
|
||||
|
void ITopLevelImpl.SetCursor(IPlatformHandle cursor) |
||||
|
{ |
||||
|
if (cursor == null) |
||||
|
Cursor = Cursors.Arrow; |
||||
|
else if (cursor.HandleDescriptor == "HCURSOR") |
||||
|
Cursor = CursorShim.FromHCursor(cursor.Handle); |
||||
|
} |
||||
|
|
||||
|
Action<RawInputEventArgs> ITopLevelImpl.Input { get; set; } //TODO
|
||||
|
Action<Rect> ITopLevelImpl.Paint { get; set; } |
||||
|
Action<Size> ITopLevelImpl.Resized { get; set; } |
||||
|
Action<double> ITopLevelImpl.ScalingChanged { get; set; } |
||||
|
Action ITopLevelImpl.Closed { get; set; } |
||||
|
public new event Action LostFocus; |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
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.Interop.Wpf |
||||
|
{ |
||||
|
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, |
||||
|
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 int Width => _bitmap.PixelWidth; |
||||
|
public int Height => _bitmap.PixelHeight; |
||||
|
public int RowBytes => _bitmap.BackBufferStride; |
||||
|
public Vector Dpi { get; } |
||||
|
public PixelFormat Format => PixelFormat.Bgra8888; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,52 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Runtime.InteropServices; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using System.Windows; |
|
||||
using System.Windows.Controls; |
|
||||
using System.Windows.Forms.Integration; |
|
||||
using System.Windows.Interop; |
|
||||
using Avalonia.Controls; |
|
||||
using Avalonia.Win32.Interop; |
|
||||
|
|
||||
namespace Avalonia.Win32.Embedding |
|
||||
{ |
|
||||
public class WpfAvaloniaControlHost : HwndHost |
|
||||
{ |
|
||||
private WinFormsAvaloniaControlHost _host; |
|
||||
private Avalonia.Controls.Control _content; |
|
||||
|
|
||||
public Avalonia.Controls.Control Content |
|
||||
{ |
|
||||
get { return _content; } |
|
||||
set |
|
||||
{ |
|
||||
if (_host != null) |
|
||||
_host.Content = value; |
|
||||
_content = value; |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void DestroyHost() |
|
||||
{ |
|
||||
_host?.Dispose(); |
|
||||
_host = null; |
|
||||
} |
|
||||
|
|
||||
protected override HandleRef BuildWindowCore(HandleRef hwndParent) |
|
||||
{ |
|
||||
DestroyHost(); |
|
||||
_host = new WinFormsAvaloniaControlHost {Content = _content}; |
|
||||
UnmanagedMethods.SetParent(_host.Handle, hwndParent.Handle); |
|
||||
return new HandleRef(this, _host.Handle); |
|
||||
} |
|
||||
|
|
||||
protected override void DestroyWindowCore(HandleRef hwnd) |
|
||||
{ |
|
||||
DestroyHost(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue