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));