Skip to content

Commit 33e07be

Browse files
joaompnevestkefauverJManoOS-sandeeppalafvieira
authored
RDEV-7371 - Upgrade to avalonia 11 (#310)
* Upgrade to avalonia 11 * Fix tests * Update Directory.Build.props * Exposed cef flags (#320) * Exposed chromium command-line args via GlobalSettings property. * Converted cef command line flag access to methods instead of a property. * Update WebViewControl/WebViewLoader.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/GlobalSettings.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/GlobalSettings.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/GlobalSettings.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/WebViewLoader.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/GlobalSettings.cs Co-authored-by: João Neves <[email protected]> * Update WebViewControl/GlobalSettings.cs --------- Co-authored-by: João Neves <[email protected]> * Update Directory.Build.props * Fix webview focus * Introduce support for enabling accessibility state * Execute when initialized * Use latest CefGlue and Avalonia * RDEV-6978 Fix Crash when webview is not yet added to visual tree (#339) * RDEV-6978 Fix Crash with detaching of tab when proxy is enabled Fix Crash with detaching of tab when proxy is enabled * RDEV-6978 Added comment Added comment * RDEV-6978 Updated comment Updated comment * Use latest version of avalonia 11 --------- Co-authored-by: tkefauver <[email protected]> Co-authored-by: João Mano <[email protected]> Co-authored-by: Sandeep Pal <[email protected]> Co-authored-by: André Pinto Vieira <[email protected]>
1 parent 442b6a4 commit 33e07be

14 files changed

+291
-269
lines changed

Directory.Build.props

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
<DefaultTargetDotnetVersion>net8.0</DefaultTargetDotnetVersion>
55
<TargetDotnetVersions>net6.0;$(DefaultTargetDotnetVersion)</TargetDotnetVersions>
66
<Platforms>x64;ARM64</Platforms>
7-
<AvaloniaVersion>0.10.17</AvaloniaVersion>
8-
<CefGlueVersion>120.6099.200</CefGlueVersion>
7+
<AvaloniaVersion>11.0.11</AvaloniaVersion>
8+
<CefGlueVersion>120.6099.201</CefGlueVersion>
99
</PropertyGroup>
1010

1111
<PropertyGroup>
1212
<AssemblyVersion>2.0.0.0</AssemblyVersion>
1313
<FileVersion>2.0.0.0</FileVersion>
14-
<Version>3.120.0</Version>
14+
<Version>3.120.1</Version>
1515
<Authors>OutSystems</Authors>
1616
<Product>WebViewControl</Product>
1717
<Copyright>Copyright © OutSystems 2023</Copyright>

Directory.Packages.props

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
<PackageVersion Include="Avalonia" Version="$(AvaloniaVersion)" />
2020
<PackageVersion Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
2121
<PackageVersion Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
22+
<PackageVersion Include="Avalonia.Themes.Simple" Version="$(AvaloniaVersion)" />
23+
<PackageVersion Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
2224

2325
<PackageVersion Include="CefGlue.Avalonia" Version="$(CefGlueVersion)" />
2426
<PackageVersion Include="CefGlue.WPF" Version="$(CefGlueVersion)" />

SampleWebView.Avalonia/App.xaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
<Application xmlns="https://github.com/avaloniaui"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3-
xmlns:sys="clr-namespace:System;assembly=netstandard"
43
x:Class="SampleWebView.Avalonia.App">
54
<Application.Resources>
65
<Thickness x:Key="TextControlBorderThemeThickness">0</Thickness>
76
<Thickness x:Key="TextControlBorderThemeThicknessFocused">0</Thickness>
87
<Thickness x:Key="TextControlThemePadding">15,10,15,8</Thickness>
98
</Application.Resources>
109
<Application.Styles>
11-
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentDark.xaml"/>
10+
<FluentTheme />
1211
</Application.Styles>
1312
</Application>

SampleWebView.Avalonia/MainWindow.xaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
<NativeMenu>
1616
<NativeMenuItem Header="Undo" Command="{Binding UndoCommand}" Gesture="CMD+Z" />
1717
<NativeMenuItem Header="Redo" Command="{Binding RedoCommand}" Gesture="Shift+CMD+Z" />
18-
<NativeMenuItemSeperator/>
18+
<NativeMenuItemSeparator/>
1919
<NativeMenuItem Header="Cut" Command="{Binding CutCommand}" Gesture="CMD+X" />
2020
<NativeMenuItem Header="Copy" Command="{Binding CopyCommand}" Gesture="CMD+C" />
2121
<NativeMenuItem Header="Paste" Command="{Binding PasteCommand}" Gesture="CMD+V" />
2222
<NativeMenuItem Header="Delete" Command="{Binding DeleteCommand}" Gesture="CMD+Back" />
23-
<NativeMenuItemSeperator/>
23+
<NativeMenuItemSeparator/>
2424
<NativeMenuItem Header="Select All" Command="{Binding SelectAllCommand}" Gesture="CMD+A" />
2525
</NativeMenu>
2626
</NativeMenuItem.Menu>
@@ -50,14 +50,14 @@
5050

5151
<DockPanel DockPanel.Dock="Top" Margin="0 0 400 0">
5252
<Button DockPanel.Dock="Right" Background="Transparent" Command="{Binding ShowDevToolsCommand}">Show DevTools</Button>
53-
<TextBox Background="Transparent" Text="{Binding Address}" Margin="80 0 0 0">
53+
<TextBox Background="Transparent" TabIndex="0" Text="{Binding Address}" Margin="80 0 0 0">
5454
<TextBox.KeyBindings>
5555
<KeyBinding Gesture="Enter" Command="{Binding NavigateCommand}" />
5656
</TextBox.KeyBindings>
5757
</TextBox>
5858
</DockPanel>
5959

60-
<webview:WebView x:Name="webview" Address="{Binding CurrentAddress}" />
60+
<webview:WebView x:Name="webview" Focusable="True" Address="{Binding CurrentAddress}" />
6161
</DockPanel>
6262
</Panel>
6363
</Window>

SampleWebView.Avalonia/Program.cs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
using Avalonia;
2-
using Avalonia.ReactiveUI;
3-
4-
namespace SampleWebView.Avalonia {
5-
6-
class Program {
7-
static void Main(string[] args) {
8-
AppBuilder.Configure<App>()
9-
.UsePlatformDetect()
10-
.With(new Win32PlatformOptions { UseWindowsUIComposition = false })
11-
.UseReactiveUI()
12-
.StartWithClassicDesktopLifetime(args);
13-
}
14-
}
15-
}
1+
using Avalonia;
2+
using Avalonia.ReactiveUI;
3+
4+
namespace SampleWebView.Avalonia {
5+
6+
class Program {
7+
static void Main(string[] args) {
8+
AppBuilder.Configure<App>()
9+
.UsePlatformDetect()
10+
.UseReactiveUI()
11+
.StartWithClassicDesktopLifetime(args);
12+
}
13+
}
14+
}

SampleWebView.Avalonia/SampleWebView.Avalonia.csproj

+5-4
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,18 @@
3030
</ItemGroup>
3131

3232
<ItemGroup>
33-
<EmbeddedResource Include="App.xaml">
33+
<AvaloniaResource Include="App.xaml">
3434
<Generator>MSBuild:Compile</Generator>
35-
</EmbeddedResource>
36-
<EmbeddedResource Include="MainWindow.xaml">
35+
</AvaloniaResource >
36+
<AvaloniaResource Include="MainWindow.xaml">
3737
<Generator>MSBuild:Compile</Generator>
38-
</EmbeddedResource>
38+
</AvaloniaResource >
3939
</ItemGroup>
4040

4141
<ItemGroup>
4242
<PackageReference Include="Avalonia.Desktop" />
4343
<PackageReference Include="Avalonia.ReactiveUI" />
44+
<PackageReference Include="Avalonia.Themes.Fluent" />
4445
<PackageReference Include="Dotnet.Bundle" />
4546
</ItemGroup>
4647

+100-98
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,100 @@
1-
using System;
2-
using System.Runtime.ExceptionServices;
3-
using Avalonia;
4-
using Avalonia.Controls;
5-
using Avalonia.Data;
6-
using Avalonia.Input;
7-
using Avalonia.Threading;
8-
9-
namespace WebViewControl {
10-
11-
partial class WebView : BaseControl {
12-
13-
private bool IsInDesignMode => false;
14-
15-
public static readonly StyledProperty<string> AddressProperty =
16-
AvaloniaProperty.Register<WebView, string>(nameof(Address), defaultBindingMode: BindingMode.TwoWay);
17-
18-
public string Address {
19-
get => GetValue(AddressProperty);
20-
set => SetValue(AddressProperty, value);
21-
}
22-
23-
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) {
24-
base.OnPropertyChanged(change);
25-
26-
if (change.Property == AddressProperty) {
27-
InternalAddress = Address;
28-
}
29-
}
30-
31-
partial void ExtraInitialize() {
32-
VisualChildren.Add(chromium);
33-
chromium.AddressChanged += (o, address) => ExecuteInUI(() => Address = address);
34-
}
35-
36-
protected override void OnKeyDown(KeyEventArgs e) {
37-
if (AllowDeveloperTools && e.Key == Key.F12) {
38-
ToggleDeveloperTools();
39-
e.Handled = true;
40-
}
41-
}
42-
43-
protected override void OnGotFocus(GotFocusEventArgs e) {
44-
if (!e.Handled) {
45-
e.Handled = true;
46-
base.OnGotFocus(e);
47-
48-
// use async call to avoid reentrancy, otherwise the webview will fight to get the focus
49-
Dispatcher.UIThread.Post(() => {
50-
if (IsFocused) {
51-
chromium.Focus();
52-
}
53-
}, DispatcherPriority.Background);
54-
}
55-
}
56-
57-
protected override void InternalDispose() => Dispose();
58-
59-
private void ForwardException(ExceptionDispatchInfo exceptionInfo) {
60-
// TODO
61-
}
62-
63-
private T ExecuteInUI<T>(Func<T> action) {
64-
if (Dispatcher.UIThread.CheckAccess()) {
65-
return action();
66-
}
67-
return Dispatcher.UIThread.InvokeAsync<T>(action).Result;
68-
}
69-
70-
private void AsyncExecuteInUI(Action action) {
71-
if (isDisposing) {
72-
return;
73-
}
74-
// use async call to avoid dead-locks, otherwise if the source action tries to to evaluate js it would block
75-
Dispatcher.UIThread.InvokeAsync(
76-
() => {
77-
if (!isDisposing) {
78-
ExecuteWithAsyncErrorHandling(action);
79-
}
80-
},
81-
DispatcherPriority.Normal);
82-
}
83-
84-
internal void InitializeBrowser(int initialWidth, int initialHeight) {
85-
chromium.CreateBrowser(initialWidth, initialHeight);
86-
}
87-
88-
/// <summary>
89-
/// Called when the webview is requesting focus. Return false to allow the
90-
/// focus to be set or true to cancel setting the focus.
91-
/// <paramref name="isSystemEvent">True if is a system focus event, or false if is a navigation</paramref>
92-
/// </summary>
93-
protected virtual bool OnSetFocus(bool isSystemEvent) {
94-
var focusedElement = KeyboardDevice.Instance.FocusedElement;
95-
return !(focusedElement == chromium || focusedElement == this);
96-
}
97-
}
98-
}
1+
using System;
2+
using System.Runtime.ExceptionServices;
3+
using Avalonia;
4+
using Avalonia.Controls;
5+
using Avalonia.Data;
6+
using Avalonia.Input;
7+
using Avalonia.Threading;
8+
9+
namespace WebViewControl {
10+
11+
partial class WebView : BaseControl {
12+
13+
private bool IsInDesignMode => false;
14+
15+
public static readonly StyledProperty<string> AddressProperty =
16+
AvaloniaProperty.Register<WebView, string>(nameof(Address), defaultBindingMode: BindingMode.TwoWay);
17+
18+
public string Address {
19+
get => GetValue(AddressProperty);
20+
set => SetValue(AddressProperty, value);
21+
}
22+
23+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) {
24+
base.OnPropertyChanged(change);
25+
26+
if (change.Property == AddressProperty) {
27+
InternalAddress = Address;
28+
}
29+
}
30+
31+
partial void ExtraInitialize() {
32+
VisualChildren.Add(chromium);
33+
chromium[!FocusableProperty] = this[!FocusableProperty];
34+
chromium.AddressChanged += (o, address) => ExecuteInUI(() => Address = address);
35+
}
36+
37+
protected override void OnKeyDown(KeyEventArgs e) {
38+
if (AllowDeveloperTools && e.Key == Key.F12) {
39+
ToggleDeveloperTools();
40+
e.Handled = true;
41+
}
42+
}
43+
44+
protected override void OnGotFocus(GotFocusEventArgs e) {
45+
if (!e.Handled) {
46+
e.Handled = true;
47+
base.OnGotFocus(e);
48+
49+
// use async call to avoid reentrancy, otherwise the webview will fight to get the focus
50+
Dispatcher.UIThread.Post(() => {
51+
if (IsFocused) {
52+
chromium.Focus();
53+
}
54+
}, DispatcherPriority.Background);
55+
}
56+
}
57+
58+
protected override void InternalDispose() => Dispose();
59+
60+
private void ForwardException(ExceptionDispatchInfo exceptionInfo) {
61+
// TODO
62+
}
63+
64+
private T ExecuteInUI<T>(Func<T> action) {
65+
if (Dispatcher.UIThread.CheckAccess()) {
66+
return action();
67+
}
68+
return Dispatcher.UIThread.InvokeAsync<T>(action).Result;
69+
}
70+
71+
private void AsyncExecuteInUI(Action action) {
72+
if (isDisposing) {
73+
return;
74+
}
75+
// use async call to avoid dead-locks, otherwise if the source action tries to to evaluate js it would block
76+
Dispatcher.UIThread.InvokeAsync(
77+
() => {
78+
if (!isDisposing) {
79+
ExecuteWithAsyncErrorHandling(action);
80+
}
81+
},
82+
DispatcherPriority.Normal);
83+
}
84+
85+
internal void InitializeBrowser(int initialWidth, int initialHeight) {
86+
chromium.CreateBrowser(initialWidth, initialHeight);
87+
}
88+
89+
/// <summary>
90+
/// Called when the webview is requesting focus. Return false to allow the
91+
/// focus to be set or true to cancel setting the focus.
92+
/// <paramref name="isSystemEvent">True if is a system focus event, or false if is a navigation</paramref>
93+
/// </summary>
94+
protected virtual bool OnSetFocus(bool isSystemEvent) {
95+
// VisualRoot can be null when webview is not yet added to the Visual tree
96+
var focusedElement = TopLevel.GetTopLevel(this)?.FocusManager.GetFocusedElement();
97+
return !(focusedElement == chromium || focusedElement == this);
98+
}
99+
}
100+
}

