From 03b2b98d0e090d67eef84f4248bbecbe1f779989 Mon Sep 17 00:00:00 2001 From: Sirius Date: Wed, 18 Sep 2024 18:51:00 +0800 Subject: [PATCH 1/6] add winform browser --- MWPFCore/BrowserUserControl.xaml | 25 ++ MWPFCore/BrowserUserControl.xaml.cs | 51 +++ MWebBrowser.sln | 42 ++- MWebBrowser/App.xaml.cs | 2 +- MWebBrowser/AssemblyInfo.cs | 1 - MWebBrowser/Code/Configure/ConfigEntity.cs | 7 + MWebBrowser/Code/Configure/ConfigHelper.cs | 47 +++ MWebBrowser/Code/Configure/KnownFolder.cs | 23 ++ .../Code/CustomCef/CustomDownloadHandler.cs | 45 +++ .../Code/CustomCef/CustomLifeSpanHandler.cs | 39 +++ .../Code/CustomCef/CustomRequestHandler.cs | 79 +++++ .../Code/CustomCef/CustomWebBrowser.cs | 76 ++++ MWebBrowser/Code/Helpers/F11Helper.cs | 35 +- MWebBrowser/MWebBrowser.csproj | 18 +- MWebBrowser/MainWindow.xaml.cs | 13 +- .../View/Download/DownloadShowAllUc.xaml.cs | 4 +- .../View/Download/DownloadToolUc.xaml.cs | 10 +- MWebBrowser/View/F11Window.xaml.cs | 9 - .../View/Favorites/FavoritesBarUc.xaml.cs | 4 +- .../View/Favorites/FavoritesMenuUc.xaml.cs | 7 +- .../View/History/HistoryItemUc.xaml.cs | 8 +- MWebBrowser/View/Setting/SettingUc.xaml | 40 +-- MWebBrowser/View/Setting/SettingUc.xaml.cs | 7 +- MWebBrowser/View/WebMenuUc.xaml.cs | 6 +- MWebBrowser/View/WebTabControlUc.xaml.cs | 328 +++++++++++++----- MWebBrowser/View/WebTabItemUc.xaml | 10 +- MWebBrowser/View/WebTabItemUc.xaml.cs | 115 +++--- MWebBrowser/ViewModel/WebTabItemViewModel.cs | 8 +- MWinFormsBrowser/App.xaml | 12 + MWinFormsBrowser/App.xaml.cs | 16 + MWinFormsBrowser/AssemblyInfo.cs | 11 + .../Code/CefWebOperate/CefWebSearch.cs | 64 ++++ .../Code/CefWebOperate/CefWebZoom.cs | 179 ++++++++++ MWinFormsBrowser/Code/GlobalControl.cs | 13 + .../Code/Helpers/DesignModeHelper.cs | 12 + .../Code/Helpers/DispatcherHelper.cs | 18 + MWinFormsBrowser/Code/Helpers/F11Helper.cs | 52 +++ MWinFormsBrowser/Code/Helpers/ImageHelper.cs | 50 +++ MWinFormsBrowser/Code/Logger.cs | 51 +++ MWinFormsBrowser/Icon.ico | Bin 0 -> 165662 bytes MWinFormsBrowser/MWinFormsBrowser.csproj | 57 +++ MWinFormsBrowser/MainWindow.xaml | 16 + MWinFormsBrowser/MainWindow.xaml.cs | 51 +++ MWinFormsBrowser/TestUC.xaml | 31 ++ MWinFormsBrowser/TestUC.xaml.cs | 26 ++ .../View/Download/DownloadShowAllItemUc.xaml | 47 +++ .../Download/DownloadShowAllItemUc.xaml.cs | 22 ++ .../View/Download/DownloadShowAllUc.xaml | 64 ++++ .../View/Download/DownloadShowAllUc.xaml.cs | 75 ++++ .../View/Download/DownloadToolItemUc.xaml | 37 ++ .../View/Download/DownloadToolItemUc.xaml.cs | 20 ++ .../View/Download/DownloadToolUc.xaml | 52 +++ .../View/Download/DownloadToolUc.xaml.cs | 110 ++++++ MWinFormsBrowser/View/F11Window.xaml | 13 + MWinFormsBrowser/View/F11Window.xaml.cs | 24 ++ .../View/Favorites/FavoritesBarUc.xaml | 52 +++ .../View/Favorites/FavoritesBarUc.xaml.cs | 262 ++++++++++++++ .../View/Favorites/FavoritesMenuUc.xaml | 59 ++++ .../View/Favorites/FavoritesMenuUc.xaml.cs | 313 +++++++++++++++++ .../View/History/HistoryItemUc.xaml | 30 ++ .../View/History/HistoryItemUc.xaml.cs | 64 ++++ MWinFormsBrowser/View/History/HistoryUc.xaml | 42 +++ .../View/History/HistoryUc.xaml.cs | 49 +++ .../View/Setting/Person/PersonMenuUc.xaml | 52 +++ .../View/Setting/Person/PersonMenuUc.xaml.cs | 30 ++ .../Setting/SearchEngine/SearchEngineUc.xaml | 16 + .../SearchEngine/SearchEngineUc.xaml.cs | 19 + MWinFormsBrowser/View/Setting/SettingUc.xaml | 57 +++ .../View/Setting/SettingUc.xaml.cs | 20 ++ MWinFormsBrowser/View/WebMenuUc.xaml | 44 +++ MWinFormsBrowser/View/WebMenuUc.xaml.cs | 57 +++ MWinFormsBrowser/View/WebTabControlUc.xaml | 48 +++ MWinFormsBrowser/View/WebTabControlUc.xaml.cs | 301 ++++++++++++++++ MWinFormsBrowser/View/WebTabItemUc.xaml | 17 + MWinFormsBrowser/View/WebTabItemUc.xaml.cs | 139 ++++++++ MWinFormsBrowser/ViewModel/BaseViewModel.cs | 19 + .../Download/DownloadShowAllItemViewModel.cs | 17 + .../Download/DownloadToolItemViewModel.cs | 35 ++ .../ViewModel/History/HistoryItemViewModel.cs | 139 ++++++++ .../ViewModel/History/HistoryViewModel.cs | 114 ++++++ .../SearchEngine/SearchEngineViewModel.cs | 56 +++ .../ViewModel/Setting/SettingViewModel.cs | 82 +++++ .../ViewModel/WebTabControlViewModel.cs | 25 ++ .../ViewModel/WebTabItemViewModel.cs | 23 ++ MWinFormsBrowser/log4net.config | 29 ++ 85 files changed, 4090 insertions(+), 302 deletions(-) create mode 100644 MWPFCore/BrowserUserControl.xaml create mode 100644 MWPFCore/BrowserUserControl.xaml.cs create mode 100644 MWebBrowser/Code/Configure/ConfigEntity.cs create mode 100644 MWebBrowser/Code/Configure/ConfigHelper.cs create mode 100644 MWebBrowser/Code/Configure/KnownFolder.cs create mode 100644 MWebBrowser/Code/CustomCef/CustomDownloadHandler.cs create mode 100644 MWebBrowser/Code/CustomCef/CustomLifeSpanHandler.cs create mode 100644 MWebBrowser/Code/CustomCef/CustomRequestHandler.cs create mode 100644 MWebBrowser/Code/CustomCef/CustomWebBrowser.cs create mode 100644 MWinFormsBrowser/App.xaml create mode 100644 MWinFormsBrowser/App.xaml.cs create mode 100644 MWinFormsBrowser/AssemblyInfo.cs create mode 100644 MWinFormsBrowser/Code/CefWebOperate/CefWebSearch.cs create mode 100644 MWinFormsBrowser/Code/CefWebOperate/CefWebZoom.cs create mode 100644 MWinFormsBrowser/Code/GlobalControl.cs create mode 100644 MWinFormsBrowser/Code/Helpers/DesignModeHelper.cs create mode 100644 MWinFormsBrowser/Code/Helpers/DispatcherHelper.cs create mode 100644 MWinFormsBrowser/Code/Helpers/F11Helper.cs create mode 100644 MWinFormsBrowser/Code/Helpers/ImageHelper.cs create mode 100644 MWinFormsBrowser/Code/Logger.cs create mode 100644 MWinFormsBrowser/Icon.ico create mode 100644 MWinFormsBrowser/MWinFormsBrowser.csproj create mode 100644 MWinFormsBrowser/MainWindow.xaml create mode 100644 MWinFormsBrowser/MainWindow.xaml.cs create mode 100644 MWinFormsBrowser/TestUC.xaml create mode 100644 MWinFormsBrowser/TestUC.xaml.cs create mode 100644 MWinFormsBrowser/View/Download/DownloadShowAllItemUc.xaml create mode 100644 MWinFormsBrowser/View/Download/DownloadShowAllItemUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Download/DownloadShowAllUc.xaml create mode 100644 MWinFormsBrowser/View/Download/DownloadShowAllUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Download/DownloadToolItemUc.xaml create mode 100644 MWinFormsBrowser/View/Download/DownloadToolItemUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Download/DownloadToolUc.xaml create mode 100644 MWinFormsBrowser/View/Download/DownloadToolUc.xaml.cs create mode 100644 MWinFormsBrowser/View/F11Window.xaml create mode 100644 MWinFormsBrowser/View/F11Window.xaml.cs create mode 100644 MWinFormsBrowser/View/Favorites/FavoritesBarUc.xaml create mode 100644 MWinFormsBrowser/View/Favorites/FavoritesBarUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Favorites/FavoritesMenuUc.xaml create mode 100644 MWinFormsBrowser/View/Favorites/FavoritesMenuUc.xaml.cs create mode 100644 MWinFormsBrowser/View/History/HistoryItemUc.xaml create mode 100644 MWinFormsBrowser/View/History/HistoryItemUc.xaml.cs create mode 100644 MWinFormsBrowser/View/History/HistoryUc.xaml create mode 100644 MWinFormsBrowser/View/History/HistoryUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Setting/Person/PersonMenuUc.xaml create mode 100644 MWinFormsBrowser/View/Setting/Person/PersonMenuUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Setting/SearchEngine/SearchEngineUc.xaml create mode 100644 MWinFormsBrowser/View/Setting/SearchEngine/SearchEngineUc.xaml.cs create mode 100644 MWinFormsBrowser/View/Setting/SettingUc.xaml create mode 100644 MWinFormsBrowser/View/Setting/SettingUc.xaml.cs create mode 100644 MWinFormsBrowser/View/WebMenuUc.xaml create mode 100644 MWinFormsBrowser/View/WebMenuUc.xaml.cs create mode 100644 MWinFormsBrowser/View/WebTabControlUc.xaml create mode 100644 MWinFormsBrowser/View/WebTabControlUc.xaml.cs create mode 100644 MWinFormsBrowser/View/WebTabItemUc.xaml create mode 100644 MWinFormsBrowser/View/WebTabItemUc.xaml.cs create mode 100644 MWinFormsBrowser/ViewModel/BaseViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/Download/DownloadShowAllItemViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/Download/DownloadToolItemViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/History/HistoryItemViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/History/HistoryViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/Setting/SearchEngine/SearchEngineViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/Setting/SettingViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/WebTabControlViewModel.cs create mode 100644 MWinFormsBrowser/ViewModel/WebTabItemViewModel.cs create mode 100644 MWinFormsBrowser/log4net.config diff --git a/MWPFCore/BrowserUserControl.xaml b/MWPFCore/BrowserUserControl.xaml new file mode 100644 index 0000000..6141baf --- /dev/null +++ b/MWPFCore/BrowserUserControl.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/MWPFCore/BrowserUserControl.xaml.cs b/MWPFCore/BrowserUserControl.xaml.cs new file mode 100644 index 0000000..89e9173 --- /dev/null +++ b/MWPFCore/BrowserUserControl.xaml.cs @@ -0,0 +1,51 @@ +using CefSharp; +using MWPFCore.Code.CustomCef; +using System.Windows; +using System.Windows.Controls; + +namespace MWPFCore +{ + /// + /// Interaction logic for BrowserUserControl.xaml + /// + public partial class BrowserUserControl : UserControl + { + public CustomWebBrowser CefWebBrowser; + public BrowserUserControl() + { + InitializeComponent(); + InitData(); + } + + private void InitData() + { + CefWebBrowser = new CustomWebBrowser(); + webBrower.Children.Add(CefWebBrowser); + } + + public void ShowDevToolsDocked() + { + if (devToolsGrid.Visibility == Visibility.Collapsed) + { + devToolsGrid.Visibility = Visibility.Visible; + } + + CefWebBrowser.GetBrowserHost().ShowDevTools(); + + + // 获取开发者工具的 WebView,wpf源码没提供,暂放弃 + CefWebBrowser.ShowDevTools(); + if (devToolsGrid.Children.Count == 0) + { + // 将开发者工具嵌入到指定的 Grid 中 + } + } + + public void CloseDevToolsDocked() + { + devToolsGrid.Children.Clear(); + devToolsGrid.Visibility = Visibility.Collapsed; // 隐藏开发者工具 + } + } + +} diff --git a/MWebBrowser.sln b/MWebBrowser.sln index 26ce5e6..c94db66 100644 --- a/MWebBrowser.sln +++ b/MWebBrowser.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWebBrowser", "MWebBrowser\MWebBrowser.csproj", "{7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cys_Resource", "Cys_Resource\Cys_Resource.csproj", "{BFA86333-1D51-4611-B199-BB9059047012}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cys_CustomControls", "Cys_CustomControls\Cys_CustomControls.csproj", "{C280D126-6E40-4BB6-83A0-8047CB4F8DC4}" @@ -23,6 +21,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWPFCore", "MWPFCore\MWPFCo EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cys", "Cys", "{D01C5D35-0DBB-4B5C-994F-C4A132A627FD}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWinFormsBrowser", "MWinFormsBrowser\MWinFormsBrowser.csproj", "{FF605711-EA53-4987-9BA9-4EA45BC90A1F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWebBrowser", "MWebBrowser\MWebBrowser.csproj", "{488A48CC-5570-4733-BCD6-50D1CC9C4B6A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,18 +35,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|x64.ActiveCfg = Debug|x86 - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|x64.Build.0 = Debug|x86 - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|x86.ActiveCfg = Debug|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Debug|x86.Build.0 = Debug|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|Any CPU.Build.0 = Release|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|x64.ActiveCfg = Release|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|x64.Build.0 = Release|Any CPU - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|x86.ActiveCfg = Release|x86 - {7FF6E8EE-4310-43AC-8C99-DBDCDC33B57B}.Release|x86.Build.0 = Release|x86 {BFA86333-1D51-4611-B199-BB9059047012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BFA86333-1D51-4611-B199-BB9059047012}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFA86333-1D51-4611-B199-BB9059047012}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -141,6 +131,30 @@ Global {8E54DF10-5C9D-44B3-A0E6-F30C2268CC24}.Release|x64.Build.0 = Release|Any CPU {8E54DF10-5C9D-44B3-A0E6-F30C2268CC24}.Release|x86.ActiveCfg = Release|Any CPU {8E54DF10-5C9D-44B3-A0E6-F30C2268CC24}.Release|x86.Build.0 = Release|Any CPU + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|x64.ActiveCfg = Debug|x64 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|x64.Build.0 = Debug|x64 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|x86.ActiveCfg = Debug|x86 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Debug|x86.Build.0 = Debug|x86 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|Any CPU.Build.0 = Release|Any CPU + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|x64.ActiveCfg = Release|x64 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|x64.Build.0 = Release|x64 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|x86.ActiveCfg = Release|x86 + {FF605711-EA53-4987-9BA9-4EA45BC90A1F}.Release|x86.Build.0 = Release|x86 + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|x64.ActiveCfg = Debug|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|x64.Build.0 = Debug|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|x86.ActiveCfg = Debug|x86 + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Debug|x86.Build.0 = Debug|x86 + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|Any CPU.Build.0 = Release|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|x64.ActiveCfg = Release|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|x64.Build.0 = Release|Any CPU + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|x86.ActiveCfg = Release|x86 + {488A48CC-5570-4733-BCD6-50D1CC9C4B6A}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MWebBrowser/App.xaml.cs b/MWebBrowser/App.xaml.cs index 86725e2..c698165 100644 --- a/MWebBrowser/App.xaml.cs +++ b/MWebBrowser/App.xaml.cs @@ -1,4 +1,4 @@ -using MWinFormsCore; +using MWPFCore; using System.Windows; namespace MWebBrowser diff --git a/MWebBrowser/AssemblyInfo.cs b/MWebBrowser/AssemblyInfo.cs index 01c8003..8b5504e 100644 --- a/MWebBrowser/AssemblyInfo.cs +++ b/MWebBrowser/AssemblyInfo.cs @@ -8,4 +8,3 @@ using System.Windows; //(used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )] -[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)] \ No newline at end of file diff --git a/MWebBrowser/Code/Configure/ConfigEntity.cs b/MWebBrowser/Code/Configure/ConfigEntity.cs new file mode 100644 index 0000000..57b36e5 --- /dev/null +++ b/MWebBrowser/Code/Configure/ConfigEntity.cs @@ -0,0 +1,7 @@ +namespace MWebBrowser.Code.Configure +{ + public class ConfigEntity + { + public string DownLoadPath { get; set; } + } +} diff --git a/MWebBrowser/Code/Configure/ConfigHelper.cs b/MWebBrowser/Code/Configure/ConfigHelper.cs new file mode 100644 index 0000000..fcc66b5 --- /dev/null +++ b/MWebBrowser/Code/Configure/ConfigHelper.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; + +namespace MWebBrowser.Code.Configure +{ + public static class ConfigHelper + { + public static ConfigEntity Config { get; private set; } + + public static void LoadLocalConfig() + { + ConfigEntity config = null; + if (string.IsNullOrEmpty(AppDomain.CurrentDomain.BaseDirectory)) + { + config = new ConfigEntity(); + } + else + { + string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); + if (File.Exists(path)) + { + try + { + using StreamReader streamReader = new StreamReader(path, System.Text.Encoding.UTF8); + string json = streamReader.ReadToEnd(); + config = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + } + catch + { + File.Delete(path); + } + } + config ??= new ConfigEntity(); + } + Config = config; + CheckConfig(); + } + + private static void CheckConfig() + { + if (string.IsNullOrEmpty(Config.DownLoadPath) || Directory.Exists(Config.DownLoadPath)) + { + Config.DownLoadPath = KnownFolderHelper.GetDownload(); + } + } + } +} diff --git a/MWebBrowser/Code/Configure/KnownFolder.cs b/MWebBrowser/Code/Configure/KnownFolder.cs new file mode 100644 index 0000000..2aef037 --- /dev/null +++ b/MWebBrowser/Code/Configure/KnownFolder.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.InteropServices; + +namespace MWebBrowser.Code.Configure +{ + public static class KnownFolder + { + public static readonly Guid Downloads = new Guid("374DE290-123F-4565-9164-39C4925E467B"); + } + + public static class KnownFolderHelper + { + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, + uint dwFlags, IntPtr hToken, out string pszPath); + + public static string GetDownload() + { + SHGetKnownFolderPath(KnownFolder.Downloads, 0, IntPtr.Zero, out var downloads); + return downloads; + } + } +} diff --git a/MWebBrowser/Code/CustomCef/CustomDownloadHandler.cs b/MWebBrowser/Code/CustomCef/CustomDownloadHandler.cs new file mode 100644 index 0000000..60c3f76 --- /dev/null +++ b/MWebBrowser/Code/CustomCef/CustomDownloadHandler.cs @@ -0,0 +1,45 @@ +using CefSharp; +using MWebBrowser.Code.Configure; +using System; + +namespace MWebBrowser.Code.CustomCef +{ + public class CustomDownloadHandler : IDownloadHandler + { + private readonly Action _downloadCallBackEvent;//第一个参数为true为update + + public CustomDownloadHandler(Action downloadCallBackEvent) + { + _downloadCallBackEvent = downloadCallBackEvent; + } + + public bool CanDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, string requestMethod) + { + return true; + } + + public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, + IBeforeDownloadCallback callback) + { + if (callback.IsDisposed) return; + _downloadCallBackEvent?.Invoke(false, downloadItem); + downloadItem.IsInProgress = true; + var path = GetDownloadFullPath(downloadItem.SuggestedFileName); + callback.Continue(path, false); + } + + + public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, + IDownloadItemCallback callback) + { + _downloadCallBackEvent?.Invoke(true, downloadItem); + } + + + private string GetDownloadFullPath(string suggestedFileName) + { + var configPath = ConfigHelper.Config.DownLoadPath.TrimEnd('\\') + "\\"; + return configPath + suggestedFileName; + } + } +} diff --git a/MWebBrowser/Code/CustomCef/CustomLifeSpanHandler.cs b/MWebBrowser/Code/CustomCef/CustomLifeSpanHandler.cs new file mode 100644 index 0000000..ede8648 --- /dev/null +++ b/MWebBrowser/Code/CustomCef/CustomLifeSpanHandler.cs @@ -0,0 +1,39 @@ +using CefSharp; +using System; + +namespace MWebBrowser.Code.CustomCef +{ + public class CustomLifeSpanHandler : ILifeSpanHandler + { + public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, + string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, + IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) + { + if (chromiumWebBrowser is CustomWebBrowser webBrowser) + { + //Cef.UIThreadTaskFactory.StartNew(() => + //{ + + //}); + webBrowser.OpenNewTab(targetUrl); + } + newBrowser = null; + return true; + } + + public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + + } + + public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + return false; + } + + public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + + } + } +} diff --git a/MWebBrowser/Code/CustomCef/CustomRequestHandler.cs b/MWebBrowser/Code/CustomCef/CustomRequestHandler.cs new file mode 100644 index 0000000..c571aa0 --- /dev/null +++ b/MWebBrowser/Code/CustomCef/CustomRequestHandler.cs @@ -0,0 +1,79 @@ +using CefSharp; +using MWebBrowser.Code.Helpers; +using System.Security.Cryptography.X509Certificates; + +namespace MWebBrowser.Code.CustomCef +{ + public class CustomRequestHandler: IRequestHandler + { + public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, + bool isRedirect) + { + return false; + } + + public void OnDocumentAvailableInMainFrame(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + + } + + public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, + WindowOpenDisposition targetDisposition, bool userGesture) + { + + DispatcherHelper.UIDispatcher.Invoke(() => + { + var s = chromiumWebBrowser.Address; + }); + return false; + } + + public IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, + IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling) + { + return null; + } + + public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, + int port, string realm, string scheme, IAuthCallback callback) + { + callback.Dispose(); + return false; + } + + public bool OnQuotaRequest(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, long newSize, + IRequestCallback callback) + { + callback.Dispose(); + return false; + } + + public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, + ISslInfo sslInfo, IRequestCallback callback) + { + return false; + } + + public bool OnSelectClientCertificate(IWebBrowser chromiumWebBrowser, IBrowser browser, bool isProxy, string host, int port, + X509Certificate2Collection certificates, ISelectClientCertificateCallback callback) + { + callback.Dispose(); + return false; + } + + public void OnPluginCrashed(IWebBrowser chromiumWebBrowser, IBrowser browser, string pluginPath) + { + + } + + public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + + } + + public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status) + { + + } + } +} diff --git a/MWebBrowser/Code/CustomCef/CustomWebBrowser.cs b/MWebBrowser/Code/CustomCef/CustomWebBrowser.cs new file mode 100644 index 0000000..0801053 --- /dev/null +++ b/MWebBrowser/Code/CustomCef/CustomWebBrowser.cs @@ -0,0 +1,76 @@ +using CefSharp; +using CefSharp.Wpf; +using Cys_Controls.Code; +using Cys_CustomControls.Controls; +using System; +using System.Windows.Input; + +namespace MWebBrowser.Code.CustomCef +{ + public class CustomWebBrowser: ChromiumWebBrowser + { + public Action DownloadCallBackEvent; + + public Action AfterLoadEvent; + public CustomWebBrowser() + { + this.LoadingStateChanged += CustomWebBrowser_LoadingStateChanged; + this.IsBrowserInitializedChanged += CustomWebBrowser_IsBrowserInitializedChanged; + } + + private void CustomWebBrowser_IsBrowserInitializedChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) + { + if (!this.IsBrowserInitialized) return; + //this.ShowDevTools(); + Cef.UIThreadTaskFactory.StartNew(() => + { + string error = ""; + var requestContext = this.GetBrowser().GetHost().RequestContext; + requestContext.SetPreference("profile.default_content_setting_values.plugins", 1, out error); + }); + } + + private void CustomWebBrowser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) + { + if (e.IsLoading) + return; + AfterLoadEvent?.Invoke(); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + this.LifeSpanHandler = new CustomLifeSpanHandler(); + this.RequestHandler = new CustomRequestHandler(); + this.DownloadHandler = new CustomDownloadHandler(DownloadCallBackEvent); + + //博客园友:【侠女多风尘】给出每个webBrowser单独缩放级别处理 + this.RequestContext = new RequestContext(); + } + + public void OpenNewTab(string url) + { + Dispatcher.Invoke(() => + { + var tabControl = ControlHelper.FindVisualParent(this); + tabControl?.TabItemAddCommand?.Execute(url); + }); + } + + protected override void OnPreviewTextInput(TextCompositionEventArgs e) + { + try + { + foreach (var character in e.Text) + { + // 字符重发 + this.GetBrowser().GetHost()?.SendKeyEvent((int)WM.CHAR, (int)character, 0); + } + } + catch (Exception ex) + { + } + e.Handled = true; + } + } +} diff --git a/MWebBrowser/Code/Helpers/F11Helper.cs b/MWebBrowser/Code/Helpers/F11Helper.cs index 02c5e7d..12c2afc 100644 --- a/MWebBrowser/Code/Helpers/F11Helper.cs +++ b/MWebBrowser/Code/Helpers/F11Helper.cs @@ -1,49 +1,42 @@ -using MWebBrowser.View; -using MWinFormsCore; +using MWebBrowser.Code.CustomCef; +using MWebBrowser.Code.Helpers; +using MWebBrowser.View; using System.Windows; -using System.Windows.Forms.Integration; +using System.Windows.Controls; -namespace MWebBrowser.Code.Helpers +namespace MWinFormsBrowser.Code.Helpers { public static class F11Helper { private static F11Window f11Window; - private static Rect originalBounds; - - public static void F11(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + public static void F11(Grid parent, CustomWebBrowser CefWebBrowser) { DispatcherHelper.UIDispatcher.Invoke(() => { if (f11Window != null) { - ExitFullscreen(browserUserControl, orgWebFormsHost); + ExitFullscreen(CefWebBrowser); + parent.Children.Add(CefWebBrowser); } else { - EnterFullscreen(browserUserControl, orgWebFormsHost); + parent.Children.Remove(CefWebBrowser); + EnterFullscreen(CefWebBrowser); } }); } - private static void EnterFullscreen(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + private static void EnterFullscreen(CustomWebBrowser CefWebBrowser) { - originalBounds = new Rect( - browserUserControl.CefWebBrowser.Margin.Left, - browserUserControl.CefWebBrowser.Margin.Top, - browserUserControl.CefWebBrowser.Width, - browserUserControl.CefWebBrowser.Height - ); f11Window = new F11Window(); - orgWebFormsHost.Child.Controls.Remove(browserUserControl); - f11Window.WebFormsHost.Child = browserUserControl; + f11Window.Parent.Children.Add(CefWebBrowser); f11Window.Show(); Application.Current.MainWindow.Hide(); } - private static void ExitFullscreen(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + private static void ExitFullscreen(CustomWebBrowser CefWebBrowser) { - f11Window.WebFormsHost.Child.Controls.Remove(browserUserControl); - orgWebFormsHost.Child = browserUserControl; + f11Window.Parent.Children.Remove(CefWebBrowser); Application.Current.MainWindow.Show(); f11Window.Close(); f11Window = null; diff --git a/MWebBrowser/MWebBrowser.csproj b/MWebBrowser/MWebBrowser.csproj index 2910a61..37b126f 100644 --- a/MWebBrowser/MWebBrowser.csproj +++ b/MWebBrowser/MWebBrowser.csproj @@ -2,13 +2,12 @@ WinExe - net8.0-windows + net8.0-windows true - true - AnyCPU;x86;x64 + AnyCPU true Icon.ico - $(SolutionDir)Output\$(Platform)\ + $(SolutionDir)Output\WPF\$(Platform)\ @@ -19,17 +18,17 @@ - - - + + + - + @@ -37,9 +36,6 @@ - - PreserveNewest - Always diff --git a/MWebBrowser/MainWindow.xaml.cs b/MWebBrowser/MainWindow.xaml.cs index b1ee165..d26b3d8 100644 --- a/MWebBrowser/MainWindow.xaml.cs +++ b/MWebBrowser/MainWindow.xaml.cs @@ -1,8 +1,8 @@ -using Cys_Common.Code.Configure; -using Cys_Common.Settings; +using Cys_Common.Settings; using Cys_CustomControls.Controls; using Cys_DataRepository; using Cys_Model.DataBase; +using MWebBrowser.Code.Configure; using MWebBrowser.Code.Helpers; namespace MWebBrowser @@ -19,17 +19,10 @@ namespace MWebBrowser ConfigHelper.LoadLocalConfig(); InitGlobalInfo(); this.Closing += MainWindow_Closing; - this.Loaded += MainWindow_Loaded; - } - - private void MainWindow_Loaded(object sender, System.Windows.RoutedEventArgs e) - { - MLogger.Info("Main Window Show Success!"); } private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - SaveGlobalInfo(); } @@ -38,14 +31,12 @@ namespace MWebBrowser DbSeed.InitData(); GlobalInfo.DownloadSetting = DataRepositoryServer.Instance.DownloadData.GetDownloadSetting(); GlobalInfo.FavoritesSetting = DataRepositoryServer.Instance.FavoritesData.GetFavoritesSetting(); - GlobalInfo.SearchEngineSetting = DataRepositoryServer.Instance.SearchEngineData.GetSearchEngineSetting(); } private void SaveGlobalInfo() { DataRepositoryServer.Instance.DownloadData.SaveDownloadSetting(); DataRepositoryServer.Instance.FavoritesData.SaveFavoritesSetting(); - DataRepositoryServer.Instance.SearchEngineData.SaveSearchEngineSetting(); } } } diff --git a/MWebBrowser/View/Download/DownloadShowAllUc.xaml.cs b/MWebBrowser/View/Download/DownloadShowAllUc.xaml.cs index 1ce0849..6173989 100644 --- a/MWebBrowser/View/Download/DownloadShowAllUc.xaml.cs +++ b/MWebBrowser/View/Download/DownloadShowAllUc.xaml.cs @@ -1,5 +1,5 @@ -using Cys_Common.Code.Configure; -using Cys_Common.Settings; +using Cys_Common.Settings; +using MWebBrowser.Code.Configure; using MWebBrowser.ViewModel; using System; using System.Diagnostics; diff --git a/MWebBrowser/View/Download/DownloadToolUc.xaml.cs b/MWebBrowser/View/Download/DownloadToolUc.xaml.cs index b3917fd..0af9049 100644 --- a/MWebBrowser/View/Download/DownloadToolUc.xaml.cs +++ b/MWebBrowser/View/Download/DownloadToolUc.xaml.cs @@ -1,14 +1,11 @@ using CefSharp; +using Cys_Common.Settings; using MWebBrowser.ViewModel; using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Animation; -using Cys_Common.Settings; -using MWebBrowser.Code.Helpers; -using Org.BouncyCastle.Asn1.Ocsp; -using Cys_Controls.Code; namespace MWebBrowser.View { @@ -55,6 +52,7 @@ namespace MWebBrowser.View this.Dispatcher.Invoke(new Action(() => { + //this.Visibility = Visibility.Visible; DisplayTool(); var item = new DownloadToolItemUc { DataContext = viewModel }; ItemsParent.Children.Insert(0, item); @@ -93,15 +91,11 @@ namespace MWebBrowser.View private void DisplayTool() { - var uc = ControlHelper.FindVisualChild(Application.Current.MainWindow); - uc.SetCurrentWebTabItemSize(true); _displayToolStoryboard.Begin(); } private void HideTool() { - var uc = ControlHelper.FindVisualChild(Application.Current.MainWindow); - uc.SetCurrentWebTabItemSize(false); _hideToolStoryboard.Begin(); } diff --git a/MWebBrowser/View/F11Window.xaml.cs b/MWebBrowser/View/F11Window.xaml.cs index 1aa6481..131eb8c 100644 --- a/MWebBrowser/View/F11Window.xaml.cs +++ b/MWebBrowser/View/F11Window.xaml.cs @@ -1,5 +1,4 @@ using System.Windows; -using System.Windows.Forms.Integration; namespace MWebBrowser.View { @@ -8,17 +7,9 @@ namespace MWebBrowser.View /// public partial class F11Window : Window { - public WindowsFormsHost WebFormsHost { get; } public F11Window() { InitializeComponent(); - WebFormsHost = new WindowsFormsHost(); - InitData(); - } - - private void InitData() - { - Parent.Children.Add(WebFormsHost); } } } diff --git a/MWebBrowser/View/Favorites/FavoritesBarUc.xaml.cs b/MWebBrowser/View/Favorites/FavoritesBarUc.xaml.cs index a6b8d15..ab28782 100644 --- a/MWebBrowser/View/Favorites/FavoritesBarUc.xaml.cs +++ b/MWebBrowser/View/Favorites/FavoritesBarUc.xaml.cs @@ -25,7 +25,7 @@ namespace MWebBrowser.View /// private MFavoritesItem _currentRightItem; public Func GetWebUrlEvent; - public Action OpenUrlCurrentEvent; + public Action OpenNewTabEvent; public FavoritesBarUc() { InitializeComponent(); @@ -132,7 +132,7 @@ namespace MWebBrowser.View if (item == null || item.Type == 1) return; if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == item.NodeId)) return; var treeNode = GlobalInfo.FavoritesSetting.FavoritesInfos.First(x => x.NodeId == item.NodeId); - OpenUrlCurrentEvent?.Invoke(treeNode.Url); + OpenNewTabEvent?.Invoke(treeNode.Url); } /// diff --git a/MWebBrowser/View/Favorites/FavoritesMenuUc.xaml.cs b/MWebBrowser/View/Favorites/FavoritesMenuUc.xaml.cs index d1a7881..522c26b 100644 --- a/MWebBrowser/View/Favorites/FavoritesMenuUc.xaml.cs +++ b/MWebBrowser/View/Favorites/FavoritesMenuUc.xaml.cs @@ -1,4 +1,5 @@ -using Cys_Common.Settings; +using Cys_Common; +using Cys_Common.Settings; using Cys_Controls.Code; using Cys_CustomControls.Controls; using Cys_Model; @@ -20,7 +21,7 @@ namespace MWebBrowser.View public partial class FavoritesMenuUc : UserControl { public Func GetWebUrlEvent; - public Action OpenUrlCurrentEvent; + public Action OpenNewTabEvent; public Action RefreshFavoritesBarEvent; /// @@ -284,7 +285,7 @@ namespace MWebBrowser.View if (item.IsEdit) return; if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == item.NodeId)) return; var treeNode = GlobalInfo.FavoritesSetting.FavoritesInfos.First(x => x.NodeId == item.NodeId); - OpenUrlCurrentEvent?.Invoke(treeNode.Url); + OpenNewTabEvent?.Invoke(treeNode.Url); } private void ReName_OnClick(object sender, RoutedEventArgs e) diff --git a/MWebBrowser/View/History/HistoryItemUc.xaml.cs b/MWebBrowser/View/History/HistoryItemUc.xaml.cs index 137b77c..c4b1116 100644 --- a/MWebBrowser/View/History/HistoryItemUc.xaml.cs +++ b/MWebBrowser/View/History/HistoryItemUc.xaml.cs @@ -40,13 +40,13 @@ namespace MWebBrowser.View.History { if (!(this.DataContext is HistoryItemViewModel viewModel)) return; try - { - ControlHelper.FindVisualChild(Application.Current.MainWindow).FavoritesPop.IsOpen = false; - ControlHelper.FindVisualChild(Application.Current.MainWindow).OpenUrl(viewModel.Url); + { + var uc = ControlHelper.FindVisualChild(Application.Current.MainWindow); + uc.TabItemAdd(viewModel.Url); } catch (Exception ex) { - MLogger.Info($"history mouse left button down exception:{ex}"); + } } diff --git a/MWebBrowser/View/Setting/SettingUc.xaml b/MWebBrowser/View/Setting/SettingUc.xaml index da46d04..0d189f8 100644 --- a/MWebBrowser/View/Setting/SettingUc.xaml +++ b/MWebBrowser/View/Setting/SettingUc.xaml @@ -4,17 +4,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:Cys_CustomControls.Controls;assembly=Cys_CustomControls" - xmlns:local="clr-namespace:Cys_CustomControls.Code;assembly=Cys_CustomControls" mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="1000" Foreground="{DynamicResource WebBrowserBrushes.DefaultForeground}" Background="{DynamicResource WebBrowserBrushes.DefaultBackground}"> - - - @@ -26,22 +19,21 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -50,7 +42,7 @@ - + diff --git a/MWebBrowser/View/Setting/SettingUc.xaml.cs b/MWebBrowser/View/Setting/SettingUc.xaml.cs index cec5eec..7155ed8 100644 --- a/MWebBrowser/View/Setting/SettingUc.xaml.cs +++ b/MWebBrowser/View/Setting/SettingUc.xaml.cs @@ -1,6 +1,4 @@ -using MWebBrowser.ViewModel; -using MWebBrowser.ViewModel.Setting; -using System.Windows.Controls; +using System.Windows.Controls; namespace MWebBrowser.View { @@ -9,12 +7,9 @@ namespace MWebBrowser.View /// public partial class SettingUc : UserControl { - private readonly SettingViewModel settingViewModel; public SettingUc() { InitializeComponent(); - settingViewModel = new SettingViewModel(); - this.DataContext = settingViewModel; } } } diff --git a/MWebBrowser/View/WebMenuUc.xaml.cs b/MWebBrowser/View/WebMenuUc.xaml.cs index 84d294d..96112c2 100644 --- a/MWebBrowser/View/WebMenuUc.xaml.cs +++ b/MWebBrowser/View/WebMenuUc.xaml.cs @@ -3,7 +3,6 @@ using System.Windows; using System.Windows.Controls; using Cys_Controls.Code; using Cys_CustomControls.Controls; -using MWebBrowser.Code.Helpers; namespace MWebBrowser.View { @@ -48,10 +47,7 @@ namespace MWebBrowser.View public void ZoomCallBack(string zoomRatio) { - DispatcherHelper.UIDispatcher.Invoke(() => - { - ZoomMenuItem.ZoomRatio = zoomRatio; - }); + ZoomMenuItem.ZoomRatio = zoomRatio; } } } diff --git a/MWebBrowser/View/WebTabControlUc.xaml.cs b/MWebBrowser/View/WebTabControlUc.xaml.cs index c343156..261e3d6 100644 --- a/MWebBrowser/View/WebTabControlUc.xaml.cs +++ b/MWebBrowser/View/WebTabControlUc.xaml.cs @@ -1,14 +1,15 @@ using CefSharp; +using CefSharp.DevTools.WebAudio; using Cys_Controls.Code; using Cys_CustomControls.Controls; using Cys_Model.Tables; using Cys_Resource.Code; using Cys_Services; using MWebBrowser.Code; -using MWebBrowser.Code.CefWebOperate; using MWebBrowser.Code.Helpers; using MWebBrowser.ViewModel; using System; +using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -22,42 +23,47 @@ namespace MWebBrowser.View /// public partial class WebTabControlUc : UserControl { - private readonly WebTabControlViewModel viewModel; - private WebTabItemUc currentWebTabItem; - private HistoryServices historyServices; - private CefWebZoom cefWebZoom; - private CefWebSearch cefWebSearch; + private readonly WebTabControlViewModel _viewModel; + private WebTabItemUc _currentWebTabItem; + private readonly System.Timers.Timer _zoomToolTimer = new System.Timers.Timer(1000); + private int _zoomWaitingCount = -1; + + private HistoryServices _historyServices; public WebTabControlUc() { InitializeComponent(); InitWebTabControl(); - historyServices = new HistoryServices(); - viewModel = new WebTabControlViewModel(); - this.DataContext = viewModel; + _historyServices = new HistoryServices(); + _viewModel = new WebTabControlViewModel(); + this.DataContext = _viewModel; this.Loaded += MWebBrowserUc_Loaded; WebTabControl.SelectionChanged += WebTabControl_SelectionChanged; - FavoritesMenu.GetWebUrlEvent += () => viewModel; - FavoritesMenu.OpenUrlCurrentEvent += OpenUrlByCurrentTab; + FavoritesMenu.GetWebUrlEvent += () => _viewModel; + FavoritesMenu.OpenNewTabEvent += TabItemAdd; FavoritesMenu.RefreshFavoritesBarEvent += FavoritesBar.RefreshFavoritesBar; - FavoritesBar.GetWebUrlEvent += () => viewModel; - FavoritesBar.OpenUrlCurrentEvent += OpenUrlByCurrentTab; + FavoritesBar.GetWebUrlEvent += () => _viewModel; + FavoritesBar.OpenNewTabEvent += TabItemAdd; } - public void SetCurrentWebTabItemSize(bool setHeight) - { - currentWebTabItem.RowBottom.Height = new GridLength(setHeight ? 40 : 0); - } private void MWebBrowserUc_Loaded(object sender, RoutedEventArgs e) { if (this.IsInDesignMode()) return; InitCommand(); InitData(); - OpenUrl("https://www.cnblogs.com/mchao/collections/12168"); + InitSearchCommand(); + InitWebMenu(); + TabItemAdd("http://www.baidu.com"); } #region InitData + private void InitWebMenu() + { + WebMenu.ZoomInEvent += ZoomIn; + WebMenu.ZoomOutEvent += ZoomOut; + WebMenu.ExecuteMenuEvent += ExecuteMenuFunction; + } private void InitWebTabControl() { WebTabControl.CloseTabEvent += () => @@ -75,16 +81,14 @@ namespace MWebBrowser.View { WebTabControl.PartHeaderParentGrid.MouseLeftButtonDown += mw.HeaderClickOrDragMove; } - cefWebZoom = new CefWebZoom(WebMenu, viewModel, SearchText); - cefWebSearch = new CefWebSearch(viewModel); + DownloadTool.ShowDownloadTabEvent += ShowDownloadTab; - WebMenu.ExecuteMenuEvent += ExecuteMenuFunction; } private void InitCommand() { - WebTabControl.TabItemAddCommand = new BaseCommand(OpenDefault); - WebTabControl.TabItemRemoveCommand = new BaseCommand(RemoveCurrentItem); + WebTabControl.TabItemAddCommand = new BaseCommand(TabItemAdd); + WebTabControl.TabItemRemoveCommand = new BaseCommand(RemoveItemCommand); } #endregion @@ -103,8 +107,6 @@ namespace MWebBrowser.View } #endregion - private void Print() => currentWebTabItem.CefWebBrowser.Print(); - #region SettingTool private void ShowSettingTab() @@ -134,7 +136,6 @@ namespace MWebBrowser.View } #endregion - #region TabControl /// @@ -144,50 +145,35 @@ namespace MWebBrowser.View /// private void WebTabControlUc_OnPreviewKeyDown(object sender, KeyEventArgs e) { + if (e.Key != Key.F5) return; if (!(WebTabControl.SelectedItem is TabItem item)) return; if (!(item.Content is WebTabItemUc webTabItemUc)) return; - int virtualKey = KeyInterop.VirtualKeyFromKey(e.Key); - webTabItemUc.CefWebBrowser_PreviewKeyDown(virtualKey); - } - - public void OpenUrlByCurrentTab(object obj) - { - currentWebTabItem.Load(obj?.ToString()); - } - - public void OpenUrl(object obj) - { - AddNewTabItem(obj, false); + webTabItemUc.CefWebBrowser?.Reload(); } - public void OpenDefault(object obj) - { - AddNewTabItem(obj, true); - } /// /// 添加新的TabItem /// /// - private void AddNewTabItem(object obj, bool firstNew) + public void TabItemAdd(object obj) { try { - DispatcherHelper.UIDispatcher.Invoke(() => - { - var uc = new WebTabItemUc { ViewModel = { FirstNew = firstNew, CurrentUrl = firstNew ? null : obj?.ToString() } }; - uc.SetCurrentEvent += SetCurrentSelectedInfo; - uc.CefWebBrowser.AfterLoadEvent += AfterLoad; - #region TabItem - - var item = new TabItem { Content = uc }; - var titleBind = new Binding { Source = uc.DataContext, Path = new PropertyPath("Title") }; - item.SetBinding(HeaderedContentControl.HeaderProperty, titleBind); - var faviconBind = new Binding { Source = uc.DataContext, Path = new PropertyPath("Favicon") }; - item.SetBinding(AttachedPropertyClass.ImageSourceProperty, faviconBind); - WebTabControl.Items.Add(item); - WebTabControl.SelectedItem = item; - WebTabControl.SetHeaderPanelWidth(); - }); + var uc = new WebTabItemUc { ViewModel = { CurrentUrl = obj?.ToString() } }; + uc.SetCurrentEvent += SetCurrentSelectedInfo; + uc.CefWebBrowser.DownloadCallBackEvent += DownloadTool.DownloadFile; + uc.CefWebBrowser.AfterLoadEvent += AfterLoad; + uc.WebMouseWheelEvent += WebMouseWheel; + #region TabItem + + var item = new TabItem { Content = uc }; + var titleBind = new Binding { Source = uc.DataContext, Path = new PropertyPath("Title") }; + item.SetBinding(HeaderedContentControl.HeaderProperty, titleBind); + var faviconBind = new Binding { Source = uc.DataContext, Path = new PropertyPath("Favicon") }; + item.SetBinding(AttachedPropertyClass.ImageSourceProperty, faviconBind); + WebTabControl.Items.Add(item); + WebTabControl.SelectedItem = item; + WebTabControl.SetHeaderPanelWidth(); #endregion } catch (Exception ex) @@ -195,13 +181,13 @@ namespace MWebBrowser.View } } - public void RemoveCurrentItem(object obj) + public void RemoveItemCommand(object obj) { if (obj is TabItem item) { WebTabControl.Items.Remove(item); - if (item.Content is WebTabItemUc webTabItem) + if(item.Content is WebTabItemUc webTabItem) { webTabItem.Dispose(); } @@ -213,26 +199,18 @@ namespace MWebBrowser.View WebTabControl.CloseTabEvent?.Invoke(); } } - private async void AfterLoad(bool isFirstLoad) + private async void AfterLoad() { try { Dispatcher.Invoke(() => { - viewModel.CurrentUrl = currentWebTabItem.CefWebBrowser.Address; - if (string.IsNullOrEmpty(currentWebTabItem.CefWebBrowser.Address) && isFirstLoad) - { - RemoveCurrentItem(this.WebTabControl.SelectedValue); - return; - } + _viewModel.Title = _currentWebTabItem.CefWebBrowser.Title; + _viewModel.CurrentUrl = _currentWebTabItem.CefWebBrowser.Address; }); - currentWebTabItem.CefWebBrowser.SetDownloadHandler(DownloadTool.DownloadFile); - currentWebTabItem.CefWebBrowser.OpenUrlEvent -= OpenUrl; - currentWebTabItem.CefWebBrowser.OpenUrlEvent += OpenUrl; - currentWebTabItem.CefWebBrowser.MouseWheelEvent -= WebMouseWheel; - currentWebTabItem.CefWebBrowser.MouseWheelEvent += WebMouseWheel; - var model = new HistoryModel { Url = viewModel.CurrentUrl, VisitTime = DateTime.Now, FormVisit = 0, Title = viewModel.Title }; - await historyServices.AddHistory(model); + + var model = new HistoryModel { Url = _viewModel.CurrentUrl, VisitTime = DateTime.Now, FormVisit = 0, Title = _viewModel.Title }; + await _historyServices.AddHistory(model); } catch (Exception ex) { @@ -243,7 +221,7 @@ namespace MWebBrowser.View switch (obj) { case "0": - OpenDefault(null); + TabItemAdd("http://www.baidu.com"); break; case "4": FavoritesMenu.FavoritesButton.IsChecked = true; @@ -254,9 +232,6 @@ namespace MWebBrowser.View case "6": ShowDownloadTab(); break; - case "10": - Print(); - break; case "15": ShowSettingTab(); break; @@ -269,13 +244,10 @@ namespace MWebBrowser.View /// private void WebTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) { - if (WebTabControl.SelectedItem is TabItem { Content: WebTabItemUc webTabItemUc }) - { - currentWebTabItem = webTabItemUc; - cefWebZoom.SetWebTabItem(currentWebTabItem); - cefWebSearch.SetWebTabItem(currentWebTabItem); - SetCurrentSelectedInfo(); - } + if (!(WebTabControl.SelectedItem is TabItem item)) return; + if (!(item.Content is WebTabItemUc webTabItemUc)) return; + _currentWebTabItem = webTabItemUc; + SetCurrentSelectedInfo(); } /// @@ -283,19 +255,187 @@ namespace MWebBrowser.View /// private void SetCurrentSelectedInfo() { - viewModel.CurrentUrl = currentWebTabItem.ViewModel.CurrentUrl; - viewModel.Title = currentWebTabItem.ViewModel.Title; + _viewModel.CurrentUrl = _currentWebTabItem.ViewModel.CurrentUrl; + _viewModel.Title = _currentWebTabItem.ViewModel.Title; } #endregion - private void WebMouseWheel(int delta) => cefWebZoom.WebMouseWheelZoom(delta); + #region 搜索框 + private void InitSearchCommand() + { + SearchText.ZoomInCommand = new BaseCommand((obj) => + { + ZoomIn(); + }); + SearchText.ZoomOutCommand = new BaseCommand((obj) => + { + ZoomOut(); + }); + SearchText.ZoomResetCommand = new BaseCommand((obj) => + { + ZoomReset(); + }); + } + + /// + /// 前进 + /// + /// + /// + private void NavigationBack_OnClick(object sender, RoutedEventArgs e) + { + _currentWebTabItem?.CefWebBrowser.Back(); + } + /// + /// 后退 + /// + /// + /// + private void NavigationForward_OnClick(object sender, RoutedEventArgs e) + { + _currentWebTabItem?.CefWebBrowser.Forward(); + } + + /// + /// 刷新 + /// + /// + /// + private void NavigationRefresh_OnClick(object sender, RoutedEventArgs e) + { + _currentWebTabItem?.CefWebBrowser.Reload(); + } - #region search box - private void NavigationBack_OnClick(object sender, RoutedEventArgs e) => cefWebSearch.NavigationBack(); - private void NavigationForward_OnClick(object sender, RoutedEventArgs e) => cefWebSearch.NavigationForward(); - private void NavigationRefresh_OnClick(object sender, RoutedEventArgs e) => cefWebSearch.NavigationRefresh(); - private void Search_OnKeyDown(object sender, KeyEventArgs e) => cefWebSearch.SearchOnKeyDown(e); + /// + /// 搜索框KeyDown事件 + /// + /// + /// + private void Search_OnKeyDown(object sender, KeyEventArgs e) + { + if (e.Key != Key.Enter) return; + var pattern = @"^(https?|ftp)://[^\s/$.?#].[^\s]*$"; + var match = Regex.Match(_viewModel.CurrentUrl, pattern); + + if (!match.Success) return; + if (string.IsNullOrEmpty(_viewModel.CurrentUrl)) return; + _currentWebTabItem.Load(_viewModel.CurrentUrl); + + DispatcherHelper.UIDispatcher.Invoke(() => + { + //使search框失去焦点 + this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); + }); + } + + #endregion + + #region 缩放 + private void WebMouseWheel(object sender, MouseWheelEventArgs e) + { + if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control) + { + _viewModel.ZoomStaysOpen = false; + return; + } + try + { + if (e.Delta > 0) + { + ZoomIn(); + } + else if (e.Delta < 0) + { + ZoomOut(); + } + _zoomWaitingCount = 0; + _zoomToolTimer.Elapsed -= ZoomToolTimer_Elapsed; + _zoomToolTimer.Elapsed += ZoomToolTimer_Elapsed; + _zoomToolTimer.AutoReset = true; + _zoomToolTimer.Enabled = true; + e.Handled = true; + } + catch (Exception ex) + { + + } + } + private void ZoomToolTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (_zoomWaitingCount > 2) + { + _zoomToolTimer?.Stop(); + _viewModel.ZoomIsChecked = false; + _viewModel.ZoomStaysOpen = false; + _zoomWaitingCount = -1; + return; + } + + if (_zoomWaitingCount > -1) + { + _zoomWaitingCount++; + } + } + + private void ZoomIn() + { + if (_currentWebTabItem.CefWebBrowser.ZoomLevel < 4) + { + _currentWebTabItem.CefWebBrowser.ZoomInCommand.Execute(null); + } + _viewModel.ZoomStaysOpen = true; + SetSearchZoomStatus(); + } + + private void ZoomOut() + { + if (_currentWebTabItem.CefWebBrowser.ZoomLevel > -4) + { + _currentWebTabItem.CefWebBrowser.ZoomOutCommand.Execute(null); + } + _viewModel.ZoomStaysOpen = true; + SetSearchZoomStatus(); + } + + private void ZoomReset() + { + _currentWebTabItem.CefWebBrowser.ZoomResetCommand.Execute(null); + // CefWebBrowser.SetZoomLevel(0); + SetSearchZoomStatus(); + } + + private void SetSearchZoomStatus() + { + if (null == _currentWebTabItem) return; + if (_currentWebTabItem.CefWebBrowser.ZoomLevel < 0) + { + _viewModel.ZoomLevelType = ZoomType.Out; + _viewModel.ZoomIsChecked = true; + if (_currentWebTabItem.CefWebBrowser.ZoomLevel > -1) + { + _viewModel.ZoomRatio = "90%"; + } + else if (_currentWebTabItem.CefWebBrowser.ZoomLevel <= 1) + { + var radio = Math.Round((_currentWebTabItem.CefWebBrowser.ZoomLevel + 5) / 5 * 100); + _viewModel.ZoomRatio = $"{radio}%"; + } + } + else if (_currentWebTabItem.CefWebBrowser.ZoomLevel > 0) + { + _viewModel.ZoomLevelType = ZoomType.In; + _viewModel.ZoomIsChecked = true; + var radio = Math.Round((1 + _currentWebTabItem.CefWebBrowser.ZoomLevel) * 100, 2); + _viewModel.ZoomRatio = $"{radio}%"; + } + else + { + _viewModel.ZoomLevelType = ZoomType.None; + _viewModel.ZoomIsChecked = false; + } + WebMenu.ZoomCallBack(_viewModel.ZoomRatio); + } #endregion } } \ No newline at end of file diff --git a/MWebBrowser/View/WebTabItemUc.xaml b/MWebBrowser/View/WebTabItemUc.xaml index 18579a2..1bb41cb 100644 --- a/MWebBrowser/View/WebTabItemUc.xaml +++ b/MWebBrowser/View/WebTabItemUc.xaml @@ -3,15 +3,11 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - - - - - - + + + \ No newline at end of file diff --git a/MWebBrowser/View/WebTabItemUc.xaml.cs b/MWebBrowser/View/WebTabItemUc.xaml.cs index 8cd29cd..d4d625d 100644 --- a/MWebBrowser/View/WebTabItemUc.xaml.cs +++ b/MWebBrowser/View/WebTabItemUc.xaml.cs @@ -1,14 +1,12 @@ using CefSharp; -using CefSharp.WinForms; using Cys_Controls.Code; +using MWebBrowser.Code.CustomCef; using MWebBrowser.Code.Helpers; using MWebBrowser.ViewModel; -using MWinFormsCore; -using MWinFormsCore.CustomCef; +using MWinFormsBrowser.Code.Helpers; using System; -using System.Threading.Tasks; using System.Windows; -using System.Windows.Forms; +using System.Windows.Controls; using System.Windows.Input; namespace MWebBrowser.View @@ -16,13 +14,14 @@ namespace MWebBrowser.View /// /// Interaction logic for WebTabItem.xaml /// - public partial class WebTabItemUc : System.Windows.Controls.UserControl + public partial class WebTabItemUc : UserControl { public CustomWebBrowser CefWebBrowser; - BrowserUserControl browserUserControl; public WebTabItemViewModel ViewModel; + public Action WebMouseWheelEvent; public Action SetCurrentEvent; + private readonly double _zoomLevelIncrement = 0.2;//默认为0.1 public WebTabItemUc() @@ -32,79 +31,66 @@ namespace MWebBrowser.View InitializeComponent(); InitWebBrowser(); } - public void CefWebBrowser_PreviewKeyDown(int keyCode) + + + private void CefWebBrowser_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { - Keys key = (Keys)Enum.Parse(typeof(Keys), keyCode.ToString()); - if (key == Keys.F5) - { - this.CefWebBrowser.Reload(); - } + WebMouseWheelEvent?.Invoke(sender,e); + } + - if (key == Keys.F11) + private void CefWebBrowser_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.F5) { - F11Helper.F11(browserUserControl, formsHost); + this.CefWebBrowser.Reload(); } - if (key == Keys.F12) + if (e.Key == Key.F11) { - this.browserUserControl.ShowDevToolsDocked(); + F11Helper.F11(WebParentGrid, CefWebBrowser); } if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control - && (key == Keys.D0 || key == Keys.NumPad0)) + && (e.Key == Key.D0 || e.Key == Key.NumPad0)) { - DispatcherHelper.UIDispatcher.Invoke(() => - { - var uc = ControlHelper.FindVisualParent(this); - uc?.SearchText.ZoomResetCommand.Execute(null); - }); + var uc = ControlHelper.FindVisualParent(this); + uc?.SearchText.ZoomResetCommand.Execute(null); } } - private void CefWebBrowser_TitleChanged(object sender, TitleChangedEventArgs e) + private void CefWebBrowser_TitleChanged(object sender, DependencyPropertyChangedEventArgs e) { - string address = CefWebBrowser.Address; - ViewModel.Title = e.Title; - DispatcherHelper.UIDispatcher.Invoke(() => - { - ViewModel.Favicon = ImageHelper.GetFavicon(address); - }); - ViewModel.CurrentUrl = address; + ViewModel.Title = CefWebBrowser.Title; + ViewModel.Favicon = ImageHelper.GetFavicon(CefWebBrowser.Address); + ViewModel.CurrentUrl = CefWebBrowser.Address; SetCurrentEvent?.Invoke(); } private void InitWebBrowser() { - browserUserControl = new BrowserUserControl(); - CefWebBrowser = browserUserControl.CefWebBrowser; - formsHost.Child = browserUserControl; + CefWebBrowser = new CustomWebBrowser(); + //NavigationStackPanel.DataContext = CefWebBrowser; CefWebBrowser.IsBrowserInitializedChanged += CefWebBrowser_IsBrowserInitializedChanged; + WebParentGrid.Children.Add(CefWebBrowser); this.CefWebBrowser.TitleChanged += CefWebBrowser_TitleChanged; - if(this.CefWebBrowser.KeyboardHandler is CustomKeyboardHandler handler) - { - handler.KeyboardCallBack += CefWebBrowser_PreviewKeyDown; - } + this.CefWebBrowser.PreviewKeyDown += CefWebBrowser_PreviewKeyDown; + this.CefWebBrowser.ZoomLevelIncrement = _zoomLevelIncrement; + this.CefWebBrowser.PreviewMouseWheel += CefWebBrowser_PreviewMouseWheel; + var s = this.CefWebBrowser.ZoomLevel; - // this.CefWebBrowser.ZoomLevelIncrement = _zoomLevelIncrement; } - private void CefWebBrowser_IsBrowserInitializedChanged(object sender, EventArgs e) + private void CefWebBrowser_IsBrowserInitializedChanged(object sender, DependencyPropertyChangedEventArgs e) { try { - DispatcherHelper.UIDispatcher.Invoke(() => + + if (!CefWebBrowser.IsBrowserInitialized) return; + CefWebBrowser.Focus();//浏览器初始化完毕后获得焦点 + if (!string.IsNullOrEmpty(ViewModel.CurrentUrl)) { - if (!CefWebBrowser.IsBrowserInitialized) return; - CefWebBrowser.Focus();//浏览器初始化完毕后获得焦点 - - if (ViewModel.FirstNew) - { - Load(ViewModel.FirstNewUrl); - } - else if (!string.IsNullOrEmpty(ViewModel.CurrentUrl)) - { - Load(ViewModel.CurrentUrl); - } - }); + Load(ViewModel.CurrentUrl); + } } catch (Exception ex) { @@ -117,25 +103,10 @@ namespace MWebBrowser.View CefWebBrowser.Load(url); } - public void Dispose() - { - - DisposeBrowserAsync(); - } - - /// - /// Synchronously disposing resources across threads might lead to crashes, so here we adopt asynchronous disposal. - /// - private async void DisposeBrowserAsync() - { - if (CefWebBrowser != null && !CefWebBrowser.IsDisposed) - { - await Task.Run(() => - { - CefWebBrowser.Dispose(); - CefWebBrowser = null; - }); - } + public void Dispose() + { + CefWebBrowser?.Dispose(); + CefWebBrowser = null; } } } diff --git a/MWebBrowser/ViewModel/WebTabItemViewModel.cs b/MWebBrowser/ViewModel/WebTabItemViewModel.cs index df96c4c..8b5e5fb 100644 --- a/MWebBrowser/ViewModel/WebTabItemViewModel.cs +++ b/MWebBrowser/ViewModel/WebTabItemViewModel.cs @@ -1,5 +1,4 @@ -using Cys_Common.Settings; -using MWebBrowser.Code.Helpers; +using MWebBrowser.Code.Helpers; using System.Windows.Media; namespace MWebBrowser.ViewModel @@ -14,10 +13,5 @@ namespace MWebBrowser.ViewModel private string _currentUrl; public string CurrentUrl { get => _currentUrl; set { _currentUrl = value; OnPropertyChanged("CurrentUrl"); } } - - private bool _firstNews; - public bool FirstNew { get => _firstNews; set { _firstNews = value; OnPropertyChanged("FirstNews"); } } - - public string FirstNewUrl { get => GlobalInfo.SearchEngineSetting.GetDefaultSearchEngineItemInfo().Url; } } } diff --git a/MWinFormsBrowser/App.xaml b/MWinFormsBrowser/App.xaml new file mode 100644 index 0000000..85006b9 --- /dev/null +++ b/MWinFormsBrowser/App.xaml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/MWinFormsBrowser/App.xaml.cs b/MWinFormsBrowser/App.xaml.cs new file mode 100644 index 0000000..3e63e76 --- /dev/null +++ b/MWinFormsBrowser/App.xaml.cs @@ -0,0 +1,16 @@ +using MWinFormsCore; +using System.Windows; + +namespace MWinFormsBrowser +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { + InitCefSharp.InitializeCefSharp(); + } + } +} diff --git a/MWinFormsBrowser/AssemblyInfo.cs b/MWinFormsBrowser/AssemblyInfo.cs new file mode 100644 index 0000000..01c8003 --- /dev/null +++ b/MWinFormsBrowser/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] +[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)] \ No newline at end of file diff --git a/MWinFormsBrowser/Code/CefWebOperate/CefWebSearch.cs b/MWinFormsBrowser/Code/CefWebOperate/CefWebSearch.cs new file mode 100644 index 0000000..81006f7 --- /dev/null +++ b/MWinFormsBrowser/Code/CefWebOperate/CefWebSearch.cs @@ -0,0 +1,64 @@ +using CefSharp; +using MWinFormsBrowser.Code.Helpers; +using MWinFormsBrowser.View; +using MWinFormsBrowser.ViewModel; +using System.Windows.Input; + +namespace MWinFormsBrowser.Code.CefWebOperate +{ + public class CefWebSearch + { + private WebTabItemUc currentWebTabItem; + private readonly WebTabControlViewModel viewModel; + public void SetWebTabItem(WebTabItemUc currentWebTabItem) + { + this.currentWebTabItem = currentWebTabItem; + } + + public CefWebSearch(WebTabControlViewModel viewModel) + { + this.viewModel = viewModel; + } + #region 搜索框 + /// + /// 前进 + /// + /// + /// + public void NavigationBack() + { + currentWebTabItem?.CefWebBrowser.Back(); + } + /// + /// 后退 + /// + /// + /// + public void NavigationForward() + { + currentWebTabItem?.CefWebBrowser.Forward(); + } + + /// + /// 刷新 + /// + /// + /// + public void NavigationRefresh() + { + currentWebTabItem?.CefWebBrowser.Reload(); + } + + /// + /// 搜索框KeyDown事件 + /// + /// + /// + public void SearchOnKeyDown(KeyEventArgs e) + { + if (e.Key != Key.Enter) return; + currentWebTabItem.Load(viewModel.CurrentUrl); + } + #endregion + } +} diff --git a/MWinFormsBrowser/Code/CefWebOperate/CefWebZoom.cs b/MWinFormsBrowser/Code/CefWebOperate/CefWebZoom.cs new file mode 100644 index 0000000..23afde7 --- /dev/null +++ b/MWinFormsBrowser/Code/CefWebOperate/CefWebZoom.cs @@ -0,0 +1,179 @@ +using CefSharp; +using Cys_Controls.Code; +using Cys_CustomControls.Controls; +using MWinFormsBrowser.View; +using MWinFormsBrowser.ViewModel; +using System; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace MWinFormsBrowser.Code.CefWebOperate +{ + public class CefWebZoom + { + private readonly System.Timers.Timer zoomToolTimer = new System.Timers.Timer(1000); + private int zoomWaitingCount = -1; + private readonly double zoomLevelIncrement = 0.1; + + private readonly WebMenuUc webMenuUc; + private readonly WebTabControlViewModel viewModel; + private WebTabItemUc currentWebTabItem; + private readonly MSearchText mSearchText; + + private readonly double minusZoom = -7.6; + private readonly double positiveZoom = 8; + public CefWebZoom(WebMenuUc webMenuUc, WebTabControlViewModel viewModel, MSearchText mSearchText) + { + this.webMenuUc = webMenuUc; + this.viewModel = viewModel; + this.mSearchText = mSearchText; + this.webMenuUc.ZoomInEvent += ZoomIn; + this.webMenuUc.ZoomOutEvent += ZoomOut; + InitZoomCommand(); + } + + public void SetWebTabItem(WebTabItemUc currentWebTabItem) + { + this.currentWebTabItem = currentWebTabItem; + } + + #region Zoom + + public void WebMouseWheelZoom(int delta) + { + if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control) + { + viewModel.ZoomStaysOpen = false; + return; + } + try + { + if (delta > 0) + { + ZoomIn(); + } + else if (delta < 0) + { + ZoomOut(); + } + zoomWaitingCount = 0; + zoomToolTimer.Elapsed -= ZoomToolTimer_Elapsed; + zoomToolTimer.Elapsed += ZoomToolTimer_Elapsed; + zoomToolTimer.AutoReset = true; + zoomToolTimer.Enabled = true; + } + catch (Exception ex) + { + + } + } + + private void InitZoomCommand() + { + mSearchText.ZoomInCommand = new BaseCommand((obj) => + { + ZoomIn(); + }); + mSearchText.ZoomOutCommand = new BaseCommand((obj) => + { + ZoomOut(); + }); + mSearchText.ZoomResetCommand = new BaseCommand((obj) => + { + ZoomReset(); + }); + } + private void ZoomToolTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (zoomWaitingCount > 2) + { + zoomToolTimer?.Stop(); + viewModel.ZoomIsChecked = false; + viewModel.ZoomStaysOpen = false; + zoomWaitingCount = -1; + return; + } + + if (zoomWaitingCount > -1) + { + zoomWaitingCount++; + } + } + + private async void ZoomIn() + { + double zoomLevel = await currentWebTabItem.CefWebBrowser.GetZoomLevelAsync(); + if (zoomLevel < positiveZoom) + { + double currentLevel = zoomLevel + zoomLevelIncrement; + currentWebTabItem.CefWebBrowser.SetZoomLevel(currentLevel); + } + else + { + currentWebTabItem.CefWebBrowser.SetZoomLevel(positiveZoom); + } + viewModel.ZoomStaysOpen = true; + SetSearchZoomStatus(); + } + + private async void ZoomOut() + { + double zoomLevel = await currentWebTabItem.CefWebBrowser.GetZoomLevelAsync(); + if (zoomLevel > minusZoom) + { + double currentLevel = zoomLevel - zoomLevelIncrement; + currentWebTabItem.CefWebBrowser.SetZoomLevel(currentLevel); + } + else + { + currentWebTabItem.CefWebBrowser.SetZoomLevel(minusZoom); + } + viewModel.ZoomStaysOpen = true; + SetSearchZoomStatus(); + } + + + private void ZoomReset() + { + currentWebTabItem.CefWebBrowser.SetZoomLevel(0); + SetSearchZoomStatus(); + } + + private async void SetSearchZoomStatus() + { + double zoomLevel = await currentWebTabItem.CefWebBrowser.GetZoomLevelAsync(); + if (null == currentWebTabItem) return; + if (zoomLevel < 0) + { + viewModel.ZoomLevelType = ZoomType.Out; + viewModel.ZoomIsChecked = true; + double minZoomLevel = -7.6; + double maxZoomLevel = 1; + double minPercentage = 25; + double maxPercentage = 100; + double percentage = minPercentage + (maxPercentage - minPercentage) * (zoomLevel - minZoomLevel) / (maxZoomLevel - minZoomLevel); + viewModel.ZoomRatio = $"{Math.Round(percentage, 2)}%"; + } + else if (zoomLevel == 0) + { + viewModel.ZoomLevelType = ZoomType.None; + viewModel.ZoomIsChecked = true; + viewModel.ZoomRatio = $"{100}%"; + } + else if (zoomLevel > 0) + { + viewModel.ZoomLevelType = ZoomType.In; + viewModel.ZoomIsChecked = true; + var radio = Math.Round((1 + zoomLevel) * 100, 2); + viewModel.ZoomRatio = $"{radio}%"; + } + else + { + viewModel.ZoomLevelType = ZoomType.None; + viewModel.ZoomIsChecked = false; + } + webMenuUc.ZoomCallBack(viewModel.ZoomRatio); + } + #endregion + } +} diff --git a/MWinFormsBrowser/Code/GlobalControl.cs b/MWinFormsBrowser/Code/GlobalControl.cs new file mode 100644 index 0000000..35b5134 --- /dev/null +++ b/MWinFormsBrowser/Code/GlobalControl.cs @@ -0,0 +1,13 @@ +using MWinFormsBrowser.View; + +namespace MWinFormsBrowser.Code +{ + public class GlobalControl + { + public static DownloadShowAllUc DownloadShowAll + { + get; + set; + } + } +} diff --git a/MWinFormsBrowser/Code/Helpers/DesignModeHelper.cs b/MWinFormsBrowser/Code/Helpers/DesignModeHelper.cs new file mode 100644 index 0000000..c5f7e85 --- /dev/null +++ b/MWinFormsBrowser/Code/Helpers/DesignModeHelper.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace MWinFormsBrowser.Code.Helpers +{ + public static class DesignModeHelper + { + public static bool IsInDesignMode(this Control control) + { + return System.ComponentModel.DesignerProperties.GetIsInDesignMode(control); + } + } +} diff --git a/MWinFormsBrowser/Code/Helpers/DispatcherHelper.cs b/MWinFormsBrowser/Code/Helpers/DispatcherHelper.cs new file mode 100644 index 0000000..e4dae83 --- /dev/null +++ b/MWinFormsBrowser/Code/Helpers/DispatcherHelper.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Threading; + +namespace MWinFormsBrowser.Code.Helpers +{ + public static class DispatcherHelper + { + public static Dispatcher UIDispatcher { get; } + + static DispatcherHelper() + { + UIDispatcher = Application.Current.Dispatcher; + } + } +} diff --git a/MWinFormsBrowser/Code/Helpers/F11Helper.cs b/MWinFormsBrowser/Code/Helpers/F11Helper.cs new file mode 100644 index 0000000..c8ccf29 --- /dev/null +++ b/MWinFormsBrowser/Code/Helpers/F11Helper.cs @@ -0,0 +1,52 @@ +using MWinFormsBrowser.View; +using MWinFormsCore; +using System.Windows; +using System.Windows.Forms.Integration; + +namespace MWinFormsBrowser.Code.Helpers +{ + public static class F11Helper + { + private static F11Window f11Window; + private static Rect originalBounds; + + public static void F11(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + { + DispatcherHelper.UIDispatcher.Invoke(() => + { + if (f11Window != null) + { + ExitFullscreen(browserUserControl, orgWebFormsHost); + } + else + { + EnterFullscreen(browserUserControl, orgWebFormsHost); + } + }); + } + + private static void EnterFullscreen(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + { + originalBounds = new Rect( + browserUserControl.CefWebBrowser.Margin.Left, + browserUserControl.CefWebBrowser.Margin.Top, + browserUserControl.CefWebBrowser.Width, + browserUserControl.CefWebBrowser.Height + ); + f11Window = new F11Window(); + orgWebFormsHost.Child.Controls.Remove(browserUserControl); + f11Window.WebFormsHost.Child = browserUserControl; + f11Window.Show(); + Application.Current.MainWindow.Hide(); + } + + private static void ExitFullscreen(BrowserUserControl browserUserControl, WindowsFormsHost orgWebFormsHost) + { + f11Window.WebFormsHost.Child.Controls.Remove(browserUserControl); + orgWebFormsHost.Child = browserUserControl; + Application.Current.MainWindow.Show(); + f11Window.Close(); + f11Window = null; + } + } +} diff --git a/MWinFormsBrowser/Code/Helpers/ImageHelper.cs b/MWinFormsBrowser/Code/Helpers/ImageHelper.cs new file mode 100644 index 0000000..f5caeb4 --- /dev/null +++ b/MWinFormsBrowser/Code/Helpers/ImageHelper.cs @@ -0,0 +1,50 @@ +using System; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace MWinFormsBrowser.Code.Helpers +{ + public static class ImageHelper + { + public static ImageSource DefaultFavicon { get; set; } + /// + /// 获取http pic + /// + /// + public static ImageSource GetBitmapFrame(string httpUrl) + { + try + { + return string.IsNullOrEmpty(httpUrl) ? DefaultFavicon : + new BitmapImage(new Uri(httpUrl, UriKind.RelativeOrAbsolute)); + } + catch + { + return DefaultFavicon; + } + } + + public static void InitImages() + { + if (Application.Current.MainWindow == null) return; + DefaultFavicon = Application.Current.MainWindow.FindResource("DrawingImage.DefaultFavicon") as ImageSource; + } + + public static ImageSource GetFavicon(string url) + { + try + { + var pattern = @"(\w+:\/\/)([^/:]+)(:\d*)?"; + var address = url; + var matches = Regex.Matches(address, pattern); + return matches.Count <= 0 ? null : ImageHelper.GetBitmapFrame($"{matches[0]}/favicon.ico"); + } + catch (Exception e) + { + return ImageHelper.DefaultFavicon; + } + } + } +} diff --git a/MWinFormsBrowser/Code/Logger.cs b/MWinFormsBrowser/Code/Logger.cs new file mode 100644 index 0000000..044041e --- /dev/null +++ b/MWinFormsBrowser/Code/Logger.cs @@ -0,0 +1,51 @@ +using log4net; +using System; + +public static class MLogger +{ + private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + //static MLogger() + //{ + // var s = log4net.Config.XmlConfigurator.Configure(); // 初始化log4net配置 + //} + + private static void Log(LogLevel level, string message, Exception ex = null) + { + switch (level) + { + case LogLevel.Debug: + if (log.IsDebugEnabled) log.Debug(message, ex); + break; + case LogLevel.Info: + if (log.IsInfoEnabled) log.Info(message, ex); + break; + case LogLevel.Warn: + log.Warn(message, ex); + break; + case LogLevel.Error: + log.Error(message, ex); + break; + case LogLevel.Fatal: + log.Fatal(message, ex); + break; + default: + throw new ArgumentOutOfRangeException(nameof(level), level, null); + } + } + + public static void Debug(string message, Exception ex = null) => Log(LogLevel.Debug, message, ex); + public static void Info(string message, Exception ex = null) => Log(LogLevel.Info, message, ex); + public static void Warn(string message, Exception ex = null) => Log(LogLevel.Warn, message, ex); + public static void Error(string message, Exception ex = null) => Log(LogLevel.Error, message, ex); + public static void Fatal(string message, Exception ex = null) => Log(LogLevel.Fatal, message, ex); + + private enum LogLevel + { + Debug, + Info, + Warn, + Error, + Fatal + } +} diff --git a/MWinFormsBrowser/Icon.ico b/MWinFormsBrowser/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8f5500fcb0efb30abe8f476b83b2682a8edce44d GIT binary patch literal 165662 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 + + + WinExe + net8.0-windows + true + true + AnyCPU;x86;x64 + true + Icon.ico + $(SolutionDir)Output\Winforms\$(Platform)\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + Always + + + Always + + + + + + $(DefaultXamlRuntime) + + + + \ No newline at end of file diff --git a/MWinFormsBrowser/MainWindow.xaml b/MWinFormsBrowser/MainWindow.xaml new file mode 100644 index 0000000..2f41253 --- /dev/null +++ b/MWinFormsBrowser/MainWindow.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/MWinFormsBrowser/MainWindow.xaml.cs b/MWinFormsBrowser/MainWindow.xaml.cs new file mode 100644 index 0000000..1b07324 --- /dev/null +++ b/MWinFormsBrowser/MainWindow.xaml.cs @@ -0,0 +1,51 @@ +using Cys_Common.Code.Configure; +using Cys_Common.Settings; +using Cys_CustomControls.Controls; +using Cys_DataRepository; +using Cys_Model.DataBase; +using MWinFormsBrowser.Code.Helpers; + +namespace MWinFormsBrowser +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : MMainWindow + { + public MainWindow() + { + InitializeComponent(); + ImageHelper.InitImages(); + ConfigHelper.LoadLocalConfig(); + InitGlobalInfo(); + this.Closing += MainWindow_Closing; + this.Loaded += MainWindow_Loaded; + } + + private void MainWindow_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + MLogger.Info("Main Window Show Success!"); + } + + private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + + SaveGlobalInfo(); + } + + private void InitGlobalInfo() + { + DbSeed.InitData(); + GlobalInfo.DownloadSetting = DataRepositoryServer.Instance.DownloadData.GetDownloadSetting(); + GlobalInfo.FavoritesSetting = DataRepositoryServer.Instance.FavoritesData.GetFavoritesSetting(); + GlobalInfo.SearchEngineSetting = DataRepositoryServer.Instance.SearchEngineData.GetSearchEngineSetting(); + } + + private void SaveGlobalInfo() + { + DataRepositoryServer.Instance.DownloadData.SaveDownloadSetting(); + DataRepositoryServer.Instance.FavoritesData.SaveFavoritesSetting(); + DataRepositoryServer.Instance.SearchEngineData.SaveSearchEngineSetting(); + } + } +} diff --git a/MWinFormsBrowser/TestUC.xaml b/MWinFormsBrowser/TestUC.xaml new file mode 100644 index 0000000..de409e2 --- /dev/null +++ b/MWinFormsBrowser/TestUC.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + +