Avalonia的WebView会收费,所以自己写一个,下一个例子给出使用例子。结构示意图。

image

WebView.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Xilium.CefGlue;
using Xilium.CefGlue.Avalonia;
using Xilium.CefGlue.Common.Events;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed partial class WebView : UserControl, IDisposable
{
    public static readonly StyledProperty<Uri> SourceProperty =
        AvaloniaProperty.Register<WebView, Uri>(
            nameof(Source),
            defaultValue: BlankUri!,
            defaultBindingMode: BindingMode.TwoWay);

    public static readonly DirectProperty<WebView, bool> CanGoBackProperty =
        AvaloniaProperty.RegisterDirect<WebView, bool>(nameof(CanGoBack), o => o.cangoback);

    public static readonly DirectProperty<WebView, bool> CanGoForwardProperty =
        AvaloniaProperty.RegisterDirect<WebView, bool>(nameof(CanGoForward), o => o.cangoforward);

    private static readonly Uri BlankUri = new("about:blank");

    private readonly AvaloniaCefBrowser view;
    private readonly WebViewCookieManager cookieManager;
    private readonly WebViewScripting scripting;
    private readonly Dictionary<string, object> jsObjectsByName = new(StringComparer.Ordinal);
    private readonly Dictionary<string, WebViewJsObjectInfo> jsInfosByName = new(StringComparer.Ordinal);

    private CefBrowser? cefBrowser;
    private bool isDisposed;
    private bool isDisposing;
    private bool isUpdatingSourceFromBrowser;
    private bool isApplyingSource;
    private int forwardedNavigationDepth;
    private bool cangoback;
    private bool cangoforward;

    public WebView()
    {
        view = new AvaloniaCefBrowser
        {
            RequestHandler = new RequestHandlerImpl(this),
            LifeSpanHandler = new LifeSpanHandlerImpl(this),
        };

        var requestContext = CefRequestContext.GetGlobalContext();
        var manager = requestContext.GetCookieManager(null);

        cookieManager = new WebViewCookieManager(manager);
        scripting = new WebViewScripting(view);

        Content = view;

        view.LoadStart += OnLoadStart;
        view.LoadEnd += OnLoadEnd;
        DetachedFromVisualTree += OnDetachedFromVisualTree;

        ApplySourceCore(Source);
        ResetNavState();
    }

    public Uri Source
    {
        get => GetValue(SourceProperty);
        set => SetValue(SourceProperty, value);
    }

    public bool CanGoBack
    {
        get => cangoback;
        private set => SetAndRaise(CanGoBackProperty, ref cangoback, value);
    }

    public bool CanGoForward
    {
        get => cangoforward;
        private set => SetAndRaise(CanGoForwardProperty, ref cangoforward, value);
    }

    public WebViewCookieManager CookieManager => cookieManager;
    public WebViewScripting Scripting => scripting;
    public IReadOnlyCollection<WebViewJsObjectInfo> JavascriptObjectInfos => [.. jsInfosByName.Values];

    public event EventHandler<WebViewRequestingEventArgs>? Requesting;
    public event EventHandler<WebViewRequestedEventArgs>? Requested;
    public event EventHandler<WebViewNavigationCompletedEventArgs>? NavigationCompleted;

    public void Navigate(string url)
    {
        if (string.IsNullOrWhiteSpace(url))
            return;

        if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
            return;

        Navigate(uri);
    }

    public void Navigate(Uri uri)
    {
        ArgumentNullException.ThrowIfNull(uri);

        ExecuteOnUiThread(() =>
        {
            if (!CanUseControl())
                return;

            if (forwardedNavigationDepth == 0 && TryDispatchProgrammaticNavigation(uri))
                return;

            ApplySourceCore(uri);
        });
    }

    public bool GoBack() => ExecuteOnUiThread(GoBackCore);

    public bool GoForward() => ExecuteOnUiThread(GoForwardCore);

    public bool Refresh() => ExecuteOnUiThread(RefreshCore);

    public bool Stop() => ExecuteOnUiThread(StopCore);

    public void ExecuteScript(string script)
    {
        if (string.IsNullOrWhiteSpace(script))
            return;

        ExecuteOnUiThread(() =>
        {
            if (!CanUseControl())
                return;

            try
            {
                scripting.Execute(script);
            }
            catch
            {
            }
        });
    }

    public Task<T> EvaluateScriptAsync<T>(string script)
    {
        if (string.IsNullOrWhiteSpace(script))
            return Task.FromResult(default(T)!);

        if (!CanUseControl())
            return Task.FromResult(default(T)!);

        if (Dispatcher.UIThread.CheckAccess())
        {
            try
            {
                if (!CanUseControl())
                    return Task.FromResult(default(T)!);

                return scripting.Evaluate<T>(script);
            }
            catch
            {
                return Task.FromResult(default(T)!);
            }
        }

        var tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);

        try
        {
            Dispatcher.UIThread.Post(async () =>
            {
                if (!CanUseControl())
                {
                    tcs.TrySetResult(default!);
                    return;
                }

                try
                {
                    var result = await scripting.Evaluate<T>(script).ConfigureAwait(false);
                    tcs.TrySetResult(result);
                }
                catch
                {
                    tcs.TrySetResult(default!);
                }
            });
        }
        catch
        {
            tcs.TrySetResult(default!);
        }

        return tcs.Task;
    }

    public void AddScriptObject(string name, object instance)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("Name cannot be null or whitespace.", nameof(name));

        ArgumentNullException.ThrowIfNull(instance);

        ExecuteOnUiThread(() =>
        {
            if (!CanUseControl())
                return;

            if (jsObjectsByName.TryGetValue(name, out var existing))
            {
                if (ReferenceEquals(existing, instance))
                    return;

                throw new InvalidOperationException($"Duplicate JS name '{name}'.");
            }

            var info = CreateJsObjectInfo(name, instance);

            view.RegisterJavascriptObject(instance, name);

            jsObjectsByName[name] = instance;
            jsInfosByName[name] = info;
        });
    }

    public bool RemoveScriptObject(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            return false;

        return ExecuteOnUiThread(() =>
        {
            if (!CanUseControl())
                return false;

            return RemoveScriptObjectCore(name);
        });
    }

    public void ClearScriptObjects()
    {
        ExecuteOnUiThread(() =>
        {
            if (!CanUseControl())
                return;

            ClearScriptObjectsCore();
        });
    }

    public void Dispose()
    {
        if (isDisposed || isDisposing)
            return;

        if (!Dispatcher.UIThread.CheckAccess())
        {
            Dispatcher.UIThread.Post(Dispose);
            return;
        }

        isDisposing = true;

        try
        {
            DetachedFromVisualTree -= OnDetachedFromVisualTree;
        }
        catch
        {
        }

        try
        {
            view.LoadStart -= OnLoadStart;
            view.LoadEnd -= OnLoadEnd;
        }
        catch
        {
        }

        try
        {
            ClearScriptObjectsCore();
        }
        catch
        {
        }

        try
        {
            view.Dispose();
        }
        catch
        {
        }

        cefBrowser = null;
        Content = null;
        isDisposed = true;
        isDisposing = false;
        ResetNavState();
    }

    protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
    {
        base.OnPropertyChanged(change);

        if (change.Property != SourceProperty)
            return;

        if (!CanUseControl())
            return;

        if (isUpdatingSourceFromBrowser || isApplyingSource)
            return;

        var uri = change.GetNewValue<Uri>();

        if (uri is null)
            return;

        if (forwardedNavigationDepth == 0 && TryDispatchProgrammaticNavigation(uri))
            return;

        ApplySourceCore(uri);
    }

    private bool CanUseControl() => !isDisposed && !isDisposing;

    private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
    {
        Dispose();
    }

    private bool TryDispatchProgrammaticNavigation(Uri uri)
    {
        var args = CreateRequestedArgs(WebViewRequestKind.Navigation, uri, "GET", true);

        DispatchRequested(args);

        if (args.Target is not null)
        {
            NavigateForwarded(args.Target, args.Uri);
            return true;
        }

        return args.Cancel;
    }

    private void ApplySourceCore(Uri uri)
    {
        if (!CanUseControl())
            return;

        if (uri is null)
            return;

        isApplyingSource = true;

        try
        {
            view.Address = uri.ToString();
        }
        catch
        {
        }
        finally
        {
            isApplyingSource = false;
        }
    }

    private bool GoBackCore()
    {
        if (!TryGetUsableBrowser(out var browser))
            return false;

        try
        {
            if (!browser.CanGoBack)
            {
                UpdateNavState();
                return false;
            }

            browser.GoBack();
            UpdateNavState();
            return true;
        }
        catch
        {
            ResetNavState();
            return false;
        }
    }

    private bool GoForwardCore()
    {
        if (!TryGetUsableBrowser(out var browser))
            return false;

        try
        {
            if (!browser.CanGoForward)
            {
                UpdateNavState();
                return false;
            }

            browser.GoForward();
            UpdateNavState();
            return true;
        }
        catch
        {
            ResetNavState();
            return false;
        }
    }

    private bool RefreshCore()
    {
        if (!TryGetUsableBrowser(out var browser))
            return false;

        try
        {
            browser.Reload();
            return true;
        }
        catch
        {
            return false;
        }
    }

    private bool StopCore()
    {
        if (!TryGetUsableBrowser(out var browser))
            return false;

        try
        {
            browser.StopLoad();
            return true;
        }
        catch
        {
            return false;
        }
    }

    private bool TryGetUsableBrowser(out CefBrowser browser)
    {
        browser = null!;

        if (!CanUseControl())
            return false;

        if (cefBrowser is null)
            return false;

        browser = cefBrowser;
        return true;
    }

    private void UpdateNavState()
    {
        if (!TryGetUsableBrowser(out var browser))
        {
            ResetNavState();
            return;
        }

        try
        {
            CanGoBack = browser.CanGoBack;
            CanGoForward = browser.CanGoForward;
        }
        catch
        {
            ResetNavState();
        }
    }

    private void ResetNavState()
    {
        CanGoBack = false;
        CanGoForward = false;
    }

    private bool RemoveScriptObjectCore(string name)
    {
        if (!jsObjectsByName.ContainsKey(name))
            return false;

        TryUnregisterJavascriptObject(name);

        jsObjectsByName.Remove(name);
        jsInfosByName.Remove(name);
        return true;
    }

    private void ClearScriptObjectsCore()
    {
        if (jsObjectsByName.Count == 0)
            return;

        foreach (var name in jsObjectsByName.Keys.ToArray())
            TryUnregisterJavascriptObject(name);

        jsObjectsByName.Clear();
        jsInfosByName.Clear();
    }

    private void TryUnregisterJavascriptObject(string name)
    {
        try
        {
            view.UnregisterJavascriptObject(name);
        }
        catch
        {
        }
    }

    private void OnLoadStart(object? sender, LoadStartEventArgs e)
    {
        if (!ShouldHandleLoadEvent(e.Frame))
            return;

        cefBrowser = e.Frame.Browser;
        var uri = SafeUri(e.Frame.Url);

        Dispatcher.UIThread.Post(() =>
        {
            if (!CanUseControl())
                return;

            isUpdatingSourceFromBrowser = true;

            try
            {
                SetCurrentValue(SourceProperty, uri);
                UpdateNavState();
            }
            finally
            {
                isUpdatingSourceFromBrowser = false;
            }
        });
    }

    private void OnLoadEnd(object? sender, LoadEndEventArgs e)
    {
        if (!ShouldHandleLoadEvent(e.Frame))
            return;

        cefBrowser = e.Frame.Browser;
        var uri = SafeUri(e.Frame.Url);
        var statusCode = e.HttpStatusCode;
        var isSuccess = statusCode == 0 || statusCode is >= 200 and <= 399;
        var error = isSuccess ? null : $"HTTP {statusCode}";

        Dispatcher.UIThread.Post(() =>
        {
            if (!CanUseControl())
                return;

            UpdateNavState();
            NavigationCompleted?.Invoke(this, new WebViewNavigationCompletedEventArgs(uri, isSuccess, error, cookieManager, scripting));
        });
    }

    private static bool ShouldHandleLoadEvent(CefFrame frame)
    {
        if (!frame.IsMain)
            return false;

        if (frame.Browser.IsPopup)
            return false;

        return true;
    }

    private void DispatchRequested(WebViewRequestedEventArgs args)
    {
        if (!CanUseControl())
        {
            args.Cancel = true;
            return;
        }

        Requested?.Invoke(this, args);
    }

    private void RaiseRequesting(WebViewRequestingEventArgs args)
    {
        if (!CanUseControl())
        {
            args.Cancel = true;
            return;
        }

        Requesting?.Invoke(this, args);
    }

    private WebViewRequestedEventArgs CreateRequestedArgs(WebViewRequestKind kind, Uri uri, string method, bool isMainFrame, WebViewRequestHeaders? headers = null)
        => new(
            kind: kind,
            uri: uri,
            method: method,
            isMainFrame: isMainFrame,
            headers: headers ?? new WebViewRequestHeaders(),
            cookieManager: cookieManager,
            scripting: scripting);

    private WebViewRequestingEventArgs CreateRequestingArgs(WebViewRequestKind kind, Uri uri, string method, bool isMainFrame, WebViewRequestHeaders headers)
        => new(
            kind: kind,
            uri: uri,
            method: method,
            isMainFrame: isMainFrame,
            headers: headers,
            cookieManager: cookieManager,
            scripting: scripting);

    private static void TryApplyHeaders(CefRequest request, WebViewRequestHeaders headers)
    {
        try
        {
            request.SetHeaderMap(headers.Raw);
        }
        catch
        {
        }
    }

    private T ExecuteOnUiThread<T>(Func<T> func)
    {
        if (Dispatcher.UIThread.CheckAccess())
            return func();

        return Dispatcher.UIThread.InvokeAsync(func).GetAwaiter().GetResult();
    }

    private void ExecuteOnUiThread(Action action)
    {
        if (Dispatcher.UIThread.CheckAccess())
        {
            action();
            return;
        }

        Dispatcher.UIThread.InvokeAsync(action).GetAwaiter().GetResult();
    }

    private void InvokeOnUiThreadAndWait(Action action)
    {
        if (Dispatcher.UIThread.CheckAccess())
        {
            action();
            return;
        }

        Dispatcher.UIThread.InvokeAsync(action).GetAwaiter().GetResult();
    }

    private static WebViewJsObjectInfo CreateJsObjectInfo(string name, object instance)
    {
        var type = instance.GetType();

        var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
            .Where(m => !m.IsSpecialName)
            .Where(m => m.DeclaringType != typeof(object))
            .Select(m => m.Name)
            .Distinct(StringComparer.Ordinal)
            .OrderBy(x => x, StringComparer.Ordinal)
            .ToArray();

        return new WebViewJsObjectInfo
        {
            Name = name,
            Type = type,
            Methods = methods
        };
    }

    private static Uri SafeUri(string? url)
        => Uri.TryCreate(url, UriKind.Absolute, out var uri) ? uri : BlankUri;

    private static void NavigateLater(WebView target, Uri uri)
    {
        Dispatcher.UIThread.Post(() =>
        {
            if (!target.CanUseControl())
                return;

            target.Navigate(uri);
        });
    }

    private static void NavigateForwarded(WebView target, Uri uri)
    {
        Dispatcher.UIThread.Post(() =>
        {
            if (!target.CanUseControl())
                return;

            target.forwardedNavigationDepth++;

            try
            {
                target.Navigate(uri);
            }
            finally
            {
                target.forwardedNavigationDepth--;
            }
        });
    }
}