WebViewControl/GlobalSettings.cs

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using Xilium.CefGlue.Common;
45

@@ -12,6 +13,17 @@ public class GlobalSettings {
1213
private string userAgent;
1314
private string logFile;
1415
private string cachePath = Path.Combine(Path.GetTempPath(), "WebView" + Guid.NewGuid().ToString().Replace("-", null) + DateTime.UtcNow.Ticks);
16+
private readonly List<KeyValuePair<string, string>> commandLineSwitches = new();
17+
18+
/// <summary>
19+
/// Use this method to pass flags to the browser. List of available flags: https://peter.sh/experiments/chromium-command-line-switches/
20+
/// </summary>
21+
public void AddCommandLineSwitch(string key, string value) {
22+
EnsureNotLoaded(nameof(AddCommandLineSwitch));
23+
commandLineSwitches.Add(new KeyValuePair<string, string>(key, value));
24+
}
25+
26+
public IEnumerable<KeyValuePair<string, string>> CommandLineSwitches => commandLineSwitches;
1527

1628
public string CachePath {
1729
get => cachePath;

WebViewControl/WebView.Extensions.cs

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ internal static bool IsMainFrame(this WebView webview, string frameName) {
2424
internal static void SendKeyEvent(this WebView webview, CefKeyEvent keyEvent) {
2525
webview.GetCefBrowser()?.GetHost()?.SendKeyEvent(keyEvent);
2626
}
27+
28+
internal static void SetAccessibilityState(this WebView webview, CefState state) {
29+
webview.GetCefBrowser()?.GetHost()?.SetAccessibilityState(state);
30+
}
2731

2832
private static CefBrowser GetCefBrowser(this WebView webview) {
2933
return webview.UnderlyingBrowser.GetBrowser();

WebViewControl/WebView.cs

+6
Original file line numberDiff line numberDiff line change
@@ -530,5 +530,11 @@ protected virtual void OnGotFocus() { }
530530
/// focus was on the last HTML element and the user pressed the TAB key.
531531
/// </summary>
532532
protected virtual void OnLostFocus() { }
533+
534+
/// <summary>
535+
/// Enables or disable support for accessibility tools like screen readers.
536+
/// </summary>
537+
public void EnableAccessibility(bool enable) =>
538+
ExecuteWhenInitialized(() => this.SetAccessibilityState(enable ? CefState.Enabled : CefState.Disabled));
533539
}
534540
}

0 commit comments

Comments
 (0)