Files
better-genshin-impact/BetterGenshinImpact/View/Controls/Webview/WebpagePanel.cs
辉鸭蛋 6f87a0c4d0 脚本仓库V2 (#1707)
* feat: add custom drawer control and integrate it into the UI

* 更新仓库UI

* feat: implement Git-based repository update mechanism and improve error handling

* feat: add reset repository functionality with confirmation dialog

* 修改打开队伍配置界面的重试次数和日志

* feat: add drawer open/close events and improve drawer closing logic

* feat: enhance WebpagePanel navigation handling and improve initialization logic

* feat: add drawer opened event handling and improve navigation completion logic

* feat: implement dynamic height adjustment for WebpagePanel using Grid container

* feat: update drawer dimensions and apply dynamic sizing based on position

* feat: add CustomDrawer component and integrate with MapPathingViewModel for enhanced navigation

* feat: integrate WebView2 for Markdown file navigation in MapPathingViewModel
2025-06-17 03:13:56 +08:00

237 lines
7.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.ViewModel.Pages;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.AccessControl;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using BetterGenshinImpact.Helpers;
namespace BetterGenshinImpact.View.Controls.Webview;
public class WebpagePanel : UserControl
{
private Uri _currentUri = null!;
private WebView2 _webView = null!;
private bool _initialized = false;
public WebView2 WebView => _webView;
public string? DownloadFolderPath { get; set; }
public Action? OnWebViewInitializedAction { get; set; }
public Action<CoreWebView2NavigationCompletedEventArgs>? OnNavigationCompletedAction { get; set; }
public WebpagePanel()
{
if (!IsWebView2Available())
{
Content = CreateDownloadButton();
}
else
{
EnsureWebView2DataFolder();
_webView = new WebView2()
{
CreationProperties = new CoreWebView2CreationProperties
{
UserDataFolder = Path.Combine(new FileInfo(Environment.ProcessPath!).DirectoryName!, @"WebView2Data\\"),
// TODO: change the theme from `md2html.html` to fit it firstly.
// AdditionalBrowserArguments = "--enable-features=WebContentsForceDark"
}
};
_webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
_webView.NavigationStarting += NavigationStarting_CancelNavigation;
_webView.NavigationCompleted += WebView_NavigationCompleted;
Content = _webView;
}
}
// public WebpagePanel(WebView2 webView2)
// {
// if (!IsWebView2Available())
// {
// Content = CreateDownloadButton();
// }
// else
// {
// EnsureWebView2DataFolder();
// _webView = webView2;
// webView2.CreationProperties = new CoreWebView2CreationProperties
// {
// UserDataFolder = Path.Combine(new FileInfo(Environment.ProcessPath!).DirectoryName!, @"WebView2Data\\"),
// };
// webView2.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
// webView2.NavigationStarting += NavigationStarting_CancelNavigation;
// Content = webView2;
// }
// }
private void WebView_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
{
// 调用外部设置的导航完成 Action
OnNavigationCompletedAction?.Invoke(e);
}
private void WebView_CoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
{
if (e.IsSuccess)
{
_initialized = true;
if (!string.IsNullOrEmpty(DownloadFolderPath))
{
WebView.CoreWebView2.Profile.DefaultDownloadFolderPath = DownloadFolderPath;
}
// 调用外部设置的 Action
OnWebViewInitializedAction?.Invoke();
}
else
{
_ = e.InitializationException;
}
}
public static bool IsWebView2Available()
{
try
{
return !string.IsNullOrEmpty(CoreWebView2Environment.GetAvailableBrowserVersionString());
}
catch (Exception)
{
return false;
}
}
public static Uri FilePathToFileUrl(string filePath)
{
var uri = new StringBuilder();
foreach (var v in filePath)
if (v >= 'a' && v <= 'z' || v >= 'A' && v <= 'Z' || v >= '0' && v <= '9' ||
v == '+' || v == '/' || v == ':' || v == '.' || v == '-' || v == '_' || v == '~' ||
v > '\x80')
uri.Append(v);
else if (v == Path.DirectorySeparatorChar || v == Path.AltDirectorySeparatorChar)
uri.Append('/');
else
uri.Append($"%{(int)v:X2}");
if (uri.Length >= 2 && uri[0] == '/' && uri[1] == '/') // UNC path
uri.Insert(0, "file:");
else
uri.Insert(0, "file:///");
try
{
return new Uri(uri.ToString());
}
catch
{
return null!;
}
}
public void NavigateToFile(string path)
{
var uri = Path.IsPathRooted(path) ? FilePathToFileUrl(path) : new Uri(path);
NavigateToUri(uri);
}
public void NavigateToUri(Uri uri)
{
if (_webView == null)
return;
_webView.Source = uri;
_currentUri = _webView.Source;
}
public void NavigateToHtml(string htmlContentOrUrl)
{
_webView?.EnsureCoreWebView2Async()
.ContinueWith(_ => SpinWait.SpinUntil(() => _initialized))
.ContinueWith(_ => Dispatcher.Invoke(() =>
{
// 检查是否是URL以file:或http开头
if (htmlContentOrUrl.StartsWith("file:") || htmlContentOrUrl.StartsWith("http"))
{
// 如果是URL使用Navigate方法
_webView?.CoreWebView2?.Navigate(htmlContentOrUrl);
_currentUri = new Uri(htmlContentOrUrl);
}
else
{
// 如果是HTML内容使用NavigateToString方法
_webView?.NavigateToString(htmlContentOrUrl);
}
}));
}
public void NavigateToMd(string md, string backgroundColor = "#2b2b2b")
{
md = WebUtility.HtmlEncode(md);
string md2Html = ResourceHelper.GetString($"pack://application:,,,/Assets/Strings/md2html.html",
Encoding.UTF8);
var html = md2Html.Replace("{{content}}", md).Replace("#202020", backgroundColor);
NavigateToHtml(html);
}
private void NavigationStarting_CancelNavigation(object? sender, CoreWebView2NavigationStartingEventArgs e)
{
if (e.Uri.StartsWith("data:")) // when using NavigateToString
return;
// 允许file:和http:开头的URL导航用于大型HTML内容
if (e.Uri.StartsWith("file:") || e.Uri.StartsWith("http:") || e.Uri.StartsWith("https:"))
{
if (_currentUri != null && e.Uri == _currentUri.ToString())
return;
}
var newUri = new Uri(e.Uri);
if (newUri != _currentUri) e.Cancel = true;
}
public void Dispose()
{
_webView?.Dispose();
_webView = null!;
}
private Button CreateDownloadButton()
{
var button = new Button
{
Content = "查看需要安装 Microsoft Edge WebView2 点击这里开始下载",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Padding = new Thickness(20, 6, 20, 6)
};
button.Click += (sender, e) => Process.Start("https://go.microsoft.com/fwlink/p/?LinkId=2124703");
return button;
}
private void EnsureWebView2DataFolder()
{
try
{
string folder = Path.Combine(new FileInfo(Environment.ProcessPath!).DirectoryName!, @"WebView2Data\\");
Directory.CreateDirectory(folder);
DirectoryInfo info = new DirectoryInfo(folder);
DirectorySecurity access = info.GetAccessControl();
access.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
info.SetAccessControl(access);
}
catch { }
}
}