WebViewCookieManager.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xilium.CefGlue;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewCookieManager
{
    private readonly CefCookieManager manager;

    internal WebViewCookieManager(CefCookieManager manager) => this.manager = manager;

    public async Task<CefCookie[]> GetCookiesAsync(Uri uri, bool includeHttpOnly = true)
    {
        var collector = new CookieCollector();
        var ok = manager.VisitUrlCookies(uri.ToString(), includeHttpOnly, collector);

        if (!ok)
            return [];

        return await collector.Task.ConfigureAwait(false);
    }

    public Task<bool> SetCookieAsync(Uri uri, CefCookie cookie)
    {
        var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
        var ok = manager.SetCookie(uri.ToString(), cookie, new SetCookieCallback(v => tcs.TrySetResult(v)));

        if (!ok)
            tcs.TrySetResult(false);

        return tcs.Task;
    }

    public Task<int> DeleteCookiesAsync(Uri uri, string? cookieName = null)
    {
        var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
        var ok = manager.DeleteCookies(uri.ToString(), cookieName ?? string.Empty, new DeleteCookiesCallback(v => tcs.TrySetResult(v)));

        if (!ok)
            tcs.TrySetResult(0);

        return tcs.Task;
    }

    private sealed class CookieCollector : CefCookieVisitor
    {
        private readonly TaskCompletionSource<CefCookie[]> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
        private readonly List<CefCookie> cookies = [];
        private bool completed;

        public Task<CefCookie[]> Task => tcs.Task;

        protected override bool Visit(CefCookie cookie, int count, int total, out bool deleteCookie)
        {
            deleteCookie = false;

            if (completed)
                return false;

            cookies.Add(cookie);

            if (count >= total - 1)
                Complete();

            return true;
        }

        protected override void Dispose(bool disposing)
        {
            Complete();
            base.Dispose(disposing);
        }

        private void Complete()
        {
            if (completed)
                return;

            completed = true;
            tcs.TrySetResult([.. cookies]);
        }
    }

    private sealed class SetCookieCallback(Action<bool> action) : CefSetCookieCallback
    {
        protected override void OnComplete(bool success) => action(success);
    }

    private sealed class DeleteCookiesCallback(Action<int> action) : CefDeleteCookiesCallback
    {
        protected override void OnComplete(int numDeleted) => action(numDeleted);
    }
}

