Skip to content

Commit 9d6ca86

Browse files
authored
Merge pull request #10 from cefsharp/avalonia
Experiment - Avalonia v11 (NativeControlHost)
2 parents 0076eb0 + 81faee7 commit 9d6ca86

17 files changed

+1281
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Application xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Class="CefSharp.Avalonia.Example.App">
4+
<Application.Styles>
5+
<FluentTheme/>
6+
</Application.Styles>
7+
</Application>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Avalonia;
2+
using Avalonia.Controls.ApplicationLifetimes;
3+
using Avalonia.Markup.Xaml;
4+
using CefSharp.Avalonia.Example.ViewModels;
5+
using CefSharp.Avalonia.Example.Views;
6+
using ReactiveUI;
7+
using Splat;
8+
9+
namespace CefSharp.Avalonia.Example;
10+
11+
public partial class App : Application
12+
{
13+
public override void Initialize()
14+
{
15+
AvaloniaXamlLoader.Load(this);
16+
17+
Locator.CurrentMutable.Register(() => new BrowserView(), typeof(IViewFor<BrowserViewModel>));
18+
}
19+
20+
public override void OnFrameworkInitializationCompleted()
21+
{
22+
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
23+
{
24+
var mainWindow = new MainWindow();
25+
26+
desktop.MainWindow = mainWindow;
27+
desktop.ShutdownRequested += (s, e) =>
28+
{
29+
mainWindow.Dispose();
30+
};
31+
}
32+
33+
base.OnFrameworkInitializationCompleted();
34+
}
35+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>WinExe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<AssemblyName>CefSharp.Avalonia.Example</AssemblyName>
7+
<RootNamespace>CefSharp.Avalonia.Example</RootNamespace>
8+
<ApplicationManifest>app.manifest</ApplicationManifest>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Avalonia" Version="11.0.0-preview5" />
13+
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview5" />
14+
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0-preview5" Condition="'$(Configuration)' == 'Debug'" />
15+
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview5" />
16+
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview5" />
17+
<PackageReference Include="XamlNameReferenceGenerator" Version="1.6.1" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<TrimmerRootDescriptor Include="Roots.xml" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="..\CefSharp.Avalonia\CefSharp.Avalonia.csproj" />
26+
</ItemGroup>
27+
28+
</Project>
29+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:rxui="using:Avalonia.ReactiveUI"
4+
x:Class="CefSharp.Avalonia.Example.MainWindow"
5+
MinWidth="500"
6+
MinHeight="300"
7+
Title="CefSharp.Avalonia.Example">
8+
<Window.Styles>
9+
<Style Selector="TabControl">
10+
<Setter Property="Background" Value="#F0F0F0"/>
11+
</Style>
12+
13+
<Style Selector="TabControl WrapPanel">
14+
<Setter Property="Background" Value="#2B579A"/>
15+
</Style>
16+
17+
<Style Selector="TabItem">
18+
<Setter Property="FontSize" Value="16"/>
19+
<Setter Property="Height" Value="34"/>
20+
<Setter Property="VerticalAlignment" Value="Center"/>
21+
<Setter Property="Background" Value="#2B579A"/>
22+
<Setter Property="Foreground" Value="#F0F0F0"/>
23+
</Style>
24+
<Style Selector="TabItem:pointerover">
25+
<Setter Property="Background" Value="#124078"/>
26+
</Style>
27+
28+
<Style Selector="TabItem:selected">
29+
<Setter Property="Background" Value="#f0f0f0"/>
30+
<Setter Property="Foreground" Value="#2B579A"/>
31+
</Style>
32+
</Window.Styles>
33+
34+
<Grid RowDefinitions="Auto, *">
35+
<Menu Name="mainMenu" Grid.Row="0">
36+
<MenuItem Header="_File">
37+
<MenuItem Header="_New Tab" Command="{Binding AddTab}" />
38+
<Separator/>
39+
<MenuItem Header="_Exit" Click="OnFileExitMenuItemClick"/>
40+
</MenuItem>
41+
</Menu>
42+
43+
<TabControl Name="tabControl" Grid.Row="1" Items="{Binding Tabs}" AutoScrollToSelectedItem="True">
44+
<TabControl.ItemTemplate>
45+
<DataTemplate>
46+
<TextBlock Text="{Binding Header}" />
47+
</DataTemplate>
48+
</TabControl.ItemTemplate>
49+
<TabControl.ContentTemplate>
50+
<DataTemplate>
51+
<rxui:ViewModelViewHost ViewModel="{Binding}" />
52+
</DataTemplate>
53+
</TabControl.ContentTemplate>
54+
</TabControl>
55+
</Grid>
56+
</Window>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using Avalonia.Collections;
2+
using Avalonia.Controls;
3+
using Avalonia.Interactivity;
4+
using CefSharp.Avalonia.Example.ViewModels;
5+
using CefSharp.Avalonia.Example.Views;
6+
using CefSharp.OutOfProcess;
7+
using System;
8+
using System.IO;
9+
using System.Threading.Tasks;
10+
11+
namespace CefSharp.Avalonia.Example;
12+
13+
public partial class MainWindow : Window, IDisposable
14+
{
15+
#if DEBUG
16+
private string _buildType = "Debug";
17+
#else
18+
private string _buildType = "Release";
19+
#endif
20+
21+
private OutOfProcessHost _outOfProcessHost;
22+
23+
public MainWindow()
24+
{
25+
InitializeComponent();
26+
27+
_ = InitializeComponentAsync();
28+
}
29+
30+
private async Task InitializeComponentAsync()
31+
{
32+
var outOfProcessHostPath = Path.GetFullPath($"..\\..\\..\\..\\CefSharp.OutOfProcess.BrowserProcess\\bin\\{_buildType}");
33+
outOfProcessHostPath = Path.Combine(outOfProcessHostPath, OutOfProcessHost.HostExeName);
34+
var cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\OutOfProcessCache");
35+
36+
var settings = Settings.WithCachePath(cachePath);
37+
_outOfProcessHost = await OutOfProcessHost.CreateAsync(outOfProcessHostPath, settings);
38+
39+
ChromiumWebBrowser.SetDefaultOutOfProcessHost(_outOfProcessHost);
40+
41+
DataContext = new MainWindowViewModel();
42+
}
43+
44+
private BrowserView ActiveBrowserView => (BrowserView) this.FindControl<TabControl>("tabControl").SelectedContent;
45+
46+
private void OnFileExitMenuItemClick(object sender, RoutedEventArgs e)
47+
{
48+
Close();
49+
}
50+
51+
public void Dispose()
52+
{
53+
_outOfProcessHost?.Dispose();
54+
}
55+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Avalonia;
2+
using Avalonia.ReactiveUI;
3+
using System;
4+
5+
namespace CefSharp.Avalonia.Example;
6+
7+
public static class Program
8+
{
9+
// Initialization code. Don't use any Avalonia, third-party APIs or any
10+
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
11+
// yet and stuff might break.
12+
[STAThread]
13+
public static void Main(string[] args) => BuildAvaloniaApp()
14+
.StartWithClassicDesktopLifetime(args);
15+
16+
// Avalonia configuration, don't remove; also used by visual designer.
17+
public static AppBuilder BuildAvaloniaApp()
18+
=> AppBuilder.Configure<App>()
19+
.UseReactiveUI()
20+
.UsePlatformDetect()
21+
.LogToTrace();
22+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<linker>
2+
<!-- Can be removed if CompiledBinding and no reflection are used -->
3+
<assembly fullname="CefSharp.Avalonia.Example" preserve="All" />
4+
<assembly fullname="Avalonia.Themes.Fluent" preserve="All" />
5+
</linker>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using ReactiveUI;
2+
using System.Runtime.Serialization;
3+
4+
namespace CefSharp.Avalonia.Example.ViewModels
5+
{
6+
public class BrowserViewModel : ViewModelBase
7+
{
8+
private string _header;
9+
10+
[DataMember]
11+
public string Header
12+
{
13+
get => _header;
14+
set => this.RaiseAndSetIfChanged(ref _header, value);
15+
}
16+
}
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Collections.ObjectModel;
2+
3+
namespace CefSharp.Avalonia.Example.ViewModels
4+
{
5+
internal class MainWindowViewModel : ViewModelBase
6+
{
7+
public ObservableCollection<BrowserViewModel> Tabs { get; } = new();
8+
9+
public MainWindowViewModel()
10+
{
11+
AddTab();
12+
}
13+
14+
public void AddTab()
15+
{
16+
Tabs.Add(new BrowserViewModel { Header = "New Tab" });
17+
}
18+
}
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using ReactiveUI;
2+
using System.Reactive.Disposables;
3+
4+
namespace CefSharp.Avalonia.Example.ViewModels
5+
{
6+
public class ViewModelBase : ReactiveObject, IActivatableViewModel
7+
{
8+
public ViewModelActivator Activator { get; }
9+
10+
public ViewModelBase()
11+
{
12+
Activator = new ViewModelActivator();
13+
this.WhenActivated((CompositeDisposable disposables) =>
14+
{
15+
/* handle activation */
16+
Disposable
17+
.Create(() => { /* handle deactivation */ })
18+
.DisposeWith(disposables);
19+
});
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)