diff --git a/VPet.Solution/Models/SettingEditor/GraphicsSettingModel.cs b/VPet.Solution/Models/SettingEditor/GraphicsSettingModel.cs index 983c2ab..2dc815c 100644 --- a/VPet.Solution/Models/SettingEditor/GraphicsSettingModel.cs +++ b/VPet.Solution/Models/SettingEditor/GraphicsSettingModel.cs @@ -1,4 +1,6 @@ using HKW.HKWUtils.Observable; +using LinePutScript.Localization.WPF; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows; @@ -6,13 +8,14 @@ namespace VPet.Solution.Models.SettingEditor; public class GraphicsSettingModel : ObservableClass { - #region + #region ZoomLevel private double _zoomLevel = 1; /// /// 缩放倍率 /// [DefaultValue(1)] + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.ZoomLevel))] public double ZoomLevel { get => _zoomLevel; @@ -37,23 +40,29 @@ public class GraphicsSettingModel : ObservableClass set => SetProperty(ref _zoomLevelMaximum, value); } #endregion + + #region Resolution private int _resolution = 1000; /// /// 桌宠图形渲染的分辨率,越高图形越清晰 /// [DefaultValue(1000)] + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.Resolution))] public int Resolution { get => _resolution; set => SetProperty(ref _resolution, value); } + #endregion + #region IsBiggerScreen private bool _isBiggerScreen; /// /// 是否为更大的屏幕 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.IsBiggerScreen))] public bool IsBiggerScreen { get => _isBiggerScreen; @@ -66,94 +75,125 @@ public class GraphicsSettingModel : ObservableClass ZoomLevelMaximum = 3; } } + #endregion + #region TopMost private bool _topMost; /// /// 是否置于顶层 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.TopMost))] public bool TopMost { get => _topMost; set => SetProperty(ref _topMost, value); } + #endregion + #region HitThrough private bool _hitThrough; /// /// 是否鼠标穿透 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.HitThrough))] public bool HitThrough { get => _hitThrough; set => SetProperty(ref _hitThrough, value); } + #endregion - private string _language; + #region Language + private string _language = Languages.First(); /// /// 语言 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.Language))] public string Language { get => _language; set => SetProperty(ref _language, value); } + + public static ObservableCollection Languages { get; } = + new() { "zh-Hans", "zh-Hant", "en" }; + // NOTE: 实际上这里面并没有文化 new(LocalizeCore.AvailableCultures); + + #endregion + + #region Font private string _font; /// /// 字体 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.Font))] public string Font { get => _font; set => SetProperty(ref _font, value); } + #endregion + + #region Theme private string _theme; /// /// 主题 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.Theme))] public string Theme { get => _theme; set => SetProperty(ref _theme, value); } + #endregion + #region StartUPBoot private bool _startUPBoot; /// /// 开机启动 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.StartUPBoot))] public bool StartUPBoot { get => _startUPBoot; set => SetProperty(ref _startUPBoot, value); } + #endregion + #region StartUPBootSteam private bool _startUPBootSteam; /// /// 开机启动 Steam /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.StartUPBootSteam))] public bool StartUPBootSteam { get => _startUPBootSteam; set => SetProperty(ref _startUPBootSteam, value); } + #endregion + #region StartRecordLast private bool _startRecordLast = true; /// /// 是否记录游戏退出位置 /// [DefaultValue(true)] + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.StartRecordLast))] public bool StartRecordLast { get => _startRecordLast; set => SetProperty(ref _startRecordLast, value); } - + #endregion //private Point _startRecordLastPoint; ///// @@ -165,26 +205,32 @@ public class GraphicsSettingModel : ObservableClass // set => SetProperty(ref _startRecordLastPoint, value); //} + #region StartRecordPoint private ObservablePoint _startRecordPoint; /// /// 设置中桌宠启动的位置 /// - [ReflectionPropertyInfo(typeof(ObservablePointToPointConverter))] + [ReflectionProperty] + [ReflectionPropertyConverter(typeof(ObservablePointToPointConverter))] public ObservablePoint StartRecordPoint { get => _startRecordPoint; set => SetProperty(ref _startRecordPoint, value); } + #endregion + #region HideFromTaskControl private bool _hideFromTaskControl; /// /// 在任务切换器(Alt+Tab)中隐藏窗口 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.HideFromTaskControl))] public bool HideFromTaskControl { get => _hideFromTaskControl; set => SetProperty(ref _hideFromTaskControl, value); } + #endregion } diff --git a/VPet.Solution/Models/SettingEditor/InteractiveSettingModel.cs b/VPet.Solution/Models/SettingEditor/InteractiveSettingModel.cs index 50e0f61..5815bdb 100644 --- a/VPet.Solution/Models/SettingEditor/InteractiveSettingModel.cs +++ b/VPet.Solution/Models/SettingEditor/InteractiveSettingModel.cs @@ -1,251 +1,328 @@ using HKW.HKWUtils.Observable; +using System.Collections.ObjectModel; using VPet_Simulator.Core; namespace VPet.Solution.Models.SettingEditor; public class InteractiveSettingModel : ObservableClass { - private string _petName; + // NOTE: 这玩意其实在存档里 而不是设置里 + //#region PetName + //private string _petName; - /// - /// 宠物名称 - /// - public string PetName - { - get => _petName; - set => SetProperty(ref _petName, value); - } + ///// + ///// 宠物名称 + ///// + //[ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PetName))] + //public string PetName + //{ + // get => _petName; + // set => SetProperty(ref _petName, value); + //} + //#endregion + #region VoiceVolume private double _voiceVolume; /// /// 播放声音大小 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.VoiceVolume))] public double VoiceVolume { get => _voiceVolume; set => SetProperty(ref _voiceVolume, value); } + #endregion + #region CalFunState private GameSave.ModeType _calFunState; /// /// 非计算模式下默认模式 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.CalFunState))] public GameSave.ModeType CalFunState { get => _calFunState; set => SetProperty(ref _calFunState, value); } + public ObservableCollection ModeTypes { get; } = + new(Enum.GetValues(typeof(GameSave.ModeType)).Cast()); + #endregion + + #region PetHelper private bool _petHelper; /// /// 是否显示宠物帮助窗口 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PetHelper))] public bool PetHelper { get => _petHelper; set => SetProperty(ref _petHelper, value); } + #endregion + #region LastCacheDate private DateTime _lastCacheDate; /// /// 上次清理缓存日期 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.LastCacheDate))] public DateTime LastCacheDate { get => _lastCacheDate; set => SetProperty(ref _lastCacheDate, value); } + #endregion + #region SaveTimes private int _saveTimes; /// /// 储存顺序次数 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.SaveTimes))] public int SaveTimes { get => _saveTimes; set => SetProperty(ref _saveTimes, value); } + #endregion + #region PressLength private int _pressLength; /// /// 按多久视为长按 单位毫秒 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PressLength))] public int PressLength { get => _pressLength; set => SetProperty(ref _pressLength, value); } + #endregion + #region InteractionCycle private int _interactionCycle; /// /// 互动周期 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.InteractionCycle))] public int InteractionCycle { get => _interactionCycle; set => SetProperty(ref _interactionCycle, value); } + #endregion + #region LogicInterval private double _logicInterval; /// /// 计算间隔 (秒) /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.LogicInterval))] public double LogicInterval { get => _logicInterval; set => SetProperty(ref _logicInterval, value); } + #endregion + #region PetHelpLeft private double _petHelpLeft; /// /// 计算间隔 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PetHelpLeft))] public double PetHelpLeft { get => _petHelpLeft; set => SetProperty(ref _petHelpLeft, value); } + #endregion + #region PetHelpTop private double _petHelpTop; /// /// 计算间隔 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PetHelpTop))] public double PetHelpTop { get => _petHelpTop; set => SetProperty(ref _petHelpTop, value); } + #endregion + #region AllowMove private bool _allowMove; /// /// 允许移动事件 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.AllowMove))] public bool AllowMove { get => _allowMove; set => SetProperty(ref _allowMove, value); } + #endregion + #region SmartMove private bool _smartMove; /// /// 智能移动 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.SmartMove))] public bool SmartMove { get => _smartMove; set => SetProperty(ref _smartMove, value); } + #endregion + #region EnableFunction private bool _enableFunction; /// /// 启用计算等数据功能 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.EnableFunction))] public bool EnableFunction { get => _enableFunction; set => SetProperty(ref _enableFunction, value); } + #endregion + #region SmartMoveInterval private int _smartMoveInterval; /// /// 智能移动周期 (秒) /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.SmartMoveInterval))] public int SmartMoveInterval { get => _smartMoveInterval; set => SetProperty(ref _smartMoveInterval, value); } + #endregion + #region MessageBarOutside private bool _messageBarOutside; /// /// 消息框外置 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.MessageBarOutside))] public bool MessageBarOutside { get => _messageBarOutside; set => SetProperty(ref _messageBarOutside, value); } + #endregion + #region PetGraph private string _petGraph; /// /// 桌宠选择内容 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.PetGraph))] public string PetGraph { get => _petGraph; set => SetProperty(ref _petGraph, value); } + #endregion + #region MusicCatch private double _musicCatch; /// /// 当实时播放音量达到该值时运行音乐动作 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.MusicCatch))] public double MusicCatch { get => _musicCatch; set => SetProperty(ref _musicCatch, value); } + #endregion + #region MusicMax private double _musicMax; /// /// 当实时播放音量达到该值时运行特殊音乐动作 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.MusicMax))] public double MusicMax { get => _musicMax; set => SetProperty(ref _musicMax, value); } + #endregion + #region AutoBuy private bool _autoBuy; /// /// 允许桌宠自动购买食品 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.AutoBuy))] public bool AutoBuy { get => _autoBuy; set => SetProperty(ref _autoBuy, value); } + #endregion + #region AutoGift private bool _autoGift; /// /// 允许桌宠自动购买礼物 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.AutoGift))] public bool AutoGift { get => _autoGift; set => SetProperty(ref _autoGift, value); } + #endregion + #region MoveAreaDefault private bool _moveAreaDefault; + + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.MoveAreaDefault))] public bool MoveAreaDefault { get => _moveAreaDefault; set => SetProperty(ref _moveAreaDefault, value); } + #endregion + + #region MoveArea private System.Drawing.Rectangle _moveArea; + + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.MoveArea))] public System.Drawing.Rectangle MoveArea { get => _moveArea; set => SetProperty(ref _moveArea, value); } + #endregion } diff --git a/VPet.Solution/Models/SettingEditor/SettingModel.cs b/VPet.Solution/Models/SettingEditor/SettingModel.cs index 1dcf46f..fc0c552 100644 --- a/VPet.Solution/Models/SettingEditor/SettingModel.cs +++ b/VPet.Solution/Models/SettingEditor/SettingModel.cs @@ -12,35 +12,26 @@ namespace VPet.Solution.Models.SettingEditor; public class SettingModel : ObservableClass { - private string _name; - /// /// 名称 /// - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } - - private string _filePath; + public string Name { get; set; } /// /// 文件路径 /// - public string FilePath - { - get => _filePath; - set => SetProperty(ref _filePath, value); - } + public string FilePath { get; set; } + #region GraphicsSetting private GraphicsSettingModel _graphicsSetting; public GraphicsSettingModel GraphicsSetting { get => _graphicsSetting; set => SetProperty(ref _graphicsSetting, value); } + #endregion + #region SystemSetting private SystemSettingModel _systemSetting; public SystemSettingModel SystemSetting @@ -48,13 +39,16 @@ public class SettingModel : ObservableClass get => _systemSetting; set => SetProperty(ref _systemSetting, value); } + #endregion + #region InteractiveSetting private InteractiveSettingModel _interactiveSetting; public InteractiveSettingModel InteractiveSetting { get => _interactiveSetting; set => SetProperty(ref _interactiveSetting, value); } + #endregion private static HashSet _settingProperties = new(typeof(Setting).GetProperties().Select(p => p.Name)); @@ -63,27 +57,35 @@ public class SettingModel : ObservableClass private ReflectionOptions _saveReflectionOptions = new() { CheckValueEquals = true }; + public SettingModel() + : this(new("")) { } + public SettingModel(Setting setting) { _setting = setting; - GraphicsSetting = LoadGraphicsSettings(); + GraphicsSetting = LoadSetting(); + InteractiveSetting = LoadSetting(); + SystemSetting = LoadSetting(); } - private GraphicsSettingModel LoadGraphicsSettings() + private T LoadSetting() + where T : new() { - var graphicsSetting = new GraphicsSettingModel(); - ReflectionUtils.SetValue(_setting, graphicsSetting); - return graphicsSetting; + var setting = new T(); + ReflectionUtils.SetValue(_setting, setting); + return setting; } public void Save() { - SaveGraphicsSettings(); + SaveSetting(GraphicsSetting); + SaveSetting(InteractiveSetting); + SaveSetting(SystemSetting); File.WriteAllText(FilePath, _setting.ToString()); } - private void SaveGraphicsSettings() + private void SaveSetting(object setting) { - ReflectionUtils.SetValue(GraphicsSetting, _setting, _saveReflectionOptions); + ReflectionUtils.SetValue(setting, _setting, _saveReflectionOptions); } } diff --git a/VPet.Solution/Models/SettingEditor/SystemSettingModel.cs b/VPet.Solution/Models/SettingEditor/SystemSettingModel.cs index 2386dd0..e5c5394 100644 --- a/VPet.Solution/Models/SettingEditor/SystemSettingModel.cs +++ b/VPet.Solution/Models/SettingEditor/SystemSettingModel.cs @@ -1,4 +1,6 @@ -namespace VPet.Solution.Models.SettingEditor; +using System.Collections.ObjectModel; + +namespace VPet.Solution.Models.SettingEditor; public class SystemSettingModel : ObservableClass { @@ -7,47 +9,62 @@ public class SystemSettingModel : ObservableClass /// public bool DiagnosisDayEnable { get; } = true; + #region Diagnosis private bool _diagnosis; /// /// 是否启用数据收集 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.Diagnosis))] public bool Diagnosis { get => _diagnosis; set => SetProperty(ref _diagnosis, value); } + #endregion + #region DiagnosisInterval private int _diagnosisInterval; /// /// 数据收集频率 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.DiagnosisInterval))] public int DiagnosisInterval { get => _diagnosisInterval; set => SetProperty(ref _diagnosisInterval, value); } + #endregion + #region AutoSaveInterval private int _autoSaveInterval; /// /// 自动保存频率 (min) /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.AutoSaveInterval))] public int AutoSaveInterval { get => _autoSaveInterval; set => SetProperty(ref _autoSaveInterval, value); } + public static ObservableCollection SaveIntervals { get; } = + new() { -1, 2, 5, 10, 20, 30, 60 }; + #endregion + + #region BackupSaveMaxNum private int _backupSaveMaxNum; /// /// 备份保存最大数量 /// + [ReflectionProperty(nameof(VPet_Simulator.Windows.Interface.Setting.BackupSaveMaxNum))] public int BackupSaveMaxNum { get => _backupSaveMaxNum; set => SetProperty(ref _backupSaveMaxNum, value); } + #endregion } diff --git a/VPet.Solution/Utils/ReflectionUtils.cs b/VPet.Solution/Utils/ReflectionUtils.cs index 5358bb4..3bedeca 100644 --- a/VPet.Solution/Utils/ReflectionUtils.cs +++ b/VPet.Solution/Utils/ReflectionUtils.cs @@ -11,8 +11,11 @@ namespace HKW.HKWUtils; public static class ReflectionUtils { + private static readonly BindingFlags _propertyBindingFlags = + BindingFlags.Instance | BindingFlags.Public; + /// - /// 目标名称 + /// 类型信息 /// /// (TargetType, (PropertyName, TargetPropertyName)) /// @@ -20,15 +23,11 @@ public static class ReflectionUtils private static readonly Dictionary _typePropertyReflectionInfos = new(); - public static void SetValue( - TSource source, - TTarget target, - ReflectionOptions options = null! - ) + public static void SetValue(object source, object target, ReflectionOptions options = null!) { options ??= new(); - var sourceType = typeof(TSource); - var targetType = typeof(TTarget); + var sourceType = source.GetType(); + var targetType = target.GetType(); if (_typePropertyReflectionInfos.TryGetValue(sourceType, out var sourceInfo) is false) sourceInfo = _typePropertyReflectionInfos[sourceType] = GetReflectionObjectInfo( sourceType @@ -41,24 +40,23 @@ public static class ReflectionUtils var sourceAccessor = ObjectAccessor.Create(source); var targetAccessor = ObjectAccessor.Create(target); - foreach (var property in sourceType.GetProperties()) + foreach (var property in targetType.GetProperties(_propertyBindingFlags)) { + // 尝试获取目标属性信息 + targetInfo.PropertyInfos.TryGetValue(property.Name, out var targetReflectionInfo); // 获取源属性名 - var sourcePropertyName = sourceInfo.PropertyInfos.TryGetValue( - property.Name, - out var sourceReflectionInfo - ) - ? sourceReflectionInfo.PropertyName - : property.Name; - if (targetInfo.PropertyNames.Contains(sourcePropertyName) is false) + var sourcePropertyName = targetReflectionInfo is null + ? property.Name + : targetReflectionInfo.TargetName; + // 获取源属性信息 + sourceInfo.PropertyInfos.TryGetValue(sourcePropertyName, out var sourceReflectionInfo); + if (sourceInfo.PropertyNames.Contains(sourcePropertyName) is false) + { + if (targetReflectionInfo?.IsRequired is true) + options.UnassignedRequiredProperties.Add(property.Name); continue; - // 获取目标属性名 - var targetPropertyName = targetInfo.PropertyInfos.TryGetValue( - sourcePropertyName, - out var targetReflectionInfo - ) - ? targetReflectionInfo.PropertyName - : property.Name; + } + // 获取源值 var sourceValue = sourceAccessor[sourcePropertyName]; // 转换源值 @@ -69,26 +67,44 @@ public static class ReflectionUtils // 比较源值和目标值 if (options.CheckValueEquals) { - var targetValue = targetAccessor[targetPropertyName]; + var targetValue = targetAccessor[property.Name]; if (sourceValue.Equals(targetValue)) continue; } - targetAccessor[targetPropertyName] = sourceValue; + targetAccessor[property.Name] = sourceValue; } } private static ReflectionObjectInfo GetReflectionObjectInfo(Type type) { var objectInfo = new ReflectionObjectInfo(type); - foreach (var property in type.GetProperties()) + foreach (var property in type.GetProperties(_propertyBindingFlags)) { - if (property.IsDefined(typeof(ReflectionPropertyInfoAttribute))) + if ( + property.IsDefined(typeof(ReflectionPropertyAttribute)) is false + && property.IsDefined(typeof(ReflectionPropertyConverterAttribute)) is false + ) + continue; + var propertyInfo = new ReflectionPropertyInfo(property.Name); + // 获取属性信息 + if ( + property.GetCustomAttribute() + is ReflectionPropertyAttribute propertyInfoAttribute + ) { - var reflectionInfo = property.GetCustomAttribute(); - if (string.IsNullOrWhiteSpace(reflectionInfo.PropertyName)) - reflectionInfo.PropertyName = property.Name; - objectInfo.PropertyInfos[property.Name] = reflectionInfo; + if (string.IsNullOrWhiteSpace(propertyInfoAttribute.TargetName) is false) + propertyInfo.TargetName = propertyInfoAttribute.TargetName; + propertyInfo.IsRequired = propertyInfoAttribute.IsRequired; } + // 获取属性转换器 + if ( + property.GetCustomAttribute() + is ReflectionPropertyConverterAttribute propertyConverterAttribute + ) + { + propertyInfo.Converter = propertyConverterAttribute.Converter; + } + objectInfo.PropertyInfos[property.Name] = propertyInfo; } return objectInfo; } @@ -101,7 +117,7 @@ public class ReflectionObjectInfo { public HashSet PropertyNames { get; } - public Dictionary PropertyInfos { get; } = new(); + public Dictionary PropertyInfos { get; } = new(); public ReflectionObjectInfo(Type type) { @@ -109,29 +125,72 @@ public class ReflectionObjectInfo } } -/// -/// 反射属性信息 -/// -public class ReflectionPropertyInfoAttribute : Attribute +public class ReflectionPropertyInfo { /// /// 目标属性名称 /// - public string PropertyName { get; set; } + public string TargetName { get; set; } + /// + /// 是必要的 + /// + [DefaultValue(true)] + public bool IsRequired { get; set; } = true; + + /// + /// 反射值转换器 + /// + public IReflectionConverter? Converter { get; set; } = null; + + public ReflectionPropertyInfo(string propertyName) + { + TargetName = propertyName; + } +} + +/// +/// 反射属性信息 +/// +[AttributeUsage(AttributeTargets.Property)] +public class ReflectionPropertyAttribute : Attribute +{ + /// + /// 属性名称 + /// + public string TargetName { get; } + + /// + /// 是必要的 + /// + [DefaultValue(true)] + public bool IsRequired { get; } = true; + + public ReflectionPropertyAttribute(bool isRequired = true) + { + IsRequired = isRequired; + } + + public ReflectionPropertyAttribute(string name, bool isRequired = true) + { + TargetName = name; + IsRequired = isRequired; + } +} + +/// +/// 反射属性转换器 +/// +[AttributeUsage(AttributeTargets.Property)] +public class ReflectionPropertyConverterAttribute : Attribute +{ /// /// 反射转换器 /// - public IReflectionConverter? Converter { get; } = null; + public IReflectionConverter Converter { get; } - public ReflectionPropertyInfoAttribute(Type converterType) - : this(string.Empty, converterType) { } - - public ReflectionPropertyInfoAttribute(string name, Type? converterType = null) + public ReflectionPropertyConverterAttribute(Type converterType) { - PropertyName = name; - if (converterType is null) - return; Converter = (IReflectionConverter)TypeAccessor.Create(converterType).CreateNew(); } } @@ -146,6 +205,11 @@ public class ReflectionOptions /// [DefaultValue(false)] public bool CheckValueEquals { get; set; } = false; + + /// + /// 未赋值的必要属性 + /// + public List UnassignedRequiredProperties { get; set; } = new(); } /// diff --git a/VPet.Solution/Utils/Utils.cs b/VPet.Solution/Utils/Utils.cs index 367f70c..0e4e157 100644 --- a/VPet.Solution/Utils/Utils.cs +++ b/VPet.Solution/Utils/Utils.cs @@ -77,6 +77,13 @@ public static class Utils return bitmapImage; } + /// + /// 获取布尔值 + /// + /// 值 + /// 目标布尔值 + /// 为空时布尔值 + /// public static bool GetBool(object value, bool boolValue, bool nullValue) { if (value is null) @@ -88,4 +95,26 @@ public static class Utils else return false; } + + /// + /// 打开文件 + /// + /// 文件路径 + public static void OpenFile(string filePath) + { + System.Diagnostics.Process + .Start(new System.Diagnostics.ProcessStartInfo(filePath) { UseShellExecute = true }) + ?.Close(); + } + + /// + /// 从资源管理器打开文件 + /// + /// 文件路径 + public static void OpenFileInExplorer(string filePath) + { + System.Diagnostics.Process + .Start("Explorer", $"/select,{Path.GetFullPath(filePath)}") + ?.Close(); + } } diff --git a/VPet.Solution/ViewModels/SettingEditor/InteractiveSettingPageVM.cs b/VPet.Solution/ViewModels/SettingEditor/InteractiveSettingPageVM.cs index d368ebb..2eda9c8 100644 --- a/VPet.Solution/ViewModels/SettingEditor/InteractiveSettingPageVM.cs +++ b/VPet.Solution/ViewModels/SettingEditor/InteractiveSettingPageVM.cs @@ -24,7 +24,10 @@ public class InteractiveSettingPageVM : ObservableClass #endregion #region Command + /// + /// 打开文件 + /// + public ObservableCommand OpenFileCommand { get; } = new(); + + /// + /// 从资源管理器打开 + /// + public ObservableCommand OpenFileInExplorerCommand { get; } = new(); + + /// + /// 重置 + /// public ObservableCommand ResetSettingCommand { get; } = new(); + + /// + /// 保存 + /// public ObservableCommand SaveSettingCommand { get; } = new(); + + /// + /// 保存全部 + /// public ObservableCommand SaveAllSettingCommand { get; } = new(); #endregion public SettingWindowVM() @@ -59,15 +80,37 @@ public class SettingWindowVM : ObservableClass foreach (var s in LoadSettings()) _settings.Add(s); - PropertyChanged += MainWindowVM_PropertyChanged; + OpenFileCommand.ExecuteCommand += OpenFileCommand_ExecuteCommand; + OpenFileInExplorerCommand.ExecuteCommand += OpenFileInExplorerCommand_ExecuteCommand; ResetSettingCommand.ExecuteCommand += ResetSettingCommand_ExecuteCommand; SaveSettingCommand.ExecuteCommand += SaveSettingCommand_ExecuteCommand; SaveAllSettingCommand.ExecuteCommand += SaveAllSettingCommand_ExecuteCommand; } + private void OpenFileInExplorerCommand_ExecuteCommand(SettingModel parameter) + { + Utils.OpenFileInExplorer(parameter.FilePath); + } + + private void OpenFileCommand_ExecuteCommand(SettingModel parameter) + { + Utils.OpenFile(parameter.FilePath); + } + private void SaveAllSettingCommand_ExecuteCommand() { + if ( + MessageBox.Show( + SettingWindow.Instance, + "确定全部保存吗".Translate(), + "", + MessageBoxButton.YesNo, + MessageBoxImage.Warning + ) + is not MessageBoxResult.Yes + ) + return; foreach (var setting in _settings) setting.Save(); } @@ -90,9 +133,7 @@ public class SettingWindowVM : ObservableClass is not MessageBoxResult.Yes ) return; - CurrentSetting = _settings[_settings.IndexOf(CurrentSetting)] = new SettingModel( - new Setting("") - ) + CurrentSetting = _settings[_settings.IndexOf(CurrentSetting)] = new SettingModel() { Name = CurrentSetting.Name, FilePath = CurrentSetting.FilePath diff --git a/VPet.Solution/ViewModels/SettingEditor/SystemSettingPageVM.cs b/VPet.Solution/ViewModels/SettingEditor/SystemSettingPageVM.cs index 2055e24..9556195 100644 --- a/VPet.Solution/ViewModels/SettingEditor/SystemSettingPageVM.cs +++ b/VPet.Solution/ViewModels/SettingEditor/SystemSettingPageVM.cs @@ -11,12 +11,15 @@ namespace VPet.Solution.ViewModels.SettingEditor; public class SystemSettingPageVM : ObservableClass { + #region SystemSetting + private SystemSettingModel _systemSetting; public SystemSettingModel SystemSetting { get => _systemSetting; set => SetProperty(ref _systemSetting, value); } + #endregion public SystemSettingPageVM() { @@ -25,7 +28,10 @@ public class SystemSettingPageVM : ObservableClass private void Current_PropertyChangedX(SettingWindowVM sender, PropertyChangedXEventArgs e) { - if (e.PropertyName == nameof(SettingWindowVM.CurrentSetting)) + if ( + e.PropertyName == nameof(SettingWindowVM.CurrentSetting) + && sender.CurrentSetting is not null + ) { SystemSetting = sender.CurrentSetting.SystemSetting; } diff --git a/VPet.Solution/Views/SettingEditor/CustomizedSettingPage.xaml.cs b/VPet.Solution/Views/SettingEditor/CustomizedSettingPage.xaml.cs index bb84e2b..5aedf93 100644 --- a/VPet.Solution/Views/SettingEditor/CustomizedSettingPage.xaml.cs +++ b/VPet.Solution/Views/SettingEditor/CustomizedSettingPage.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using VPet.Solution.ViewModels.SettingEditor; namespace VPet.Solution.Views.SettingEditor; @@ -20,8 +21,11 @@ namespace VPet.Solution.Views.SettingEditor; /// public partial class CustomizedSettingPage : Page { + public CustomizedSettingPageVM ViewModel => (CustomizedSettingPageVM)DataContext; + public CustomizedSettingPage() { InitializeComponent(); + this.SetViewModel(); } } diff --git a/VPet.Solution/Views/SettingEditor/DiagnosticSettingPage.xaml.cs b/VPet.Solution/Views/SettingEditor/DiagnosticSettingPage.xaml.cs index 917e74b..add4b88 100644 --- a/VPet.Solution/Views/SettingEditor/DiagnosticSettingPage.xaml.cs +++ b/VPet.Solution/Views/SettingEditor/DiagnosticSettingPage.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using VPet.Solution.ViewModels.SettingEditor; namespace VPet.Solution.Views.SettingEditor; @@ -20,8 +21,11 @@ namespace VPet.Solution.Views.SettingEditor; /// public partial class DiagnosticSettingPage : Page { + public DiagnosticSettingPageVM ViewModel => (DiagnosticSettingPageVM)DataContext; + public DiagnosticSettingPage() { InitializeComponent(); + this.SetViewModel(); } } diff --git a/VPet.Solution/Views/SettingEditor/GraphicsSettingPage.xaml b/VPet.Solution/Views/SettingEditor/GraphicsSettingPage.xaml index f58d0de..dc250cb 100644 --- a/VPet.Solution/Views/SettingEditor/GraphicsSettingPage.xaml +++ b/VPet.Solution/Views/SettingEditor/GraphicsSettingPage.xaml @@ -153,7 +153,8 @@ ToolTip="{ll:Str '桌宠图形渲染的分辨率,越高图形越清晰\ 但是高分辨率会占用更多内存\ 重启后生效'}" Value="{Binding Value, ElementName=Slider_Resolution}" /> - + + diff --git a/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml b/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml index 189eade..a61bbb7 100644 --- a/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml +++ b/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml @@ -24,7 +24,8 @@ FontSize="16" FontWeight="Bold" Style="{DynamicResource Label_BaseStyle}" /> - + + @@ -55,15 +56,10 @@ Grid.Column="2" pu:ComboBoxHelper.Watermark="{ll:Str '当关闭数据计算时\ 桌宠显示的状态'}" IsEnabled="{Binding IsChecked, ElementName=Switch_EnablePetState, Converter={StaticResource BoolInverter}}" - SelectedIndex="0" + ItemsSource="{Binding InteractiveSetting.ModeTypes}" SelectedItem="{Binding InteractiveSetting.CalFunState}" Style="{DynamicResource ComboBox_BaseStyle}" - ToolTip="{ll:Str '当关闭数据计算时\ 桌宠显示的状态'}"> - - - - - + ToolTip="{ll:Str '当关闭数据计算时\ 桌宠显示的状态'}" /> @@ -376,7 +372,7 @@ Maximum="100" Minimum="{Binding ElementName=VoiceCatchSilder, Path=Value}" SmallChange="1" - Style="{DynamicResource StandardSliderStyle}" + Style="{DynamicResource Slider_BaseStyle}" TickFrequency="1" ToolTip="{ll:Str 当实时播放音量达到该值时运行特殊音乐动作}" Value="75" /> diff --git a/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml.cs b/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml.cs index a777556..1ebffcd 100644 --- a/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml.cs +++ b/VPet.Solution/Views/SettingEditor/InteractiveSettingPage.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using VPet.Solution.ViewModels.SettingEditor; namespace VPet.Solution.Views.SettingEditor; @@ -20,8 +21,11 @@ namespace VPet.Solution.Views.SettingEditor; /// public partial class InteractiveSettingPage : Page { + public InteractiveSettingPageVM ViewModel => (InteractiveSettingPageVM)DataContext; + public InteractiveSettingPage() { InitializeComponent(); + this.SetViewModel(); } } diff --git a/VPet.Solution/Views/SettingEditor/ModSettingPage.xaml.cs b/VPet.Solution/Views/SettingEditor/ModSettingPage.xaml.cs index 269a496..3c22d77 100644 --- a/VPet.Solution/Views/SettingEditor/ModSettingPage.xaml.cs +++ b/VPet.Solution/Views/SettingEditor/ModSettingPage.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using VPet.Solution.ViewModels.SettingEditor; namespace VPet.Solution.Views.SettingEditor; @@ -20,8 +21,11 @@ namespace VPet.Solution.Views.SettingEditor; /// public partial class ModSettingPage : Page { + public ModSettingPageVM ViewModel => (ModSettingPageVM)DataContext; + public ModSettingPage() { InitializeComponent(); + this.SetViewModel(); } } diff --git a/VPet.Solution/Views/SettingEditor/SettingWindow.xaml b/VPet.Solution/Views/SettingEditor/SettingWindow.xaml index 3af0e6a..d77bf9b 100644 --- a/VPet.Solution/Views/SettingEditor/SettingWindow.xaml +++ b/VPet.Solution/Views/SettingEditor/SettingWindow.xaml @@ -44,14 +44,22 @@ - + + + diff --git a/VPet.Solution/Views/SettingEditor/SystemSettingPage.xaml b/VPet.Solution/Views/SettingEditor/SystemSettingPage.xaml index 8671ba3..b27e0ce 100644 --- a/VPet.Solution/Views/SettingEditor/SystemSettingPage.xaml +++ b/VPet.Solution/Views/SettingEditor/SystemSettingPage.xaml @@ -39,44 +39,9 @@ x:Name="CBAutoSave" Grid.Column="2" d:SelectionChanged="CBAutoSave_SelectionChanged" - SelectedIndex="3" - Style="{DynamicResource ComboBox_BaseStyle}"> - - + ItemsSource="{Binding SystemSetting.SaveIntervals}" + SelectedItem="{Binding SystemSetting.AutoSaveInterval}" + Style="{DynamicResource ComboBox_BaseStyle}" /> public partial class SystemSettingPage : Page { + public SystemSettingPageVM ViewModel => (SystemSettingPageVM)DataContext; + public SystemSettingPage() { InitializeComponent(); + this.SetViewModel(); } }