WebViewHandlers.cs

using Avalonia.Threading;
using Xilium.CefGlue;
using Xilium.CefGlue.Common.Handlers;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed partial class WebView
{
    private sealed class LifeSpanHandlerImpl(WebView owner) : LifeSpanHandler
    {
        protected override bool OnBeforePopup(
            CefBrowser browser,
            CefFrame frame,
            string targetUrl,
            string targetFrameName,
            CefWindowOpenDisposition targetDisposition,
            bool userGesture,
            CefPopupFeatures popupFeatures,
            CefWindowInfo windowInfo,
            ref CefClient client,
            CefBrowserSettings settings,
            ref CefDictionaryValue extraInfo,
            ref bool noJavascriptAccess)
        {
            var uri = SafeUri(targetUrl);

            var args = owner.CreateRequestedArgs(
                kind: WebViewRequestKind.Popup,
                uri: uri,
                method: "GET",
                isMainFrame: true);

            owner.InvokeOnUiThreadAndWait(() => owner.DispatchRequested(args));

            if (args.Target is not null)
            {
                NavigateForwarded(args.Target, args.Uri);
                return true;
            }

            if (!args.Cancel)
                NavigateLater(owner, args.Uri);

            return true;
        }
    }

    private sealed class RequestHandlerImpl(WebView owner) : RequestHandler
    {
        protected override CefResourceRequestHandler GetResourceRequestHandler(
            CefBrowser browser,
            CefFrame frame,
            CefRequest request,
            bool isNavigation,
            bool isDownload,
            string requestInitiator,
            ref bool disableDefaultHandling)
        {
            return new ResourceRequestHandlerImpl(owner);
        }

        protected override bool OnBeforeBrowse(CefBrowser browser, CefFrame frame, CefRequest request, bool userGesture, bool isRedirect)
        {
            if (!frame.IsMain)
                return false;

            var uri = SafeUri(request.Url);
            var method = request.Method ?? "GET";
            var headers = new WebViewRequestHeaders(request.GetHeaderMap());

            var args = owner.CreateRequestedArgs(
                kind: WebViewRequestKind.Navigation,
                uri: uri,
                method: method,
                isMainFrame: true,
                headers: headers);

            owner.InvokeOnUiThreadAndWait(() => owner.DispatchRequested(args));

            if (args.Target is not null)
            {
                NavigateForwarded(args.Target, args.Uri);
                return true;
            }

            if (args.Cancel)
                return true;

            TryApplyHeaders(request, headers);
            return false;
        }
    }

    private sealed class ResourceRequestHandlerImpl(WebView owner) : CefResourceRequestHandler
    {
        protected override CefCookieAccessFilter GetCookieAccessFilter(CefBrowser browser, CefFrame frame, CefRequest request)
            => null!;

        protected override CefReturnValue OnBeforeResourceLoad(CefBrowser browser, CefFrame frame, CefRequest request, CefCallback callback)
        {
            var uri = SafeUri(request.Url);
            var method = request.Method ?? "GET";
            var kind = frame.IsMain ? WebViewRequestKind.Navigation : WebViewRequestKind.Resource;
            var headers = new WebViewRequestHeaders(request.GetHeaderMap());

            var args = owner.CreateRequestingArgs(
                kind: kind,
                uri: uri,
                method: method,
                isMainFrame: frame.IsMain,
                headers: headers);

            if (Dispatcher.UIThread.CheckAccess())
            {
                owner.RaiseRequesting(args);

                if (args.Cancel)
                    return CefReturnValue.Cancel;

                TryApplyHeaders(request, headers);
                return CefReturnValue.Continue;
            }

            Dispatcher.UIThread.Post(() =>
            {
                try
                {
                    owner.RaiseRequesting(args);

                    if (!args.Cancel)
                        TryApplyHeaders(request, headers);
                }
                catch
                {
                }
                finally
                {
                    try
                    {
                        if (args.Cancel)
                            callback?.Cancel();
                        else
                            callback?.Continue();
                    }
                    catch
                    {
                    }
                }
            });

            return CefReturnValue.ContinueAsync;
        }
    }
}

