28 changed files with 657 additions and 402 deletions
@ -0,0 +1,15 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\NativeEmbedSample\NativeEmbedSample.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<Import Project="..\..\..\build\SampleApp.props" /> |
|||
<Import Project="..\..\..\build\BuildTargets.targets" /> |
|||
<Import Project="..\..\..\build\ReferenceCoreLibraries.props" /> |
|||
</Project> |
|||
@ -0,0 +1,17 @@ |
|||
using Avalonia; |
|||
using NativeEmbedSample; |
|||
|
|||
namespace NativeEmbedSample.Desktop; |
|||
|
|||
public class Program |
|||
{ |
|||
static int Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); |
|||
|
|||
public static AppBuilder BuildAvaloniaApp() |
|||
=> AppBuilder.Configure<App>() |
|||
.With(new AvaloniaNativePlatformOptions() |
|||
{ |
|||
}) |
|||
.UsePlatformDetect(); |
|||
|
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
#if __ANDROID__ || ANDROID
|
|||
using System; |
|||
using System.IO; |
|||
using System.Diagnostics; |
|||
using Android.Views; |
|||
using Android.Webkit; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public partial class EmbedSample |
|||
{ |
|||
private IPlatformHandle CreateAndroid(IPlatformHandle parent) |
|||
{ |
|||
var button = new Android.Widget.Button(Android.App.Application.Context) { Text = "Android button" }; |
|||
|
|||
return new AndroidViewHandle(button); |
|||
} |
|||
|
|||
private void DestroyAndroid(IPlatformHandle control) |
|||
{ |
|||
base.DestroyNativeControlCore(control); |
|||
} |
|||
} |
|||
|
|||
internal sealed class AndroidViewHandle : INativeControlHostDestroyableControlHandle |
|||
{ |
|||
private View _view; |
|||
|
|||
public AndroidViewHandle(View view) |
|||
{ |
|||
_view = view; |
|||
} |
|||
|
|||
public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; |
|||
public string HandleDescriptor => "JavaHandle"; |
|||
|
|||
public void Destroy() |
|||
{ |
|||
_view?.Dispose(); |
|||
_view = null; |
|||
} |
|||
|
|||
~AndroidViewHandle() |
|||
{ |
|||
Destroy(); |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,23 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls.ApplicationLifetimes; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public class App : Application |
|||
{ |
|||
public override void Initialize() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public override void OnFrameworkInitializationCompleted() |
|||
{ |
|||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) |
|||
desktopLifetime.MainWindow = new MainWindow(); |
|||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) |
|||
singleViewLifetime.MainView = new MainView(); |
|||
|
|||
base.OnFrameworkInitializationCompleted(); |
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls.ApplicationLifetimes; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace NativeEmbedSample |
|||
{ |
|||
public class App : Application |
|||
{ |
|||
public override void Initialize() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public override void OnFrameworkInitializationCompleted() |
|||
{ |
|||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) |
|||
desktopLifetime.MainWindow = new MainWindow(); |
|||
|
|||
base.OnFrameworkInitializationCompleted(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
#if DESKTOP
|
|||
using System.IO; |
|||
using System.Diagnostics; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public partial class EmbedSample |
|||
{ |
|||
private Process _mplayer; |
|||
|
|||
IPlatformHandle CreateLinux(IPlatformHandle parent) |
|||
{ |
|||
if (IsSecond) |
|||
{ |
|||
var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); |
|||
if (chooser != null) |
|||
return chooser; |
|||
} |
|||
|
|||
var control = base.CreateNativeControlCore(parent); |
|||
var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, |
|||
"..", |
|||
"nodes.mp4")); |
|||
_mplayer = Process.Start(new ProcessStartInfo("mplayer", |
|||
$"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") |
|||
{ |
|||
UseShellExecute = false, |
|||
|
|||
}); |
|||
return control; |
|||
} |
|||
|
|||
void DestroyLinux(IPlatformHandle handle) |
|||
{ |
|||
_mplayer?.Kill(); |
|||
_mplayer = null; |
|||
base.DestroyNativeControlCore(handle); |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,62 @@ |
|||
#if DESKTOP
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Platform.Interop; |
|||
using Avalonia.X11.NativeDialogs; |
|||
using static Avalonia.X11.NativeDialogs.Gtk; |
|||
using static Avalonia.X11.NativeDialogs.Glib; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
internal class GtkHelper |
|||
{ |
|||
private static Task<bool> s_gtkTask; |
|||
|
|||
class FileChooser : INativeControlHostDestroyableControlHandle |
|||
{ |
|||
private readonly IntPtr _widget; |
|||
|
|||
public FileChooser(IntPtr widget, IntPtr xid) |
|||
{ |
|||
_widget = widget; |
|||
Handle = xid; |
|||
} |
|||
|
|||
public IntPtr Handle { get; } |
|||
public string HandleDescriptor => "XID"; |
|||
|
|||
public void Destroy() |
|||
{ |
|||
RunOnGlibThread(() => |
|||
{ |
|||
gtk_widget_destroy(_widget); |
|||
return 0; |
|||
}).Wait(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public static IPlatformHandle CreateGtkFileChooser(IntPtr parentXid) |
|||
{ |
|||
if (s_gtkTask == null) |
|||
s_gtkTask = StartGtk(); |
|||
if (!s_gtkTask.Result) |
|||
return null; |
|||
return RunOnGlibThread(() => |
|||
{ |
|||
using (var title = new Utf8Buffer("Embedded")) |
|||
{ |
|||
var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, |
|||
IntPtr.Zero); |
|||
gtk_widget_realize(widget); |
|||
var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); |
|||
gtk_window_present(widget); |
|||
return new FileChooser(widget, xid); |
|||
} |
|||
}).Result; |
|||
} |
|||
} |
|||
#endif
|
|||
@ -1,58 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Platform.Interop; |
|||
using Avalonia.X11.NativeDialogs; |
|||
using static Avalonia.X11.NativeDialogs.Gtk; |
|||
using static Avalonia.X11.NativeDialogs.Glib; |
|||
namespace NativeEmbedSample |
|||
{ |
|||
public class GtkHelper |
|||
{ |
|||
private static Task<bool> s_gtkTask; |
|||
class FileChooser : INativeControlHostDestroyableControlHandle |
|||
{ |
|||
private readonly IntPtr _widget; |
|||
|
|||
public FileChooser(IntPtr widget, IntPtr xid) |
|||
{ |
|||
_widget = widget; |
|||
Handle = xid; |
|||
} |
|||
|
|||
public IntPtr Handle { get; } |
|||
public string HandleDescriptor => "XID"; |
|||
public void Destroy() |
|||
{ |
|||
RunOnGlibThread(() => |
|||
{ |
|||
gtk_widget_destroy(_widget); |
|||
return 0; |
|||
}).Wait(); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public static IPlatformHandle CreateGtkFileChooser(IntPtr parentXid) |
|||
{ |
|||
if (s_gtkTask == null) |
|||
s_gtkTask = StartGtk(); |
|||
if (!s_gtkTask.Result) |
|||
return null; |
|||
return RunOnGlibThread(() => |
|||
{ |
|||
using (var title = new Utf8Buffer("Embedded")) |
|||
{ |
|||
var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, |
|||
IntPtr.Zero); |
|||
gtk_widget_realize(widget); |
|||
var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); |
|||
gtk_window_present(widget); |
|||
return new FileChooser(widget, xid); |
|||
} |
|||
}).Result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
#if DESKTOP
|
|||
using Avalonia.Platform; |
|||
using Avalonia.Threading; |
|||
using MonoMac.Foundation; |
|||
using MonoMac.WebKit; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public partial class EmbedSample |
|||
{ |
|||
IPlatformHandle CreateOSX(IPlatformHandle parent) |
|||
{ |
|||
// Note: We are using MonoMac for example purposes
|
|||
// It shouldn't be used in production apps
|
|||
MacHelper.EnsureInitialized(); |
|||
|
|||
var webView = new WebView(); |
|||
Dispatcher.UIThread.Post(() => |
|||
{ |
|||
webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( |
|||
IsSecond ? "https://bing.com": "https://google.com/"))); |
|||
}); |
|||
return new MacOSViewHandle(webView); |
|||
|
|||
} |
|||
|
|||
void DestroyOSX(IPlatformHandle handle) |
|||
{ |
|||
((MacOSViewHandle)handle).Dispose(); |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,39 @@ |
|||
#if DESKTOP
|
|||
using System; |
|||
using Avalonia.Platform; |
|||
using MonoMac.AppKit; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
internal class MacHelper |
|||
{ |
|||
private static bool _isInitialized; |
|||
|
|||
public static void EnsureInitialized() |
|||
{ |
|||
if (_isInitialized) |
|||
return; |
|||
_isInitialized = true; |
|||
NSApplication.Init(); |
|||
} |
|||
} |
|||
|
|||
internal class MacOSViewHandle : IPlatformHandle, IDisposable |
|||
{ |
|||
private NSView _view; |
|||
|
|||
public MacOSViewHandle(NSView view) |
|||
{ |
|||
_view = view; |
|||
} |
|||
|
|||
public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; |
|||
public string HandleDescriptor => "NSView"; |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_view.Dispose(); |
|||
_view = null; |
|||
} |
|||
} |
|||
#endif
|
|||
@ -1,39 +0,0 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
using MonoMac.AppKit; |
|||
|
|||
namespace NativeEmbedSample |
|||
{ |
|||
public class MacHelper |
|||
{ |
|||
private static bool _isInitialized; |
|||
|
|||
public static void EnsureInitialized() |
|||
{ |
|||
if (_isInitialized) |
|||
return; |
|||
_isInitialized = true; |
|||
NSApplication.Init(); |
|||
} |
|||
} |
|||
|
|||
class MacOSViewHandle : IPlatformHandle, IDisposable |
|||
{ |
|||
private NSView _view; |
|||
|
|||
public MacOSViewHandle(NSView view) |
|||
{ |
|||
_view = view; |
|||
} |
|||
|
|||
public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; |
|||
public string HandleDescriptor => "NSView"; |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_view.Dispose(); |
|||
_view = null; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:local="clr-namespace:NativeEmbedSample" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="NativeEmbedSample.MainView"> |
|||
<DockPanel> |
|||
<Menu DockPanel.Dock="Top"> |
|||
<MenuItem Header="Test"> |
|||
<MenuItem Header="SubMenu"> |
|||
<MenuItem Header="Item 1"/> |
|||
<MenuItem Header="Item 2"/> |
|||
<MenuItem Header="Item 3"/> |
|||
</MenuItem> |
|||
<MenuItem Header="Item 1"/> |
|||
<MenuItem Header="Item 2"/> |
|||
<MenuItem Header="Item 3"/> |
|||
</MenuItem> |
|||
</Menu> |
|||
<DockPanel DockPanel.Dock="Top"> |
|||
<Button DockPanel.Dock="Right" Click="ShowPopupDelay">Show popup (delay)</Button> |
|||
<Button DockPanel.Dock="Right" Click="ShowPopup">Show popup</Button> |
|||
<Border DockPanel.Dock="Right" Background="#c0c0c0"> |
|||
<ToolTip.Tip> |
|||
<ToolTip> |
|||
<TextBlock>Text</TextBlock> |
|||
</ToolTip> |
|||
</ToolTip.Tip> |
|||
<TextBlock VerticalAlignment="Center">Tooltip</TextBlock> |
|||
</Border> |
|||
<TextBox Text="Lorem ipsum dolor sit amet"/> |
|||
|
|||
</DockPanel> |
|||
<Grid ColumnDefinitions="*,5,*" |
|||
RowDefinitions="*,5,*"> |
|||
<Grid.Styles> |
|||
<Style Selector="DockPanel#FirstPanel:not(.mobile), DockPanel#SecondPanel:not(.mobile)"> |
|||
<Setter Property="Grid.RowSpan" Value="3" /> |
|||
</Style> |
|||
<Style Selector="DockPanel#SecondPanel:not(.mobile)"> |
|||
<Setter Property="Grid.Column" Value="2" /> |
|||
</Style> |
|||
|
|||
<Style Selector="DockPanel#FirstPanel.mobile, DockPanel#SecondPanel.mobile"> |
|||
<Setter Property="Grid.ColumnSpan" Value="3" /> |
|||
</Style> |
|||
<Style Selector="DockPanel#SecondPanel.mobile"> |
|||
<Setter Property="Grid.Row" Value="2" /> |
|||
</Style> |
|||
</Grid.Styles> |
|||
|
|||
<DockPanel x:Name="FirstPanel"> |
|||
<CheckBox x:Name="firstVisible" DockPanel.Dock="Top" |
|||
IsChecked="True" Content="Visible" /> |
|||
<local:EmbedSample IsVisible="{Binding #firstVisible.IsChecked}"/> |
|||
</DockPanel> |
|||
<GridSplitter Grid.Row="0" Grid.RowSpan="3" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" /> |
|||
<GridSplitter Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Height="5" VerticalAlignment="Stretch" /> |
|||
<DockPanel x:Name="SecondPanel"> |
|||
<CheckBox x:Name="secondVisible" DockPanel.Dock="Top" |
|||
IsChecked="True" Content="Visible" /> |
|||
<local:EmbedSample IsSecond="True" IsVisible="{Binding #secondVisible.IsChecked}"/> |
|||
</DockPanel> |
|||
</Grid> |
|||
</DockPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,45 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public class MainView : UserControl |
|||
{ |
|||
public MainView() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public async void ShowPopupDelay(object sender, RoutedEventArgs args) |
|||
{ |
|||
await Task.Delay(3000); |
|||
ShowPopup(sender, args); |
|||
} |
|||
|
|||
public void ShowPopup(object sender, RoutedEventArgs args) |
|||
{ |
|||
new ContextMenu() |
|||
{ |
|||
Items = new List<MenuItem> |
|||
{ |
|||
new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } |
|||
} |
|||
}.Open((Control)sender); |
|||
} |
|||
|
|||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) |
|||
{ |
|||
base.OnPropertyChanged(change); |
|||
|
|||
if (change.Property == BoundsProperty) |
|||
{ |
|||
var isMobile = change.GetNewValue<Rect>().Width < 1200; |
|||
this.Find<DockPanel>("FirstPanel")!.Classes.Set("mobile", isMobile); |
|||
this.Find<DockPanel>("SecondPanel")!.Classes.Set("mobile", isMobile); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
<Window xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:nativeEmbedSample="clr-namespace:NativeEmbedSample" |
|||
x:Class="NativeEmbedSample.MainWindow" |
|||
MinWidth="500" MinHeight="300" |
|||
Width="1024" Height="800" |
|||
Title="Native embedding sample"> |
|||
<nativeEmbedSample:MainView /> |
|||
</Window> |
|||
|
|||
@ -0,0 +1,17 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public class MainWindow : Window |
|||
{ |
|||
public MainWindow() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
#if DEBUG && DESKTOP
|
|||
this.AttachDevTools(); |
|||
#endif
|
|||
} |
|||
} |
|||
|
|||
@ -1,52 +0,0 @@ |
|||
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300" |
|||
Width="1024" Height="800" |
|||
Title="Native embedding sample" |
|||
xmlns:local="clr-namespace:NativeEmbedSample" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="NativeEmbedSample.MainWindow"> |
|||
<DockPanel> |
|||
<Menu DockPanel.Dock="Top"> |
|||
<MenuItem Header="Test"> |
|||
<MenuItem Header="SubMenu"> |
|||
<MenuItem Header="Item 1"/> |
|||
<MenuItem Header="Item 2"/> |
|||
<MenuItem Header="Item 3"/> |
|||
</MenuItem> |
|||
<MenuItem Header="Item 1"/> |
|||
<MenuItem Header="Item 2"/> |
|||
<MenuItem Header="Item 3"/> |
|||
</MenuItem> |
|||
</Menu> |
|||
<DockPanel DockPanel.Dock="Top"> |
|||
<Button DockPanel.Dock="Right" Click="ShowPopupDelay">Show popup (delay)</Button> |
|||
<Button DockPanel.Dock="Right" Click="ShowPopup">Show popup</Button> |
|||
<Border DockPanel.Dock="Right" Background="#c0c0c0"> |
|||
<ToolTip.Tip> |
|||
<ToolTip> |
|||
<TextBlock>Text</TextBlock> |
|||
</ToolTip> |
|||
</ToolTip.Tip> |
|||
<TextBlock>Tooltip</TextBlock> |
|||
</Border> |
|||
<TextBox Text="Lorem ipsum dolor sit amet"/> |
|||
|
|||
</DockPanel> |
|||
<Grid ColumnDefinitions="*,5,*"> |
|||
<DockPanel> |
|||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top"> |
|||
<CheckBox x:Name="firstVisible" IsChecked="True"/> |
|||
<TextBlock>Visible</TextBlock> |
|||
</StackPanel> |
|||
<local:EmbedSample IsVisible="{Binding #firstVisible.IsChecked}"/> |
|||
</DockPanel> |
|||
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" /> |
|||
<DockPanel Grid.Column="2"> |
|||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top"> |
|||
<CheckBox x:Name="secondVisible" IsChecked="True"/> |
|||
<TextBlock>Visible</TextBlock> |
|||
</StackPanel> |
|||
<local:EmbedSample IsSecond="True" IsVisible="{Binding #secondVisible.IsChecked}"/> |
|||
</DockPanel> |
|||
</Grid> |
|||
</DockPanel> |
|||
</Window> |
|||
@ -1,36 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace NativeEmbedSample |
|||
{ |
|||
public class MainWindow : Window |
|||
{ |
|||
public MainWindow() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
this.AttachDevTools(); |
|||
} |
|||
|
|||
public async void ShowPopupDelay(object sender, RoutedEventArgs args) |
|||
{ |
|||
await Task.Delay(3000); |
|||
ShowPopup(sender, args); |
|||
} |
|||
|
|||
public void ShowPopup(object sender, RoutedEventArgs args) |
|||
{ |
|||
|
|||
new ContextMenu() |
|||
{ |
|||
Items = new List<MenuItem> |
|||
{ |
|||
new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } |
|||
} |
|||
}.Open((Control)sender); |
|||
} |
|||
} |
|||
} |
|||
@ -1,30 +1,32 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch> |
|||
<TargetFrameworks>net6.0;net6.0-android;net6.0-ios</TargetFrameworks> |
|||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> |
|||
|
|||
<DefineConstants Condition="'$(TargetFramework)' == 'net6.0'">$(DefineConstants);DESKTOP</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'"> |
|||
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" /> |
|||
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" /> |
|||
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> |
|||
<ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" /> |
|||
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" /> |
|||
|
|||
<AvaloniaResource Include="**\*.xaml"> |
|||
<SubType>Designer</SubType> |
|||
</AvaloniaResource> |
|||
<None Remove="nodes.mp4" /> |
|||
<Content Include="nodes.mp4"> |
|||
|
|||
<Compile Include="..\..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs"> |
|||
<Link>Gtk\Gtk.cs</Link> |
|||
</Compile> |
|||
|
|||
<Content Include="Gtk\nodes.mp4"> |
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
|||
</Content> |
|||
<Compile Include="..\..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" /> |
|||
</ItemGroup> |
|||
|
|||
<Import Project="..\..\..\build\SampleApp.props" /> |
|||
<Import Project="..\..\..\build\BuildTargets.targets" /> |
|||
<Import Project="..\..\..\build\ReferenceCoreLibraries.props" /> |
|||
</Project> |
|||
|
|||
@ -1,17 +0,0 @@ |
|||
using Avalonia; |
|||
|
|||
namespace NativeEmbedSample |
|||
{ |
|||
class Program |
|||
{ |
|||
static int Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); |
|||
|
|||
public static AppBuilder BuildAvaloniaApp() |
|||
=> AppBuilder.Configure<App>() |
|||
.With(new AvaloniaNativePlatformOptions() |
|||
{ |
|||
}) |
|||
.UsePlatformDetect(); |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
#if DESKTOP
|
|||
using System; |
|||
using System.Text; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public partial class EmbedSample |
|||
{ |
|||
private const string RichText = |
|||
@"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
|
|||
{\colortbl ;\red255\green0\blue0;\red0\green77\blue187;\red0\green176\blue80;\red155\green0\blue211;\red247\green150\blue70;\red75\green172\blue198;} |
|||
{\*\generator Riched20 6.3.9600}\viewkind4\uc1 |
|||
\pard\sa200\sl276\slmult1\f0\fs22\lang9 <PREFIX>I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par |
|||
}";
|
|||
|
|||
IPlatformHandle CreateWin32(IPlatformHandle parent) |
|||
{ |
|||
WinApi.LoadLibrary("Msftedit.dll"); |
|||
var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", |
|||
@"Rich Edit", |
|||
0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, |
|||
IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); |
|||
var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; |
|||
var text = RichText.Replace("<PREFIX>", IsSecond ? "\\qr " : ""); |
|||
var bytes = Encoding.UTF8.GetBytes(text); |
|||
WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); |
|||
return new PlatformHandle(handle, "HWND"); |
|||
|
|||
} |
|||
|
|||
void DestroyWin32(IPlatformHandle handle) |
|||
{ |
|||
WinApi.DestroyWindow(handle.Handle); |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,75 @@ |
|||
#if DESKTOP
|
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
internal unsafe class WinApi |
|||
{ |
|||
public enum CommonControls : uint |
|||
{ |
|||
ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header
|
|||
ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips
|
|||
ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips
|
|||
ICC_TAB_CLASSES = 0x00000008, // tab, tooltips
|
|||
ICC_UPDOWN_CLASS = 0x00000010, // updown
|
|||
ICC_PROGRESS_CLASS = 0x00000020, // progress
|
|||
ICC_HOTKEY_CLASS = 0x00000040, // hotkey
|
|||
ICC_ANIMATE_CLASS = 0x00000080, // animate
|
|||
ICC_WIN95_CLASSES = 0x000000FF, |
|||
ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown
|
|||
ICC_USEREX_CLASSES = 0x00000200, // comboex
|
|||
ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control
|
|||
ICC_INTERNET_CLASSES = 0x00000800, |
|||
ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller
|
|||
ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control
|
|||
ICC_STANDARD_CLASSES = 0x00004000, |
|||
ICC_LINK_CLASS = 0x00008000 |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct INITCOMMONCONTROLSEX |
|||
{ |
|||
public int dwSize; |
|||
public uint dwICC; |
|||
} |
|||
|
|||
[DllImport("Comctl32.dll")] |
|||
public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); |
|||
|
|||
[DllImport("user32.dll", SetLastError = true)] |
|||
public static extern bool DestroyWindow(IntPtr hwnd); |
|||
|
|||
[DllImport("kernel32.dll")] |
|||
public static extern IntPtr LoadLibrary(string lib); |
|||
|
|||
|
|||
[DllImport("kernel32.dll")] |
|||
public static extern IntPtr GetModuleHandle(string lpModuleName); |
|||
|
|||
[DllImport("user32.dll", SetLastError = true)] |
|||
public static extern IntPtr CreateWindowEx( |
|||
int dwExStyle, |
|||
string lpClassName, |
|||
string lpWindowName, |
|||
uint dwStyle, |
|||
int x, |
|||
int y, |
|||
int nWidth, |
|||
int nHeight, |
|||
IntPtr hWndParent, |
|||
IntPtr hMenu, |
|||
IntPtr hInstance, |
|||
IntPtr lpParam); |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct SETTEXTEX |
|||
{ |
|||
public uint Flags; |
|||
public uint Codepage; |
|||
} |
|||
|
|||
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] |
|||
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); |
|||
} |
|||
#endif
|
|||
@ -1,74 +0,0 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NativeEmbedSample |
|||
{ |
|||
public unsafe class WinApi |
|||
{ |
|||
public enum CommonControls : uint |
|||
{ |
|||
ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header
|
|||
ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips
|
|||
ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips
|
|||
ICC_TAB_CLASSES = 0x00000008, // tab, tooltips
|
|||
ICC_UPDOWN_CLASS = 0x00000010, // updown
|
|||
ICC_PROGRESS_CLASS = 0x00000020, // progress
|
|||
ICC_HOTKEY_CLASS = 0x00000040, // hotkey
|
|||
ICC_ANIMATE_CLASS = 0x00000080, // animate
|
|||
ICC_WIN95_CLASSES = 0x000000FF, |
|||
ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown
|
|||
ICC_USEREX_CLASSES = 0x00000200, // comboex
|
|||
ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control
|
|||
ICC_INTERNET_CLASSES = 0x00000800, |
|||
ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller
|
|||
ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control
|
|||
ICC_STANDARD_CLASSES = 0x00004000, |
|||
ICC_LINK_CLASS = 0x00008000 |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct INITCOMMONCONTROLSEX |
|||
{ |
|||
public int dwSize; |
|||
public uint dwICC; |
|||
} |
|||
|
|||
[DllImport("Comctl32.dll")] |
|||
public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); |
|||
|
|||
[DllImport("user32.dll", SetLastError = true)] |
|||
public static extern bool DestroyWindow(IntPtr hwnd); |
|||
|
|||
[DllImport("kernel32.dll")] |
|||
public static extern IntPtr LoadLibrary(string lib); |
|||
|
|||
|
|||
[DllImport("kernel32.dll")] |
|||
public static extern IntPtr GetModuleHandle(string lpModuleName); |
|||
|
|||
[DllImport("user32.dll", SetLastError = true)] |
|||
public static extern IntPtr CreateWindowEx( |
|||
int dwExStyle, |
|||
string lpClassName, |
|||
string lpWindowName, |
|||
uint dwStyle, |
|||
int x, |
|||
int y, |
|||
int nWidth, |
|||
int nHeight, |
|||
IntPtr hWndParent, |
|||
IntPtr hMenu, |
|||
IntPtr hInstance, |
|||
IntPtr lpParam); |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct SETTEXTEX |
|||
{ |
|||
public uint Flags; |
|||
public uint Codepage; |
|||
} |
|||
|
|||
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] |
|||
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
#if IOS
|
|||
using System; |
|||
using System.IO; |
|||
using System.Diagnostics; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Platform; |
|||
using CoreGraphics; |
|||
using Foundation; |
|||
using UIKit; |
|||
using WebKit; |
|||
|
|||
namespace NativeEmbedSample; |
|||
|
|||
public partial class EmbedSample |
|||
{ |
|||
private IPlatformHandle CreateIOS(IPlatformHandle parent) |
|||
{ |
|||
if (IsSecond) |
|||
{ |
|||
var webView = new WKWebView(CGRect.Empty, new WKWebViewConfiguration()); |
|||
webView.LoadRequest(new NSUrlRequest(new NSUrl("https://www.apple.com/"))); |
|||
|
|||
return new UIViewHandle(webView); |
|||
} |
|||
else |
|||
{ |
|||
var button = new UIButton(); |
|||
var clickCount = 0; |
|||
button.SetTitle("Hello world", UIControlState.Normal); |
|||
button.BackgroundColor = UIColor.Blue; |
|||
button.AddTarget((_, _) => |
|||
{ |
|||
clickCount++; |
|||
button.SetTitle($"Click count {clickCount}", UIControlState.Normal); |
|||
}, UIControlEvent.TouchDown); |
|||
|
|||
return new UIViewHandle(button); |
|||
} |
|||
} |
|||
|
|||
private void DestroyIOS(IPlatformHandle control) |
|||
{ |
|||
base.DestroyNativeControlCore(control); |
|||
} |
|||
} |
|||
|
|||
internal class UIViewHandle : INativeControlHostDestroyableControlHandle |
|||
{ |
|||
private UIView _view; |
|||
|
|||
public UIViewHandle(UIView view) |
|||
{ |
|||
_view = view; |
|||
} |
|||
|
|||
public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; |
|||
public string HandleDescriptor => "UIView"; |
|||
|
|||
public void Destroy() |
|||
{ |
|||
_view?.Dispose(); |
|||
_view = null; |
|||
} |
|||
} |
|||
#endif
|
|||
Loading…
Reference in new issue