From 0d8e270dde1064c309e3be42570ea5c109580d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E5=BB=BA=E5=8D=8E?= Date: Sun, 8 Dec 2019 14:16:34 +0800 Subject: [PATCH] Change some designs to fit MVVM and Task mode. --- YandereLinks/App.xaml.cs | 2 +- YandereLinks/Commands/CommandBase.cs | 191 ----------------- YandereLinks/Commands/DelegateCommand.cs | 149 ------------- YandereLinks/Helpers/ConsoleManager.cs | 6 +- YandereLinks/Helpers/ControlExtensions.cs | 37 ---- YandereLinks/Helpers/SystemComponents.cs | 10 +- YandereLinks/Models/YanderePage.cs | 199 ++++++++---------- YandereLinks/Properties/AssemblyInfo.cs | 4 +- YandereLinks/ViewModels/MainWindowModel.cs | 157 +++----------- YandereLinks/Views/ConsoleWindow.cs | 62 +++--- YandereLinks/Views/MainWindow.xaml | 21 +- YandereLinks/Views/MainWindow.xaml.cs | 142 ++++++++++++- ...Browser.xaml => NavigationWebBrowser.xaml} | 2 +- ...r.xaml.cs => NavigationWebBrowser.xaml.cs} | 141 +++++++------ YandereLinks/YandereLinks.csproj | 9 +- 15 files changed, 387 insertions(+), 745 deletions(-) delete mode 100644 YandereLinks/Commands/CommandBase.cs delete mode 100644 YandereLinks/Commands/DelegateCommand.cs delete mode 100644 YandereLinks/Helpers/ControlExtensions.cs rename YandereLinks/Views/{NaviWebBrowser.xaml => NavigationWebBrowser.xaml} (96%) rename YandereLinks/Views/{NaviWebBrowser.xaml.cs => NavigationWebBrowser.xaml.cs} (57%) diff --git a/YandereLinks/App.xaml.cs b/YandereLinks/App.xaml.cs index 0ec610a..f872934 100644 --- a/YandereLinks/App.xaml.cs +++ b/YandereLinks/App.xaml.cs @@ -4,7 +4,7 @@ namespace XstarS.YandereLinks { /// - /// App.xaml 的交互逻辑。 + /// 表示应用程序的入口点。 /// public partial class App : Application { diff --git a/YandereLinks/Commands/CommandBase.cs b/YandereLinks/Commands/CommandBase.cs deleted file mode 100644 index 978277d..0000000 --- a/YandereLinks/Commands/CommandBase.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; -using System.Threading; -using System.Windows.Input; - -namespace XstarS.ComponentModel -{ - /// - /// 提供命令 的无参数的抽象基类。 - /// - public abstract class CommandBase : ICommand - { - /// - /// 的值。 - /// - private bool _IsExecutable = true; - - /// - /// 创建当前命令的线程的同步上下文。 - /// - private readonly SynchronizationContext InitSyncContext; - - /// - /// 初始化 类的新实例。 - /// - protected CommandBase() - { - this.InitSyncContext = SynchronizationContext.Current; - } - - /// - /// 获取或设置此命令是否可在其当前状态下执行。 - /// - protected bool IsExecutable - { - get => this._IsExecutable; - set { this._IsExecutable = value; this.OnCanExecuteChanged(); } - } - - /// - /// 当出现影响是否应执行该命令的更改时发生。 - /// - public event EventHandler CanExecuteChanged; - - /// - /// 在当前状态下执行此命令。 - /// - public abstract void Execute(); - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 如果可执行此命令,则为 ; - /// 否则为 - public virtual bool CanExecute() => this.IsExecutable; - - /// - /// 引发 事件。 - /// - protected virtual void OnCanExecuteChanged() - { - if ((this.InitSyncContext is null) || - (this.InitSyncContext == SynchronizationContext.Current)) - { - this.OnCanExecuteChanged(null); - } - else - { - this.InitSyncContext.Post(this.OnCanExecuteChanged, null); - } - } - - /// - /// 引发 事件。 - /// - /// 不使用此参数。 - private void OnCanExecuteChanged(object unused) - { - this.CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - - /// - /// 在当前状态下执行此命令。 - /// - /// 此命令使用的数据。不使用此参数。 - void ICommand.Execute(object parameter) => this.Execute(); - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 此命令使用的数据。不使用此参数。 - /// 如果可执行此命令,则为 ; - /// 否则为 - bool ICommand.CanExecute(object parameter) => this.CanExecute(); - } - - /// - /// 提供命令 的有参数的抽象基类。 - /// - /// 命令使用的数据的类型。 - public abstract class CommandBase : ICommand - { - /// - /// 的值。 - /// - private bool _IsExecutable = true; - - /// - /// 创建当前命令的线程的同步上下文。 - /// - private readonly SynchronizationContext InitSyncContext; - - /// - /// 初始化 类的新实例。 - /// - protected CommandBase() - { - this.InitSyncContext = SynchronizationContext.Current; - } - - /// - /// 获取或设置此命令是否可在其当前状态下执行。 - /// - protected bool IsExecutable - { - get => this._IsExecutable; - set { this._IsExecutable = value; this.OnCanExecuteChanged(); } - } - - /// - /// 当出现影响是否应执行该命令的更改时发生。 - /// - public event EventHandler CanExecuteChanged; - - /// - /// 在当前状态下执行此命令。 - /// - /// 此命令使用的数据。 - public abstract void Execute(TParameter parameter); - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 此命令使用的数据。 - /// 如果可执行此命令,则为 ; - /// 否则为 - public virtual bool CanExecute(TParameter parameter) => this.IsExecutable; - - /// - /// 引发 事件。 - /// - protected virtual void OnCanExecuteChanged() - { - if ((this.InitSyncContext is null) || - (this.InitSyncContext == SynchronizationContext.Current)) - { - this.OnCanExecuteChanged(null); - } - else - { - this.InitSyncContext.Post(this.OnCanExecuteChanged, null); - } - } - - /// - /// 引发 事件。 - /// - /// 不使用此参数。 - private void OnCanExecuteChanged(object unused) - { - this.CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - - /// - /// 在当前状态下执行此命令。 - /// - /// 此命令使用的数据。 - /// - /// 不为 类型。 - void ICommand.Execute(object parameter) => this.Execute((TParameter)parameter); - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 此命令使用的数据。 - /// 如果可执行此命令,则为 ; - /// 否则为 - /// - /// 不为 类型。 - bool ICommand.CanExecute(object parameter) => this.CanExecute((TParameter)parameter); - } -} diff --git a/YandereLinks/Commands/DelegateCommand.cs b/YandereLinks/Commands/DelegateCommand.cs deleted file mode 100644 index e5f20c5..0000000 --- a/YandereLinks/Commands/DelegateCommand.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Windows.Input; - -namespace XstarS.ComponentModel -{ - /// - /// 表示由委托 定义的无参数的命令 。 - /// - public sealed class DelegateCommand : CommandBase - { - /// - /// 方法的委托。 - /// - private readonly Action ExecuteDelegate; - - /// - /// 方法的委托。 - /// - private readonly Func CanExecuteDelegate; - - /// - /// 使用指定的委托初始化 类的新实例。 - /// - /// - /// 方法的委托。 - /// - /// - public DelegateCommand(Action executeDelegate) - { - this.ExecuteDelegate = executeDelegate ?? - throw new ArgumentNullException(nameof(executeDelegate)); - this.CanExecuteDelegate = base.CanExecute; - } - - /// - /// 使用指定的委托初始化 类的新实例。 - /// - /// - /// 方法的委托。 - /// - /// 方法的委托。 - /// - /// 或 - public DelegateCommand(Action executeDelegate, Func canExecuteDelegate) - { - this.ExecuteDelegate = executeDelegate ?? - throw new ArgumentNullException(nameof(executeDelegate)); - this.CanExecuteDelegate = canExecuteDelegate ?? - throw new ArgumentNullException(nameof(canExecuteDelegate)); - } - - /// - /// 在当前状态下执行此命令。 - /// - public override void Execute() - { - this.ExecuteDelegate.Invoke(); - } - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 如果可执行此命令,则为 ; - /// 否则为 - public override bool CanExecute() - { - return this.CanExecuteDelegate.Invoke(); - } - - /// - /// 通知当前命令的可执行状态已更改。 - /// - public void NotifyCanExecuteChanged() => this.OnCanExecuteChanged(); - } - - /// - /// 表示由委托 定义的有参数的命令 。 - /// - /// 命令使用的数据的类型。 - public sealed class DelegateCommand : CommandBase - { - /// - /// 方法的委托。 - /// - private readonly Action ExecuteDelegate; - - /// - /// 方法的委托。 - /// - private readonly Func CanExecuteDelegate; - - /// - /// 使用指定的委托初始化 类的新实例。 - /// - /// - /// 方法的委托。 - /// - /// - public DelegateCommand(Action executeDelegate) - { - this.ExecuteDelegate = executeDelegate ?? - throw new ArgumentNullException(nameof(executeDelegate)); - this.CanExecuteDelegate = base.CanExecute; - } - - /// - /// 使用指定的委托初始化 类的新实例。 - /// - /// - /// 方法的委托。 - /// - /// 方法的委托。 - /// - /// 或 - public DelegateCommand(Action executeDelegate, - Func canExecuteDelegate) - { - this.ExecuteDelegate = executeDelegate ?? - throw new ArgumentNullException(nameof(executeDelegate)); - this.CanExecuteDelegate = canExecuteDelegate ?? - throw new ArgumentNullException(nameof(canExecuteDelegate)); - } - - /// - /// 在当前状态下执行此命令。 - /// - /// 此命令使用的数据。 - public override void Execute(TParameter parameter) - { - this.ExecuteDelegate.Invoke(parameter); - } - - /// - /// 确定此命令是否可在其当前状态下执行。 - /// - /// 此命令使用的数据。 - /// 如果可执行此命令,则为 ; - /// 否则为 - public override bool CanExecute(TParameter parameter) - { - return this.CanExecuteDelegate.Invoke(parameter); - } - - /// - /// 通知当前命令的可执行状态已更改。 - /// - public void NotifyCanExecuteChanged() => this.OnCanExecuteChanged(); - } -} diff --git a/YandereLinks/Helpers/ConsoleManager.cs b/YandereLinks/Helpers/ConsoleManager.cs index 20ab624..1285a82 100644 --- a/YandereLinks/Helpers/ConsoleManager.cs +++ b/YandereLinks/Helpers/ConsoleManager.cs @@ -59,7 +59,7 @@ public static void Show() if (!ConsoleManager.HasConsole) { ConsoleManager.SafeNativeMethods.AllocConsole(); - ConsoleManager.InvalidateStdOutError(); + ConsoleManager.InitializeStdOutError(); } } @@ -91,9 +91,9 @@ public static void Toggle() } /// - /// 释放 的标准输出流和错误流,以触发其重新初始化。 + /// 重新初始化 的标准输出流和错误流。 /// - private static void InvalidateStdOutError() + private static void InitializeStdOutError() { var t_Console = typeof(Console); var staticNoPublic = BindingFlags.Static | BindingFlags.NonPublic; diff --git a/YandereLinks/Helpers/ControlExtensions.cs b/YandereLinks/Helpers/ControlExtensions.cs deleted file mode 100644 index 1ded439..0000000 --- a/YandereLinks/Helpers/ControlExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Reflection; -using System.Windows.Controls; - -namespace XstarS.Windows.Controls -{ - /// - /// 提供 WPF 用户控件 及其派生类的扩展方法。 - /// - internal static class ControlExtensions - { - /// - /// 设定是否禁止当前 的脚本错误提示。 - /// - /// 要设定脚本错误提示的 对象。 - /// 指示是否要禁止脚本错误提示。 - /// - /// - public static void SuppressScriptErrors(this WebBrowser browser, bool supresses = true) - { - if (browser is null) - { - throw new ArgumentNullException(nameof(browser)); - } - - var if__axIWebBrowser2 = typeof(WebBrowser).GetField( - "_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic); - if (if__axIWebBrowser2 is null) { return; } - - var _axIWebBrowser2 = if__axIWebBrowser2.GetValue(browser); - if (_axIWebBrowser2 is null) { return; } - - _axIWebBrowser2.GetType().InvokeMember( - "Silent", BindingFlags.SetProperty, null, _axIWebBrowser2, new object[] { supresses }); - } - } -} diff --git a/YandereLinks/Helpers/SystemComponents.cs b/YandereLinks/Helpers/SystemComponents.cs index f03ceaf..ada33da 100644 --- a/YandereLinks/Helpers/SystemComponents.cs +++ b/YandereLinks/Helpers/SystemComponents.cs @@ -28,7 +28,7 @@ public static Version Version using (var regKeyIE = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\Microsoft\Internet Explorer")) { - string versionSz = (regKeyIE.GetValue("svcVersion") ?? + var versionSz = (regKeyIE.GetValue("svcVersion") ?? regKeyIE.GetValue("Version")) as string; return (versionSz is null) ? null : new Version(versionSz); } @@ -67,7 +67,7 @@ public static class WebBrowser @"SOFTWARE\Microsoft\Internet Explorer\" + @"MAIN\FeatureControl\FEATURE_BROWSER_EMULATION", false)) { - string appName = AppDomain.CurrentDomain.FriendlyName; + var appName = AppDomain.CurrentDomain.FriendlyName; return regKeyBrowser.GetValue(appName) as int?; } } @@ -84,7 +84,7 @@ public static class WebBrowser @"SOFTWARE\Microsoft\Internet Explorer\" + @"MAIN\FeatureControl\FEATURE_BROWSER_EMULATION", true)) { - string appName = AppDomain.CurrentDomain.FriendlyName; + var appName = AppDomain.CurrentDomain.FriendlyName; if (value is null) { regKeyBrowser.DeleteValue(appName); @@ -131,7 +131,7 @@ public static class WebBrowser @"SOFTWARE\Microsoft\Internet Explorer\" + @"MAIN\FeatureControl\FEATURE_BROWSER_EMULATION", false)) { - string appName = AppDomain.CurrentDomain.FriendlyName; + var appName = AppDomain.CurrentDomain.FriendlyName; return regKeyBrowser.GetValue(appName) as int?; } } @@ -148,7 +148,7 @@ public static class WebBrowser @"SOFTWARE\Microsoft\Internet Explorer\" + @"MAIN\FeatureControl\FEATURE_BROWSER_EMULATION", true)) { - string appName = AppDomain.CurrentDomain.FriendlyName; + var appName = AppDomain.CurrentDomain.FriendlyName; if (value is null) { regKeyBrowser.DeleteValue(appName); diff --git a/YandereLinks/Models/YanderePage.cs b/YandereLinks/Models/YanderePage.cs index c6c346d..8e2575f 100644 --- a/YandereLinks/Models/YanderePage.cs +++ b/YandereLinks/Models/YanderePage.cs @@ -61,22 +61,19 @@ public class YanderePage : IDisposable, IReadOnlyList protected static readonly string NextPageLinkPrefix; /// - /// 页面的链接。 - /// 使用 访问以执行对象释放检查。 + /// 指示当前对象是否已经被释放。 /// - private readonly string _PageLink; + private volatile bool IsDisposed = false; /// - /// 用于 HTTP 访问的客户端对象。 - /// 使用 访问以执行对象释放检查。 + /// 的值。 /// private HttpClient _HttpClient; /// - /// 获取 HTML 文本的任务。 - /// 使用 访问以执行对象释放检查。 + /// 的值。 /// - private Task _DocumentTextTask; + private Task _DocumentTextAsync; /// /// 初始化 类的静态成员。 @@ -107,112 +104,94 @@ static YanderePage() /// 。 /// /// 不为合法的绝对 URI。 - public YanderePage(string pageLink) : this(pageLink, true) { } - - /// - /// 使用页面的链接和 HTML 文本初始化 类的新实例。 - /// - /// 页面的链接。 - /// 页面的 HTML 文本。 - /// 或 - /// - /// - /// 不为合法的绝对 URI。 - public YanderePage(string pageLink, string documentText) : this(pageLink, false) + public YanderePage(string pageLink) { - if (documentText is null) + if (pageLink is null) { - throw new ArgumentNullException(nameof(documentText)); + throw new ArgumentNullException(nameof(pageLink)); + } + if (!Uri.TryCreate(pageLink, UriKind.Absolute, out _)) + { + throw new ArgumentException(new ArgumentException().Message, nameof(pageLink)); } - this._DocumentTextTask = new Task(() => documentText); - this._DocumentTextTask.RunSynchronously(); + this.PageLink = pageLink; + this.HttpClient = new HttpClient(); + this.DocumentTextAsync = this._HttpClient.GetStringAsync(pageLink); } /// - /// 使用页面的链接初始化 类的新实例, - /// 并指定是否获取页面的 HTML 文本。 + /// 使用页面的链接和 HTML 文本初始化 类的新实例。 /// - /// - /// 若在派生类的初始化方法中调用了此初始化方法, - /// 应重写 属性, - /// 以确保基类能够正确读取页面的 HTML 文本并获取链接。 - /// /// 页面的链接。 - /// 指示是否获取页面的 HTML 文本。 - /// - /// + /// 页面的 HTML 文本。 + /// 或 + /// /// /// 不为合法的绝对 URI。 - protected YanderePage(string pageLink, bool getsDocument) + public YanderePage(string pageLink, string documentText) { if (pageLink is null) { throw new ArgumentNullException(nameof(pageLink)); } - else if (!Uri.TryCreate(pageLink, UriKind.Absolute, out var _)) + if (!Uri.TryCreate(pageLink, UriKind.Absolute, out var _)) { throw new ArgumentException(new ArgumentException().Message, nameof(pageLink)); } + if (documentText is null) + { + throw new ArgumentNullException(nameof(documentText)); + } - this._PageLink = pageLink; - this._HttpClient = new HttpClient(); - this._DocumentTextTask = getsDocument ? - this._HttpClient.GetStringAsync(pageLink) : null; + this.PageLink = pageLink; + this.DocumentTextAsync = Task.Run(() => documentText); } - /// - /// 指示当前对象是否已经被释放。 - /// - protected bool IsDisposed { get; private set; } = false; - - /// - /// 获取当前对象,并检查当前对象是否已经被释放。 - /// - /// 当前对象已经被释放。 - protected YanderePage Disposable => this.IsDisposed ? - throw new ObjectDisposedException(this.GetType().ToString()) : this; - /// /// 页面的链接。 /// - public string PageLink => this.Disposable._PageLink; + public string PageLink { get; } /// /// 用于 HTTP 访问的客户端对象。 /// private HttpClient HttpClient { - get => this.Disposable._HttpClient; - set => this.Disposable._HttpClient = value; + get => !this.IsDisposed ? this._HttpClient : + throw new ObjectDisposedException(this.GetType().ToString()); + set => this._HttpClient = !this.IsDisposed ? value : + throw new ObjectDisposedException(this.GetType().ToString()); } /// - /// 获取 HTML 文本的任务。 + /// 异步获取页面的 HTML 文本。 /// - private Task DocumentTextTask + public Task DocumentTextAsync { - get => this.Disposable._DocumentTextTask; - set => this.Disposable._DocumentTextTask = value; + get => !this.IsDisposed ? this._DocumentTextAsync : + throw new ObjectDisposedException(this.GetType().ToString()); + private set => this._DocumentTextAsync = !this.IsDisposed ? value : + throw new ObjectDisposedException(this.GetType().ToString()); } /// - /// 页面的 HTML 文本。 + /// 获取页面的 HTML 文本。 /// [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public virtual string DocumentText + public string DocumentText { get { - if (this.DocumentTextTask is null) + if (this.DocumentTextAsync is null) { return string.Empty; } try { - return this.DocumentTextTask.Result; + return this.DocumentTextAsync.Result; } catch (Exception e) when (e.InnerException is TaskCanceledException) @@ -251,22 +230,22 @@ public virtual string DocumentText } /// - /// 当前页面的索引。 + /// 获取当前页面的索引。 /// public int Index { get { - string pageIndexPrefix = "page="; - string pageLink = this.PageLink; + var pageIndexPrefix = "page="; + var pageLink = this.PageLink; if (!pageLink.Contains(pageIndexPrefix)) { return 1; } - string pageIndexString = string.Empty; - int startIndex = pageLink.IndexOf(pageIndexPrefix) + + var pageIndexString = string.Empty; + var startIndex = pageLink.IndexOf(pageIndexPrefix) + pageIndexPrefix.Length; for (int i = startIndex; i < pageLink.Length; i++) { @@ -284,13 +263,13 @@ public int Index } /// - /// 当前页面能够直接导航的页面数量。 + /// 获取当前页面能够直接导航的页面数量。 /// public int Count { get { - string documentText = this.DocumentText; + var documentText = this.DocumentText; if (!documentText.Contains(YanderePage.NextPageLinkPrefix)) { @@ -298,8 +277,8 @@ public int Count this.Index : 1; } - string lastPageIndexString = string.Empty; - int endIndex = documentText.IndexOf(YanderePage.NextPageLinkPrefix); + var lastPageIndexString = string.Empty; + var endIndex = documentText.IndexOf(YanderePage.NextPageLinkPrefix); for (int i = endIndex; i >= 0; i--) { if (char.IsDigit(documentText[i])) @@ -316,20 +295,20 @@ public int Count } /// - /// 页面包含的图片链接。 + /// 获取页面包含的图片链接。 /// public string[] ImageLinks { get { - string documentText = this.DocumentText; + var documentText = this.DocumentText; var imageLinks = new List(); while (documentText.Contains(YanderePage.ImageLinkPrefix)) { - int startIndex = documentText.IndexOf(YanderePage.ImageLinkPrefix) + + var startIndex = documentText.IndexOf(YanderePage.ImageLinkPrefix) + YanderePage.ImageLinkPrefix.Length; - string imageLink = documentText.Substring(startIndex); + var imageLink = documentText.Substring(startIndex); imageLink = imageLink.Remove(imageLink.IndexOf('"')); imageLinks.Add(imageLink); documentText = documentText.Substring(startIndex); @@ -339,20 +318,20 @@ public string[] ImageLinks } /// - /// Pools 页面的所有 Pool 页面的链接。 + /// 获取 Pools 页面的所有 Pool 页面的链接。 /// public string[] PoolPageLinks { get { - string documentText = this.DocumentText; + var documentText = this.DocumentText; var poolPageLinks = new List(); while (documentText.Contains(YanderePage.PoolPageLinkPrefix)) { - int startIndex = documentText.IndexOf(YanderePage.PoolPageLinkPrefix) + + var startIndex = documentText.IndexOf(YanderePage.PoolPageLinkPrefix) + YanderePage.PoolPageLinkPrefix.Length; - string poolPageLink = documentText.Substring(startIndex); + var poolPageLink = documentText.Substring(startIndex); poolPageLink = poolPageLink.Remove(poolPageLink.IndexOf('"')); poolPageLinks.Add(YanderePage.PoolPageLinkStatic + poolPageLink); documentText = documentText.Substring(startIndex); @@ -362,69 +341,69 @@ public string[] PoolPageLinks } /// - /// Pools 页面的所有 Pool 页面的 对象。 + /// 获取 Pools 页面的所有 Pool 页面的 对象。 /// public YanderePage[] PoolPages => Array.ConvertAll(this.PoolPageLinks, pageLink => new YanderePage(pageLink)); /// - /// 上一页面的链接。 + /// 获取上一页面的链接。 /// public string PrevPageLink { get { - string documentText = this.DocumentText; + var documentText = this.DocumentText; if (!documentText.Contains(YanderePage.PrevPageLinkPrefix)) { return null; } - int startIndex = documentText.IndexOf(YanderePage.PrevPageLinkPrefix) + + var startIndex = documentText.IndexOf(YanderePage.PrevPageLinkPrefix) + YanderePage.PrevPageLinkPrefix.Length; - string prevPageLink = documentText.Substring(startIndex); + var prevPageLink = documentText.Substring(startIndex); prevPageLink = prevPageLink.Remove(prevPageLink.IndexOf('"')); return YanderePage.IndexPageLink + prevPageLink; } } /// - /// 上一页面的 对象。 + /// 获取上一页面的 对象。 /// public YanderePage PrevPage => (this.PrevPageLink is null) ? null : new YanderePage(this.PrevPageLink); /// - /// 下一页面的链接。 + /// 获取下一页面的链接。 /// public string NextPageLink { get { - string documentText = this.DocumentText; + var documentText = this.DocumentText; if (!documentText.Contains(YanderePage.NextPageLinkPrefix)) { return null; } - int startIndex = documentText.IndexOf(YanderePage.NextPageLinkPrefix) + + var startIndex = documentText.IndexOf(YanderePage.NextPageLinkPrefix) + YanderePage.NextPageLinkPrefix.Length; - string nextPageLink = documentText.Substring(startIndex); + var nextPageLink = documentText.Substring(startIndex); nextPageLink = nextPageLink.Remove(nextPageLink.IndexOf('"')); return YanderePage.IndexPageLink + nextPageLink; } } /// - /// 下一页面的 对象。 + /// 获取下一页面的 对象。 /// public YanderePage NextPage => (this.NextPageLink is null) ? null : new YanderePage(this.NextPageLink); /// - /// 指示页面是否为 yande.re 的页面。 + /// 确定指定页面是否为 yande.re 的页面。 /// /// 待验证的 对象。 /// 为 yande.re 的页面, @@ -434,7 +413,7 @@ public string NextPageLink page.PageLink.StartsWith(YanderePage.IndexPageLink); /// - /// 指示页面是否为 Posts 页面。 + /// 确定指定页面是否为 Posts 页面。 /// /// 待验证的 对象。 /// 为 Posts 页面, @@ -445,7 +424,7 @@ public string NextPageLink !page.PageLink.StartsWith(YanderePage.PostPageLinkStatic); /// - /// 指示页面是否为 Pools 页面。 + /// 确定指定页面是否为 Pools 页面。 /// /// 待验证的 对象。 /// 为 Pools 页面, @@ -456,7 +435,7 @@ public string NextPageLink !page.PageLink.StartsWith(YanderePage.PoolPageLinkStatic); /// - /// 指示页面是否为 Post 页面。 + /// 确定指定页面是否为 Post 页面。 /// /// 待验证的 对象。 /// 为 Post 页面, @@ -466,7 +445,7 @@ public string NextPageLink page.PageLink.StartsWith(YanderePage.PostPageLinkStatic); /// - /// 指示页面是否为 Pool 页面。 + /// 确定指定页面是否为 Pool 页面。 /// /// 待验证的 对象。 /// 为 Pool 页面, @@ -490,15 +469,15 @@ public YanderePage PageAt(int index) return this; } - string pageIndexPrefix = "page="; - string pageLink = (this.PageLink == YanderePage.IndexPageLink) ? + var pageIndexPrefix = "page="; + var pageLink = (this.PageLink == YanderePage.IndexPageLink) ? YanderePage.PostsPageLink : this.PageLink; string indexPageLink; if (pageLink.Contains(pageIndexPrefix)) { - int pageIndexLength = 0; - int startIndex = pageLink.IndexOf(pageIndexPrefix) + pageIndexPrefix.Length; + var pageIndexLength = 0; + var startIndex = pageLink.IndexOf(pageIndexPrefix) + pageIndexPrefix.Length; for (int i = startIndex; i < pageLink.Length; i++) { if (char.IsDigit(pageLink[i])) @@ -510,12 +489,12 @@ public YanderePage PageAt(int index) break; } } - indexPageLink = pageLink.Remove(startIndex, pageIndexLength). - Insert(startIndex, index.ToString()); + indexPageLink = pageLink.Remove( + startIndex, pageIndexLength).Insert(startIndex, index.ToString()); } else { - string paramModifier = pageLink.Contains("?") ? "&" : "?"; + var paramModifier = pageLink.Contains("?") ? "&" : "?"; indexPageLink = pageLink + paramModifier + pageIndexPrefix + index.ToString(); } return new YanderePage(indexPageLink); @@ -527,8 +506,8 @@ public YanderePage PageAt(int index) public virtual void Refresh() { this.Cancel(); - this.DocumentTextTask?.Dispose(); - this.DocumentTextTask = this.HttpClient?.GetStringAsync(this.PageLink); + this.DocumentTextAsync?.Dispose(); + this.DocumentTextAsync = this.HttpClient?.GetStringAsync(this.PageLink); } /// @@ -539,7 +518,7 @@ public virtual void Refresh() public virtual void Cancel() { this.HttpClient?.CancelPendingRequests(); - try { this.DocumentTextTask?.Wait(); } catch { } + try { this.DocumentTextAsync?.Wait(); } catch { } } /// @@ -568,10 +547,10 @@ protected virtual void Dispose(bool disposing) if (disposing) { this.Cancel(); - this._DocumentTextTask?.Dispose(); - this._DocumentTextTask = null; - this._HttpClient?.Dispose(); - this._HttpClient = null; + this.DocumentTextAsync?.Dispose(); + this.DocumentTextAsync = null; + this.HttpClient?.Dispose(); + this.HttpClient = null; } this.IsDisposed = true; diff --git a/YandereLinks/Properties/AssemblyInfo.cs b/YandereLinks/Properties/AssemblyInfo.cs index 79f0eef..d688267 100644 --- a/YandereLinks/Properties/AssemblyInfo.cs +++ b/YandereLinks/Properties/AssemblyInfo.cs @@ -49,5 +49,5 @@ // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.0.0")] -[assembly: AssemblyFileVersion("1.3.0.0")] +[assembly: AssemblyVersion("1.3.1.0")] +[assembly: AssemblyFileVersion("1.3.1.0")] diff --git a/YandereLinks/ViewModels/MainWindowModel.cs b/YandereLinks/ViewModels/MainWindowModel.cs index 7057030..8d7b8bc 100644 --- a/YandereLinks/ViewModels/MainWindowModel.cs +++ b/YandereLinks/ViewModels/MainWindowModel.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using System.Threading; using System.Threading.Tasks; -using System.Windows; using XstarS.ComponentModel; using XstarS.YandereLinks.Models; @@ -18,16 +17,10 @@ public class MainWindowModel : ObservableStorage /// public MainWindowModel() { - this.ExtractCancellationSource = new CancellationTokenSource(); - this.ExtractLinksCommand = this.CreateExtractLinksCommand(); - this.EnumerateExtractLinksCommand = this.CreateEnumerateExtractLinksCommand(); - this.CancelExtractLinksCommand = this.CreateCancelExtractLinksCommand(); - this.CopyLinksCommand = this.CreateCopyLinksCommand(); - this.ClearLinksCommand = this.CreateClearLinksCommand(); - this.PageLink = this.HomePageLink; this.ImageLinks = string.Empty; this.CanExtract = true; + this.ExtractCancellationSource = new CancellationTokenSource(); } /// @@ -106,129 +99,58 @@ private void ExtractImageLinks() } /// - /// 表示提取图片链接的命令。 - /// - public DelegateCommand ExtractLinksCommand { get; } - - /// - /// 创建 。 + /// 异步提取当前页面包含的图片链接。 /// - /// - private DelegateCommand CreateExtractLinksCommand() + public Task ExtractImageLinksAsync() { - return new DelegateCommand( - () => Task.Run(() => + return Task.Run(() => + { + if (this.CanExtract) { - if (this.CanExtract) - { - this.CanExtract = false; - this.ExtractImageLinks(); - this.CanExtract = true; - } - }), - () => this.CanExtract); + this.CanExtract = false; + this.ExtractImageLinks(); + this.CanExtract = true; + } + }); } /// - /// 表示遍历页面并提取图片链接的命令。 - /// - public DelegateCommand EnumerateExtractLinksCommand { get; } - - /// - /// 创建 。 + /// 异步提取当前页面到最后页面包含的图片链接。 /// - /// - private DelegateCommand CreateEnumerateExtractLinksCommand() + public Task EnumeratePageExtractAsync() { - return new DelegateCommand( - () => Task.Run(() => + return Task.Run(() => + { + if (this.CanExtract) { - if (this.CanExtract) + this.CanExtract = false; + var page = this.PageObject; + var token = this.ExtractCancellationSource.Token; + if (YanderePage.IsYanderePage(page) && !token.IsCancellationRequested) { - this.CanExtract = false; - var page = this.PageObject; - var token = this.ExtractCancellationSource.Token; - if (YanderePage.IsYanderePage(page) && !token.IsCancellationRequested) + foreach (var nextPage in page) { - foreach (var nextPage in page) - { - if (token.IsCancellationRequested) { break; } - this.PageLink = nextPage.PageLink; - this.ExtractImageLinks(); - } + if (token.IsCancellationRequested) { break; } + this.PageLink = nextPage.PageLink; + this.ExtractImageLinks(); } - this.CanExtract = true; } - }), - () => this.CanExtract); - } - - /// - /// 表示取消提取图片链接的命令。 - /// - public DelegateCommand CancelExtractLinksCommand { get; } - - /// - /// 创建 。 - /// - /// - private DelegateCommand CreateCancelExtractLinksCommand() - { - return new DelegateCommand( - () => - { - if (this.CanCancelExtract) - { - this.ExtractCancellationSource.Cancel(); - this.ExtractCancellationSource = new CancellationTokenSource(); - this.PageObject.Refresh(); - } - }, - () => this.CanCancelExtract); - } - - /// - /// 表示复制已提取的图片链接到剪贴板的命令。 - /// - public DelegateCommand CopyLinksCommand { get; } - - /// - /// 创建 。 - /// - /// - private DelegateCommand CreateCopyLinksCommand() - { - return new DelegateCommand( - () => - { - if (this.HasImageLinks) - { - Clipboard.SetText(this.ImageLinks); - } - }, - () => this.HasImageLinks); + this.CanExtract = true; + } + }); } /// - /// 表示清除已提取的图片链接的命令。 - /// - public DelegateCommand ClearLinksCommand { get; } - - /// - /// 创建 。 + /// 取消提取图片链接的异步操作。 /// - /// - private DelegateCommand CreateClearLinksCommand() + public void CancelExtract() { - return new DelegateCommand( - () => - { - if (this.HasImageLinks) - { - this.ImageLinks = string.Empty; - } - }, - () => this.HasImageLinks); + if (this.CanCancelExtract) + { + this.ExtractCancellationSource.Cancel(); + this.ExtractCancellationSource = new CancellationTokenSource(); + this.PageObject.Refresh(); + } } /// @@ -243,19 +165,10 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e) { case nameof(this.CanExtract): this.NotifyPropertyChanged(nameof(this.CanCancelExtract)); - this.ExtractLinksCommand.NotifyCanExecuteChanged(); - this.EnumerateExtractLinksCommand.NotifyCanExecuteChanged(); - break; - case nameof(this.CanCancelExtract): - this.CancelExtractLinksCommand.NotifyCanExecuteChanged(); break; case nameof(this.ImageLinks): this.NotifyPropertyChanged(nameof(this.HasImageLinks)); break; - case nameof(this.HasImageLinks): - this.CopyLinksCommand.NotifyCanExecuteChanged(); - this.ClearLinksCommand.NotifyCanExecuteChanged(); - break; default: break; } diff --git a/YandereLinks/Views/ConsoleWindow.cs b/YandereLinks/Views/ConsoleWindow.cs index 0e2f23f..5eadc42 100644 --- a/YandereLinks/Views/ConsoleWindow.cs +++ b/YandereLinks/Views/ConsoleWindow.cs @@ -37,7 +37,7 @@ public static class ConsoleWindow /// /// 已提取的图片链接。 /// - private static readonly ICollection ImageLinks = new HashSet(); + private static readonly HashSet ImageLinks = new HashSet(); /// /// 显示控制台窗口,并传递程序启动参数。 @@ -111,8 +111,8 @@ private static void Run(string[] args) foreach (var page in pages) { - if (enumCount == 0) { ConsoleWindow.ExtractPage(page); } - else { ConsoleWindow.EnumeratePages(page, enumCount); } + if (enumCount == 0) { ConsoleWindow.ExtractImageLinksAsync(page); } + else { ConsoleWindow.EnumeratePageExtractAsync(page, enumCount); } } while (ConsoleWindow.WorkingThreads != 0) { Thread.Sleep(10); } @@ -129,6 +129,22 @@ private static void Run(string[] args) } } + /// + /// 将帮助信息输出到控制台。 + /// + private static void ShowHelp() + { + Console.WriteLine(); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_Usage); + Console.WriteLine(); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_PageLink); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_PageCount); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_MaxThreads); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_OutFile); + Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_Help); + Console.WriteLine(); + } + /// /// 格式化输入的 yande.re 页面链接。 /// @@ -150,27 +166,11 @@ private static string FormatPageLink(string pageLink) else { return pageLink; } } - /// - /// 将帮助信息输出到控制台。 - /// - private static void ShowHelp() - { - Console.WriteLine(); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_Usage); - Console.WriteLine(); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_PageLink); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_PageCount); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_MaxThreads); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_OutFile); - Console.WriteLine(Properties.StringResources.ConsoleWindow_Help_Help); - Console.WriteLine(); - } - /// /// 提取页面中包含的图片链接。 /// /// 页面连接提取对象。 - private static void ExtractLinks(YanderePage page) + private static void ExtractImageLinks(YanderePage page) { lock (ConsoleWindow.SyncRoot) { @@ -205,26 +205,14 @@ private static void ExtractLinks(YanderePage page) } } - /// - /// 提取页面中包含的图片链接的线程池回调方法。 - /// - /// 包含回调方法要使用的信息的对象, - /// 应为 。 - private static void OnExtractLinks(object state) - { - if (state is YanderePage page) - { - ConsoleWindow.ExtractLinks(page); - } - } - /// /// 异步提取页面中包含的图片链接。 /// /// 页面链接提取对象。 - private static void ExtractPage(YanderePage page) + private static void ExtractImageLinksAsync(YanderePage page) { - ThreadPool.QueueUserWorkItem(ConsoleWindow.OnExtractLinks, page); + ThreadPool.QueueUserWorkItem( + state => ConsoleWindow.ExtractImageLinks((YanderePage)state), page); } /// @@ -233,14 +221,14 @@ private static void ExtractPage(YanderePage page) /// 页面链接提取对象。 /// 指定遍历的页面数量; /// 为 -1 则遍历至最后一页,为 0 则不进行遍历。默认为 0。 - private static void EnumeratePages(YanderePage page, int enumCount = -1) + private static void EnumeratePageExtractAsync(YanderePage page, int enumCount = -1) { enumCount = (enumCount < 0) ? (page.Count - page.Index + 1) : ((enumCount == 0) ? 1 : enumCount); for (int i = page.Index; i < page.Index + enumCount; i++) { - ConsoleWindow.ExtractPage(page[i]); + ConsoleWindow.ExtractImageLinksAsync(page[i]); } } } diff --git a/YandereLinks/Views/MainWindow.xaml b/YandereLinks/Views/MainWindow.xaml index b575390..2ff5403 100644 --- a/YandereLinks/Views/MainWindow.xaml +++ b/YandereLinks/Views/MainWindow.xaml @@ -9,21 +9,14 @@ Height="720" Width="1280" MinHeight="450" MinWidth="800" WindowStartupLocation="CenterScreen" Title="{x:Static props:StringResources.MainWindow_Title}" Icon="../Properties/YandereLinks.ico" Loaded="ThisWindow_Loaded"> - - - - - - - - + @@ -45,19 +38,19 @@ - public partial class NaviWebBrowser : UserControl + public partial class NavigationWebBrowser : UserControl { /// - /// 初始化 类的新实例。 + /// 初始化 类。 /// - public NaviWebBrowser() + static NavigationWebBrowser() + { + NavigationWebBrowser.InitializeCommandBindings(); + } + + /// + /// 初始化 类的新实例。 + /// + public NavigationWebBrowser() { this.InitializeComponent(); - this.InitializeCommandBindings(); + this.InitializeComponentCommandBindings(); this.MainWebBrowser.Navigated += this.MainWebBrowser_Navigated; - this.MainWebBrowser.SuppressScriptErrors(true); } /// - /// 初始化当前用户控件的命令绑定。 + /// 初始化 的命令绑定。 /// - private void InitializeCommandBindings() + private static void InitializeCommandBindings() { - this.CommandBindings.AddRange(new[] + var commandBindings = new[] { new CommandBinding(NavigationCommands.BrowseBack, - (sender, e) => this.GoBack(), (sender, e) => e.CanExecute = this.CanGoBack), + (sender, e) => ((NavigationWebBrowser)sender).GoBack(), + (sender, e) => e.CanExecute = ((NavigationWebBrowser)sender).CanGoBack), new CommandBinding(NavigationCommands.BrowseForward, - (sender, e) => this.GoForward(), (sender, e) => e.CanExecute = this.CanGoForward), - new CommandBinding(NavigationCommands.BrowseHome, (senders, e) => this.GoHome()), + (sender, e) => ((NavigationWebBrowser)sender).GoForward(), + (sender, e) => e.CanExecute = ((NavigationWebBrowser)sender).CanGoForward), + new CommandBinding(NavigationCommands.BrowseHome, + (sender, e) => ((NavigationWebBrowser)sender).GoHome()), new CommandBinding(NavigationCommands.GoToPage, - (sender, e) => this.Navigate(e.Parameter as string)), - new CommandBinding(NavigationCommands.Refresh, (sender, e) => this.Refresh()), - }); + (sender, e) => ((NavigationWebBrowser)sender).Navigate(e.Parameter as string)), + new CommandBinding(NavigationCommands.Refresh, + (sender, e) => ((NavigationWebBrowser)sender).Refresh()), + }; + + foreach (var commandBinding in commandBindings) + { + CommandManager.RegisterClassCommandBinding(typeof(NavigationWebBrowser), commandBinding); + } + } + + /// + /// 初始化当前 所包含的组件的命令绑定。 + /// + private void InitializeComponentCommandBindings() + { this.SourceTextBox.CommandBindings.AddRange(new[] { new CommandBinding(EditingCommands.EnterParagraphBreak, @@ -47,61 +69,61 @@ private void InitializeCommandBindings() } /// - /// 表示 的依赖属性。 + /// 表示 的依赖属性。 /// public static readonly DependencyProperty CanGoBackProperty = - DependencyProperty.Register(nameof(NaviWebBrowser.CanGoBack), - typeof(bool), typeof(NaviWebBrowser), new PropertyMetadata(false)); + DependencyProperty.Register(nameof(NavigationWebBrowser.CanGoBack), + typeof(bool), typeof(NavigationWebBrowser), new PropertyMetadata(false)); + + /// + /// 后退到前一页面。 + /// + public void GoBack() => this.MainWebBrowser.GoBack(); /// /// 指示是否可以后退到前一页面。 /// public bool CanGoBack { - get => (bool)this.GetValue(NaviWebBrowser.CanGoBackProperty); - private set => this.SetValue(NaviWebBrowser.CanGoBackProperty, value); + get => (bool)this.GetValue(NavigationWebBrowser.CanGoBackProperty); + private set => this.SetValue(NavigationWebBrowser.CanGoBackProperty, value); } /// - /// 后退到前一页面。 + /// 表示 的依赖属性。 /// - public void GoBack() => this.MainWebBrowser.GoBack(); + public static readonly DependencyProperty CanGoForwardProperty = + DependencyProperty.Register(nameof(NavigationWebBrowser.CanGoForward), + typeof(bool), typeof(NavigationWebBrowser), new PropertyMetadata(false)); /// - /// 表示 的依赖属性。 + /// 前进到下一页面。 /// - public static readonly DependencyProperty CanGoForwardProperty = - DependencyProperty.Register(nameof(NaviWebBrowser.CanGoForward), - typeof(bool), typeof(NaviWebBrowser), new PropertyMetadata(false)); + public void GoForward() => this.MainWebBrowser.GoForward(); /// /// 指示是否可以前进到下一页面。 /// public bool CanGoForward { - get => (bool)this.GetValue(NaviWebBrowser.CanGoForwardProperty); - private set => this.SetValue(NaviWebBrowser.CanGoForwardProperty, value); + get => (bool)this.GetValue(NavigationWebBrowser.CanGoForwardProperty); + private set => this.SetValue(NavigationWebBrowser.CanGoForwardProperty, value); } /// - /// 前进到下一页面。 - /// - public void GoForward() => this.MainWebBrowser.GoForward(); - - /// - /// 表示 的依赖属性。 + /// 表示 的依赖属性。 /// public static readonly DependencyProperty HomeSourceProperty = - DependencyProperty.Register(nameof(NaviWebBrowser.HomeSource), - typeof(string), typeof(NaviWebBrowser), new PropertyMetadata(string.Empty)); + DependencyProperty.Register(nameof(NavigationWebBrowser.HomeSource), + typeof(string), typeof(NavigationWebBrowser), new PropertyMetadata(string.Empty)); /// /// 获取主页的链接文本。 /// public string HomeSource { - get => (string)this.GetValue(NaviWebBrowser.HomeSourceProperty); - set => this.SetValue(NaviWebBrowser.HomeSourceProperty, value); + get => (string)this.GetValue(NavigationWebBrowser.HomeSourceProperty); + set => this.SetValue(NavigationWebBrowser.HomeSourceProperty, value); } /// @@ -110,22 +132,22 @@ public string HomeSource public void GoHome() => this.MainWebBrowser.Navigate(this.HomeSource); /// - /// 表示 的依赖属性。 + /// 表示 的依赖属性。 /// public static readonly DependencyProperty SourceProperty = - DependencyProperty.Register(nameof(NaviWebBrowser.Source), - typeof(string), typeof(NaviWebBrowser), new PropertyMetadata(string.Empty, - NaviWebBrowser.SourceProperty_PropertyChanged)); + DependencyProperty.Register(nameof(NavigationWebBrowser.Source), + typeof(string), typeof(NavigationWebBrowser), new PropertyMetadata(string.Empty, + NavigationWebBrowser.OnSourcePropertyChanged)); /// - /// 依赖属性发生更改的事件处理。 + /// 依赖属性发生更改的事件处理。 /// - /// 包含依赖属性的 。 + /// 包含依赖属性的 。 /// 提供事件数据的对象。 - private static void SourceProperty_PropertyChanged( + private static void OnSourcePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { - if ((d is NaviWebBrowser navi) && (e.NewValue is string source)) + if ((d is NavigationWebBrowser navi) && (e.NewValue is string source)) { if (navi.MainWebBrowser.Source?.OriginalString != source) { @@ -139,8 +161,18 @@ public string HomeSource /// public string Source { - get => (string)this.GetValue(NaviWebBrowser.SourceProperty); - set => this.SetValue(NaviWebBrowser.SourceProperty, value); + get => (string)this.GetValue(NavigationWebBrowser.SourceProperty); + set => this.SetValue(NavigationWebBrowser.SourceProperty, value); + } + + /// + /// 显式更新链接文本框的数据源。 + /// + private void ExplicitUpdateSource() + { + this.SourceTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); + this.MainWebBrowser.Navigate(this.Source); + this.MainWebBrowser.Focus(); } /// @@ -180,16 +212,6 @@ public string Source remove => this.MainWebBrowser.LoadCompleted -= value; } - /// - /// 显式更新链接文本框的数据源。 - /// - private void ExplicitUpdateSource() - { - this.SourceTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); - this.MainWebBrowser.Navigate(this.Source); - this.MainWebBrowser.Focus(); - } - /// /// 网页浏览器导航完成的事件处理。 /// @@ -200,7 +222,8 @@ private void MainWebBrowser_Navigated(object sender, NavigationEventArgs e) this.CanGoBack = this.MainWebBrowser.CanGoBack; this.CanGoForward = this.MainWebBrowser.CanGoForward; this.Source = this.MainWebBrowser.Source?.OriginalString; - CommandManager.InvalidateRequerySuggested(); + this.Dispatcher.Invoke( + () => CommandManager.InvalidateRequerySuggested()); } } } diff --git a/YandereLinks/YandereLinks.csproj b/YandereLinks/YandereLinks.csproj index 7b2884a..a550c34 100644 --- a/YandereLinks/YandereLinks.csproj +++ b/YandereLinks/YandereLinks.csproj @@ -62,8 +62,6 @@ MSBuild:Compile Designer - - True True @@ -74,12 +72,11 @@ True Settings.settings - - NaviWebBrowser.xaml + + NavigationWebBrowser.xaml - @@ -100,7 +97,7 @@ MainWindow.xaml Code - + Designer MSBuild:Compile