WebViewJsObjectInfo.cs

using System;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewJsObjectInfo
{
    public required string Name { get; init; }
    public required Type Type { get; init; }
    public required string[] Methods { get; init; }
}

WebViewNavigationCompletedEventArgs.cs

using System;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewNavigationCompletedEventArgs(
    Uri uri,
    bool isSuccess,
    string? error,
    WebViewCookieManager cookieManager,
    WebViewScripting scripting) : EventArgs
{
    public Uri Uri { get; } = uri;
    public bool IsSuccess { get; } = isSuccess;
    public string? Error { get; } = error;
    public WebViewCookieManager CookieManager { get; } = cookieManager;
    public WebViewScripting Scripting { get; } = scripting;
}

WebViewRequestedEventArgs.cs

using System;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewRequestedEventArgs : WebViewRequestingEventArgs
{
    internal WebViewRequestedEventArgs(
        WebViewRequestKind kind,
        Uri uri,
        string method,
        bool isMainFrame,
        WebViewRequestHeaders headers,
        WebViewCookieManager cookieManager,
        WebViewScripting scripting)
        : base(kind, uri, method, isMainFrame, headers, cookieManager, scripting)
    {
    }

    internal WebView? Target { get; private set; }

    public void OpenIn(WebView target) => Target = target ?? throw new ArgumentNullException(nameof(target));
}

