From f92c4d874a2e753af6b2107cd23e22bf156641cb Mon Sep 17 00:00:00 2001 From: status102 <102887808+status102@users.noreply.github.com> Date: Sat, 7 Jun 2025 10:43:17 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20wpf=E5=B1=9E=E6=80=A7=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E7=AE=80=E5=8C=96=20(#12725)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 绑定合并 * perf: 循环依赖检查 * perf: 循环依赖检查 --- .../Utilities/PropertyDependsOnAttribute.cs | 33 +++++++++++ src/MaaWpfGui/ViewModels/TaskViewModel.cs | 59 +++++++++++++++++++ .../InfrastSettingsUserControlModel.cs | 3 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/MaaWpfGui/Utilities/PropertyDependsOnAttribute.cs diff --git a/src/MaaWpfGui/Utilities/PropertyDependsOnAttribute.cs b/src/MaaWpfGui/Utilities/PropertyDependsOnAttribute.cs new file mode 100644 index 0000000000..114b083819 --- /dev/null +++ b/src/MaaWpfGui/Utilities/PropertyDependsOnAttribute.cs @@ -0,0 +1,33 @@ +// +// MaaWpfGui - A part of the MaaCoreArknights project +// Copyright (C) 2021 MistEO and Contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License v3.0 only as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY +// + +#nullable enable +using System; + +namespace MaaWpfGui.Utilities; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] +public class PropertyDependsOnAttribute : Attribute +{ + public PropertyDependsOnAttribute(string propertyName) + { + PropertyNames = [propertyName]; + } + + public PropertyDependsOnAttribute(string propertyName, params string[] propertyNames) + { + PropertyNames = [propertyName, .. propertyNames]; + } + + public string[] PropertyNames { get; init; } +} diff --git a/src/MaaWpfGui/ViewModels/TaskViewModel.cs b/src/MaaWpfGui/ViewModels/TaskViewModel.cs index 6ebfc81a46..f35578dc77 100644 --- a/src/MaaWpfGui/ViewModels/TaskViewModel.cs +++ b/src/MaaWpfGui/ViewModels/TaskViewModel.cs @@ -12,8 +12,13 @@ // #nullable enable using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; using MaaWpfGui.Main; using MaaWpfGui.Services; +using MaaWpfGui.Utilities; using Newtonsoft.Json.Linq; using Stylet; @@ -21,6 +26,60 @@ namespace MaaWpfGui.ViewModels; public abstract class TaskViewModel : PropertyChangedBase { + private readonly Dictionary> _propertyDependencies = []; // 属性依赖关系, key为被订阅的属性名, value为依赖于该属性的属性名列表 + + protected TaskViewModel() + { + InitializePropertyDependencies(); + } + + /// + /// 初始化属性依赖关系 + /// + private void InitializePropertyDependencies() + { + var type = GetType(); + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + + foreach (var property in properties) + { + var dependsOnAttributes = property.GetCustomAttributes(true); + foreach (var attribute in dependsOnAttributes.Where(i => i.PropertyNames.Length > 0)) + { + foreach (var key in attribute.PropertyNames) + { + if (!_propertyDependencies.TryGetValue(key, out var value)) + { + value = []; + _propertyDependencies[key] = value; + } + + if (_propertyDependencies.TryGetValue(property.Name, out var values) && values.Contains(key)) + { + throw new ArgumentException($"属性 {key} 依赖于属性 {property.Name}, 但它们之间存在循环依赖关系"); + } + + value.Add(property.Name); + } + } + } + + PropertyChanged += OnPropertyChanged; + } + + private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (string.IsNullOrEmpty(e.PropertyName) || !_propertyDependencies.TryGetValue(e.PropertyName, out var value)) + { + return; + } + + foreach (var dependentProperty in value) + { + NotifyOfPropertyChange(dependentProperty); + } + } + public virtual void ProcSubTaskMsg(AsstMsg msg, JObject details) { } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs index f170b1c2b0..e120c0c55c 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs @@ -22,6 +22,7 @@ using MaaWpfGui.Helper; using MaaWpfGui.Models; using MaaWpfGui.Models.AsstTasks; using MaaWpfGui.Services; +using MaaWpfGui.Utilities; using MaaWpfGui.Utilities.ValueType; using MaaWpfGui.ViewModels.UI; using Microsoft.Win32; @@ -317,11 +318,11 @@ public class InfrastSettingsUserControlModel : TaskViewModel CustomInfrastFile = @"resource\custom_infrast\" + value; } - NotifyOfPropertyChange(nameof(IsCustomInfrastFileReadOnly)); ConfigurationHelper.SetValue(ConfigurationKeys.DefaultInfrast, value); } } + [PropertyDependsOn(nameof(DefaultInfrast))] public bool IsCustomInfrastFileReadOnly => _defaultInfrast != UserDefined; private bool _dormFilterNotStationedEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.DormFilterNotStationedEnabled, bool.TrueString));