WebViewRequestHeaders.cs

using System;
using System.Collections.Specialized;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewRequestHeaders
{
    private readonly NameValueCollection headers;

    public WebViewRequestHeaders()
        : this(new NameValueCollection(StringComparer.OrdinalIgnoreCase))
    {
    }

    internal WebViewRequestHeaders(NameValueCollection headers) => this.headers = headers;

    public NameValueCollection Raw => headers;

    public string? GetSingle(string name) => headers[name];

    public void SetSingle(string name, string value) => headers[name] = value;

    public void Remove(string name) => headers.Remove(name);
}

WebViewRequestingEventArgs.cs

using System;

namespace Shares.Avalonia.CustomControls.WebView;

public class WebViewRequestingEventArgs : EventArgs
{
    internal WebViewRequestingEventArgs(
        WebViewRequestKind kind,
        Uri uri,
        string method,
        bool isMainFrame,
        WebViewRequestHeaders headers,
        WebViewCookieManager cookieManager,
        WebViewScripting scripting)
    {
        Kind = kind;
        Uri = uri;
        Method = method;
        IsMainFrame = isMainFrame;
        Headers = headers;
        CookieManager = cookieManager;
        Scripting = scripting;
    }

    public WebViewRequestKind Kind { get; }
    public Uri Uri { get; }
    public string Method { get; }
    public bool IsMainFrame { get; }
    public WebViewRequestHeaders Headers { get; }
    public WebViewCookieManager CookieManager { get; }
    public WebViewScripting Scripting { get; }

    public bool Cancel { get; set; }
}

WebViewRequestKind.cs

namespace Shares.Avalonia.CustomControls.WebView;

public enum WebViewRequestKind
{
    Navigation,
    Resource,
    Popup
}

WebViewScripting.cs

using System.Threading.Tasks;
using Xilium.CefGlue.Avalonia;

namespace Shares.Avalonia.CustomControls.WebView;

public sealed class WebViewScripting
{
    private readonly AvaloniaCefBrowser browser;

    internal WebViewScripting(AvaloniaCefBrowser browser) => this.browser = browser;

    public void Execute(string script) => browser.ExecuteJavaScript(script);

    public Task<T> Evaluate<T>(string script) => browser.EvaluateJavaScript<T>(script);
}

 

posted on 2026-03-24 14:12  dalgleish  阅读(9)  评论(0)    收藏  举报