VPet.Solution 实装 SaveViewer

This commit is contained in:
Hakoyu 2024-01-13 21:56:21 +08:00
parent e26fb9b792
commit 47395ec6a8
16 changed files with 925 additions and 17 deletions

View File

@ -0,0 +1,188 @@
using HKW.HKWUtils.Observable;
using LinePutScript.Localization.WPF;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VPet_Simulator.Windows.Interface;
namespace VPet.Solution.Models.SaveViewer;
/// <summary>
/// 存档模型
/// </summary>
public class SaveModel : ObservableClass<SaveModel>
{
/// <summary>
/// 名称
/// </summary>
[ReflectionPropertyIgnore]
public string Name { get; set; }
/// <summary>
/// 文件路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 统计数据
/// </summary>
public ObservableCollection<StatisticDataModel> Statistics { get; set; } = new();
#region DateSaved
private DateTime _dateSaved;
public DateTime DateSaved
{
get => _dateSaved;
set => SetProperty(ref _dateSaved, value);
}
#endregion
#region PetName
private string _petName;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Name))]
public string PetName
{
get => _petName;
set => SetProperty(ref _petName, value);
}
#endregion
#region Level
private int _level;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Level))]
public int Level
{
get => _level;
set => SetProperty(ref _level, value);
}
#endregion
#region Money
private double _money = 100;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Money))]
public double Money
{
get => _money;
set => SetProperty(ref _money, value);
}
#endregion
#region Exp
private double _exp = 0;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Exp))]
public double Exp
{
get => _exp;
set => SetProperty(ref _exp, value);
}
#endregion
#region Feeling
private double _feeling = 60;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Feeling))]
public double Feeling
{
get => _feeling;
set => SetProperty(ref _feeling, value);
}
#endregion
#region Health
private double _health = 100;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Health))]
public double Health
{
get => _health;
set => SetProperty(ref _health, value);
}
#endregion
#region Likability
private double _likability = 0;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Likability))]
public double Likability
{
get => _likability;
set => SetProperty(ref _likability, value);
}
#endregion
#region Mode
private VPet_Simulator.Core.GameSave.ModeType _mode;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Mode))]
public VPet_Simulator.Core.GameSave.ModeType Mode
{
get => _mode;
set => SetProperty(ref _mode, value);
}
#endregion
#region Strength
private double _strength = 100;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.Strength))]
public double Strength
{
get => _strength;
set => SetProperty(ref _strength, value);
}
#endregion
#region StrengthFood
private double _strengthFood = 100;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.StrengthFood))]
public double StrengthFood
{
get => _strengthFood;
set => SetProperty(ref _strengthFood, value);
}
#endregion
#region StrengthDrink
private double _strengthDrink = 100;
[ReflectionProperty(nameof(VPet_Simulator.Core.GameSave.StrengthDrink))]
public double StrengthDrink
{
get => _strengthDrink;
set => SetProperty(ref _strengthDrink, value);
}
#endregion
public SaveModel(string filePath, GameSave_v2 save)
{
Name = Path.GetFileNameWithoutExtension(filePath);
FilePath = filePath;
DateSaved = File.GetLastWriteTime(filePath);
LoadSave(save.GameSave);
foreach (var data in save.Statistics.Data)
{
Statistics.Add(
new()
{
Id = data.Key,
Name = data.Key.Translate(),
Value = data.Value
}
);
}
}
private void LoadSave(VPet_Simulator.Core.GameSave save)
{
ReflectionUtils.SetValue(save, this);
}
}

View File

@ -0,0 +1,46 @@
namespace VPet.Solution.Models.SaveViewer;
/// <summary>
/// 统计数据模型
/// </summary>
public class StatisticDataModel : ObservableClass<StatisticDataModel>
{
#region Id
private string _id;
/// <summary>
/// ID
/// </summary>
public string Id
{
get => _id;
set => SetProperty(ref _id, value);
}
#endregion
#region Name
private string _name;
/// <summary>
/// 名称
/// </summary>
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
#endregion
#region Value
private object _value;
/// <summary>
/// 值
/// </summary>
public object Value
{
get => _value;
set => SetProperty(ref _value, value);
}
#endregion
}

View File

@ -46,6 +46,9 @@ public static class ReflectionUtils
{
// 尝试获取目标属性信息
targetInfo.PropertyInfos.TryGetValue(property.Name, out var targetReflectionInfo);
// 检测忽视
if (targetReflectionInfo?.IsIgnore is true)
continue;
// 获取源属性名
var sourcePropertyName = targetReflectionInfo is null
? property.Name
@ -82,8 +85,14 @@ public static class ReflectionUtils
var objectInfo = new ReflectionObjectInfo(type);
foreach (var property in type.GetProperties(_propertyBindingFlags))
{
// 获取是否被忽视
if (property.IsDefined(typeof(ReflectionPropertyIgnoreAttribute)))
{
objectInfo.PropertyInfos[property.Name] = new(property.Name) { IsIgnore = true };
continue;
}
if (
property.IsDefined(typeof(ReflectionPropertyAttribute)) is false
property.IsDefined(typeof(ReflectionPropertyIgnoreAttribute))
&& property.IsDefined(typeof(ReflectionPropertyConverterAttribute)) is false
)
continue;
@ -94,8 +103,8 @@ public static class ReflectionUtils
is ReflectionPropertyAttribute propertyInfoAttribute
)
{
if (string.IsNullOrWhiteSpace(propertyInfoAttribute.TargetName) is false)
propertyInfo.TargetName = propertyInfoAttribute.TargetName;
if (string.IsNullOrWhiteSpace(propertyInfoAttribute.TargetPropertyName) is false)
propertyInfo.TargetName = propertyInfoAttribute.TargetPropertyName;
propertyInfo.IsRequired = propertyInfoAttribute.IsRequired;
}
// 获取属性转换器
@ -151,8 +160,13 @@ public class ReflectionPropertyInfo
/// <summary>
/// 是必要的
/// </summary>
[DefaultValue(true)]
public bool IsRequired { get; set; } = true;
[DefaultValue(false)]
public bool IsRequired { get; set; } = false;
/// <summary>
/// 是忽视的
/// </summary>
public bool IsIgnore { get; set; } = false;
/// <summary>
/// 反射值转换器
@ -174,7 +188,7 @@ public class ReflectionPropertyAttribute : Attribute
/// <summary>
/// 属性名称
/// </summary>
public string TargetName { get; }
public string TargetPropertyName { get; }
/// <summary>
/// 是必要的
@ -187,9 +201,9 @@ public class ReflectionPropertyAttribute : Attribute
IsRequired = isRequired;
}
public ReflectionPropertyAttribute(string name, bool isRequired = true)
public ReflectionPropertyAttribute(string targetPropertyName, bool isRequired = true)
{
TargetName = name;
TargetPropertyName = targetPropertyName;
IsRequired = isRequired;
}
}
@ -211,6 +225,15 @@ public class ReflectionPropertyConverterAttribute : Attribute
}
}
/// <summary>
/// 反射属性忽视
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ReflectionPropertyIgnoreAttribute : Attribute
{
public ReflectionPropertyIgnoreAttribute() { }
}
/// <summary>
/// 反射设置
/// </summary>

View File

@ -95,6 +95,8 @@
<Compile Include="Converters\MaxConverter.cs" />
<Compile Include="Converters\ValueToBoolConverter.cs" />
<Compile Include="Converters\BoolInverter.cs" />
<Compile Include="Models\SaveViewer\SaveModel.cs" />
<Compile Include="Models\SaveViewer\StatisticDataModel.cs" />
<Compile Include="Models\SettingEditor\GraphicsSettingModel.cs" />
<Compile Include="Models\SettingEditor\InteractiveSettingModel.cs" />
<Compile Include="Models\SettingEditor\SystemSettingModel.cs" />
@ -103,11 +105,23 @@
<Compile Include="Utils\FindTopParent.cs" />
<Compile Include="Utils\ReflectionUtils.cs" />
<Compile Include="ViewModels\MainWindowVM.cs" />
<Compile Include="ViewModels\SaveViewer\SaveDataPageVM.cs" />
<Compile Include="ViewModels\SaveViewer\SaveStatisticPageVM.cs" />
<Compile Include="ViewModels\SaveViewer\SaveWindowVM.cs" />
<Compile Include="ViewModels\SettingEditor\CustomizedSettingPageVM.cs" />
<Compile Include="ViewModels\SettingEditor\DiagnosticSettingPageVM.cs" />
<Compile Include="ViewModels\SettingEditor\ModSettingPageVM.cs" />
<Compile Include="Models\SettingEditor\SettingModel.cs" />
<Compile Include="ViewModels\SettingEditor\SystemSettingPageVM.cs" />
<Compile Include="Views\SaveViewer\SaveDataPage.xaml.cs">
<DependentUpon>SaveDataPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SaveViewer\SaveStatisticPage.xaml.cs">
<DependentUpon>SaveStatisticPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SaveViewer\SaveWindow.xaml.cs">
<DependentUpon>SaveWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingEditor\SettingWindow.xaml.cs">
<DependentUpon>SettingWindow.xaml</DependentUpon>
</Compile>
@ -135,6 +149,18 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\SaveViewer\SaveDataPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SaveViewer\SaveStatisticPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SaveViewer\SaveWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\SettingEditor\SettingWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -250,10 +276,6 @@
<Name>VPet-Simulator.Windows.Interface</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Models\SaveEditor\" />
<Folder Include="ViewModels\SaveEditor\" />
<Folder Include="Views\SaveEditor\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VPet.Solution.Models.SaveViewer;
using VPet.Solution.Views.SaveViewer;
namespace VPet.Solution.ViewModels.SaveViewer;
public class SaveDataPageVM : ObservableClass<SaveDataPageVM>
{
private SaveModel _save;
public SaveModel Save
{
get => _save;
set => SetProperty(ref _save, value);
}
public SaveDataPageVM()
{
SaveWindowVM.Current.PropertyChangedX += Current_PropertyChangedX;
}
private void Current_PropertyChangedX(SaveWindowVM sender, PropertyChangedXEventArgs e)
{
if (e.PropertyName == nameof(SaveWindowVM.CurrentSave) && sender.CurrentSave is not null)
{
Save = sender.CurrentSave;
}
}
}

View File

@ -0,0 +1,71 @@
using HKW.HKWUtils.Observable;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VPet.Solution.Models.SaveViewer;
namespace VPet.Solution.ViewModels.SaveViewer;
public class SaveStatisticPageVM : ObservableClass<SaveStatisticPageVM>
{
#region Properties
#region Save
private SaveModel _save;
public SaveModel Save
{
get => _save;
set => SetProperty(ref _save, value);
}
#endregion
#region ShowStatistics
private IEnumerable<StatisticDataModel> _showStatistics;
public IEnumerable<StatisticDataModel> ShowStatistics
{
get => _showStatistics;
set => SetProperty(ref _showStatistics, value);
}
#endregion
#region SearchStatistic
private string _searchStatistic;
public string SearchStatistic
{
get => _searchStatistic;
set
{
SetProperty(ref _searchStatistic, value);
RefreshShowStatistics(value);
}
}
#endregion
#endregion
public SaveStatisticPageVM()
{
SaveWindowVM.Current.PropertyChangedX += Current_PropertyChangedX;
}
private void Current_PropertyChangedX(SaveWindowVM sender, PropertyChangedXEventArgs e)
{
if (e.PropertyName == nameof(SaveWindowVM.CurrentSave) && sender.CurrentSave is not null)
{
Save = sender.CurrentSave;
ShowStatistics = Save.Statistics;
}
}
public void RefreshShowStatistics(string name)
{
if (string.IsNullOrWhiteSpace(name))
ShowStatistics = Save.Statistics;
else
ShowStatistics = Save.Statistics.Where(
s => s.Name.Contains(SearchStatistic, StringComparison.OrdinalIgnoreCase)
);
}
}

View File

@ -0,0 +1,111 @@
using HKW.HKWUtils.Observable;
using LinePutScript;
using LinePutScript.Localization.WPF;
using Panuon.WPF.UI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VPet.Solution.Models;
using VPet.Solution.Models.SaveViewer;
using VPet.Solution.Models.SettingEditor;
using VPet.Solution.Views.SettingEditor;
using VPet_Simulator.Windows.Interface;
namespace VPet.Solution.ViewModels.SaveViewer;
public class SaveWindowVM : ObservableClass<SaveWindowVM>
{
public static SaveWindowVM Current { get; private set; }
#region Properties
private SaveModel _currentSave;
public SaveModel CurrentSave
{
get => _currentSave;
set => SetProperty(ref _currentSave, value);
}
private readonly ObservableCollection<SaveModel> _saves = new();
private IEnumerable<SaveModel> _showSaves;
public IEnumerable<SaveModel> ShowSaves
{
get => _showSaves;
set => SetProperty(ref _showSaves, value);
}
private string _searchSave;
public string SearchSave
{
get => _searchSave;
set => SetProperty(ref _searchSave, value);
}
#endregion
#region Command
/// <summary>
/// 打开文件
/// </summary>
public ObservableCommand<SaveModel> OpenFileCommand { get; } = new();
/// <summary>
/// 从资源管理器打开
/// </summary>
public ObservableCommand<SaveModel> OpenFileInExplorerCommand { get; } = new();
#endregion
public SaveWindowVM()
{
Current = this;
ShowSaves = _saves;
LoadSaves();
PropertyChanged += SaveWindowVM_PropertyChanged;
OpenFileCommand.ExecuteCommand += OpenFileCommand_ExecuteCommand;
OpenFileInExplorerCommand.ExecuteCommand += OpenFileInExplorerCommand_ExecuteCommand;
}
private void OpenFileInExplorerCommand_ExecuteCommand(SaveModel parameter)
{
Utils.OpenFileInExplorer(parameter.FilePath);
}
private void OpenFileCommand_ExecuteCommand(SaveModel parameter)
{
Utils.OpenFile(parameter.FilePath);
}
public void RefreshShowSaves(string name)
{
if (string.IsNullOrWhiteSpace(name))
ShowSaves = _saves;
else
ShowSaves = _saves.Where(
s => s.Name.Contains(SearchSave, StringComparison.OrdinalIgnoreCase)
);
}
private void SaveWindowVM_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(SearchSave))
{
RefreshShowSaves(SearchSave);
}
}
private void LoadSaves()
{
var saveDirectory = Path.Combine(Environment.CurrentDirectory, "Saves");
foreach (var file in Directory.EnumerateFiles(saveDirectory))
{
var save = new GameSave_v2(new LPS(File.ReadAllText(file)));
var saveModel = new SaveModel(file, save);
_saves.Add(saveModel);
}
}
}

View File

@ -31,7 +31,8 @@
<Button
x:Name="Button_OpenSaveEditor"
Grid.Column="1"
Content="{ll:Str 打开存档编辑器}"
Click="Button_OpenSaveEditor_Click"
Content="{ll:Str 打开存档查看器}"
FontSize="16"
Style="{DynamicResource Button_BaseStyle}" />
</Grid>

View File

@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using VPet.Solution.ViewModels;
using VPet.Solution.Views.SaveViewer;
using VPet.Solution.Views.SettingEditor;
namespace VPet.Solution.Views;
@ -15,7 +16,8 @@ public partial class MainWindow : WindowX
{
public MainWindowVM ViewModel => (MainWindowVM)DataContext;
public SettingWindow SettingWindow { get; set; } = new();
public SettingWindow SettingWindow { get; } = new();
public SaveWindow SaveWindow { get; } = new();
public MainWindow()
{
@ -33,10 +35,16 @@ public partial class MainWindow : WindowX
private void MainWindow_Closed(object sender, EventArgs e)
{
SettingWindow.CloseX();
SaveWindow.CloseX();
}
private void Button_OpenSettingEditor_Click(object sender, RoutedEventArgs e)
{
SettingWindow.ShowOrActivate();
}
private void Button_OpenSaveEditor_Click(object sender, RoutedEventArgs e)
{
SaveWindow.ShowOrActivate();
}
}

View File

@ -0,0 +1,92 @@
<Page
x:Class="VPet.Solution.Views.SaveViewer.SaveDataPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:h="clr-namespace:HKW.WPF.Helpers"
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
xmlns:local="clr-namespace:VPet.Solution.Views.SaveViewer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pu="https://opensource.panuon.com/wpf-ui"
xmlns:vm="clr-namespace:VPet.Solution.ViewModels.SaveViewer"
Title="SaveDataPage"
d:DataContext="{d:DesignInstance Type=vm:SaveDataPageVM}"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 保存日期}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.DateSaved, StringFormat='yyyy/MM/dd HH:mm:ss'}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 宠物名称}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.PetName}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 模式}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Mode}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 等级}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Exp}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 金钱}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Money}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 经验}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Level}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 体力}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Strength}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 心情}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.Feeling}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 饱腹度}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.StrengthFood}" />
</DockPanel>
<DockPanel>
<Label
h:ElementHelper.UniformMinWidthGroup="A"
Content="{ll:Str 口渴度}"
Style="{DynamicResource Label_BaseStyle}" />
<TextBlock Style="{DynamicResource TextBlock_LeftCenter}" Text="{Binding Save.StrengthDrink}" />
</DockPanel>
</StackPanel>
</ScrollViewer>
</Page>

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VPet.Solution.ViewModels.SaveViewer;
namespace VPet.Solution.Views.SaveViewer;
/// <summary>
/// SaveDataPage.xaml 的交互逻辑
/// </summary>
public partial class SaveDataPage : Page
{
public SaveDataPageVM ViewModel => (SaveDataPageVM)DataContext;
public SaveDataPage()
{
InitializeComponent();
this.SetViewModel<SaveDataPageVM>();
}
}

View File

@ -0,0 +1,56 @@
<Page
x:Class="VPet.Solution.Views.SaveViewer.SaveStatisticPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
xmlns:local="clr-namespace:VPet.Solution.Views.SaveViewer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pu="https://opensource.panuon.com/wpf-ui"
xmlns:vm="clr-namespace:VPet.Solution.ViewModels.SaveViewer"
Title="SaveStatisticPage"
d:DataContext="{d:DesignInstance Type=vm:SaveStatisticPageVM}"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox
x:Name="TextBox_Search"
pu:TextBoxHelper.Watermark="{ll:Str 搜索统计}"
Style="{DynamicResource StandardTextBoxStyle}"
Text="{Binding SearchStatistic, UpdateSourceTrigger=PropertyChanged}" />
<DataGrid
x:Name="DataGridStatic"
Grid.Row="1"
Margin="0,5,0,0"
d:ItemsSource="{d:SampleData ItemCount=5}"
AutoGenerateColumns="False"
CanUserAddRows="False"
ItemsSource="{Binding ShowStatistics}">
<DataGrid.RowStyle>
<Style BasedOn="{StaticResource {x:Type DataGridRow}}" TargetType="DataGridRow">
<Setter Property="ToolTip" Value="{Binding Id}" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn
Width="300"
Binding="{Binding Name}"
ElementStyle="{StaticResource TextBlock_LeftCenter}"
Header="{ll:Str 名称}"
IsReadOnly="True" />
<DataGridTextColumn
Width="200"
Binding="{Binding Value}"
ElementStyle="{StaticResource TextBlock_LeftCenter}"
Header="{ll:Str 值}"
IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Page>

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VPet.Solution.ViewModels.SaveViewer;
namespace VPet.Solution.Views.SaveViewer;
/// <summary>
/// SaveStatisticPage.xaml 的交互逻辑
/// </summary>
public partial class SaveStatisticPage : Page
{
public SaveStatisticPageVM ViewModel => (SaveStatisticPageVM)DataContext;
public SaveStatisticPage()
{
InitializeComponent();
this.SetViewModel<SaveStatisticPageVM>();
}
}

View File

@ -0,0 +1,153 @@
<pu:WindowX
x:Class="VPet.Solution.Views.SaveViewer.SaveWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
xmlns:local="clr-namespace:VPet.Solution"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pu="https://opensource.panuon.com/wpf-ui"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:vm="clr-namespace:VPet.Solution.ViewModels.SaveViewer"
Title="{ll:Str 'VPET 存档查看器'}"
Width="800"
Height="450"
MinWidth="400"
MinHeight="200"
d:DataContext="{d:DesignInstance Type=vm:SaveWindowVM}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" />
<ColumnDefinition MinWidth="300" />
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox
pu:TextBoxHelper.Watermark="{ll:Str 搜索存档}"
Style="{DynamicResource StandardTextBoxStyle}"
Text="{Binding SearchSave, UpdateSourceTrigger=PropertyChanged}" />
<ListBox
x:Name="ListBox_Saves"
Grid.Row="1"
d:ItemsSource="{d:SampleData ItemCount=5}"
ItemsSource="{Binding ShowSaves}"
SelectedItem="{Binding CurrentSave}"
Style="{DynamicResource SideMenuListBoxStyle}">
<ListBox.ItemContainerStyle>
<Style BasedOn="{StaticResource {x:Type ListBoxItem}}" TargetType="ListBoxItem">
<Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window}}" />
<Setter Property="Content" Value="{Binding Name}" />
<Setter Property="ToolTip" Value="{Binding FilePath}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=Self}}">
<MenuItem
Command="{Binding PlacementTarget.Tag.OpenFileDommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"
Header="{ll:Str 打开文件}" />
<MenuItem
Command="{Binding PlacementTarget.Tag.OpenFileInExplorerCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"
Header="{ll:Str 从资源管理器打开文件}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
<Grid Grid.Column="1" IsEnabled="{Binding SelectedItem, ElementName=ListBox_Saves, Converter={StaticResource NullToFalse}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox x:Name="ListBox_Pages" Style="{DynamicResource SideMenuListBoxStyle}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem x:Name="ListBoxItem_SaveData" Content="{ll:Str 数据}" />
<ListBoxItem x:Name="ListBoxItem_SaveStatistic" Content="{ll:Str 统计}" />
</ListBox>
<Frame
x:Name="Frame_Main"
Grid.Row="1"
Content="{Binding SelectedItem.Tag, ElementName=ListBox_Pages}"
ContentRendered="Frame_Main_ContentRendered"
NavigationUIVisibility="Hidden" />
<!--<TabControl
x:Name="MainTab"
Grid.Column="1"
Margin="5"
d:SelectionChanged="MainTab_SelectionChanged"
pu:TabControlHelper.CanHeaderPanelScroll="True"
pu:TabControlHelper.ItemsCornerRadius="4"
pu:TabControlHelper.ItemsHeight="NaN"
pu:TabControlHelper.ItemsHoverBackground="{DynamicResource PrimaryLight}"
pu:TabControlHelper.ItemsPadding="10,7"
pu:TabControlHelper.ItemsSelectedBackground="{DynamicResource PrimaryDark}"
pu:TabControlHelper.ItemsSelectedForeground="{DynamicResource DARKPrimaryText}"
Background="Transparent"
BorderThickness="0"
Foreground="{DynamicResource PrimaryText}">
<TabControl.ContentTemplate>
<DataTemplate>
<Border
Margin="0,5,0,10"
Background="{DynamicResource DARKPrimaryText}"
CornerRadius="15">
<ContentControl Margin="10,5" Content="{Binding}" />
</Border>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem
BorderBrush="{DynamicResource PrimaryDarker}"
Foreground="{DynamicResource PrimaryText}"
Header="" />
<TabItem BorderBrush="{DynamicResource PrimaryDarker}" Header="{ll:Str 系统}" />
<TabItem BorderBrush="{DynamicResource PrimaryDarker}" Header="{ll:Str 互动}" />
<TabItem BorderBrush="{DynamicResource PrimaryDarker}" Header="{ll:Str 自定}" />
<TabItem BorderBrush="{DynamicResource PrimaryDarker}" Header="{ll:Str 诊断}" />
<TabItem BorderBrush="{DynamicResource PrimaryDarker}" Header="{ll:Str MOD管理}" />
</TabControl>
<Label
x:Name="GameVerison"
Grid.ColumnSpan="2"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Background="{x:Null}"
Content="版本v1.0 (655366666)"
FontSize="10"
Foreground="Green" />-->
</Grid>
<!--<Grid Grid.Column="1">
<TextBox
x:Name="tb_seach_menu"
Margin="3,6,6,0"
VerticalAlignment="Top"
d:TextChanged="tb_seach_menu_textchange"
pu:TextBoxHelper.Watermark="{ll:Str 搜索设置}"
FontSize="16"
Style="{DynamicResource StandardTextBoxStyle}" />
<ListBox
x:Name="ListMenu"
Margin="3,40,6,3"
pu:ListBoxHelper.CornerRadius="5"
pu:ListBoxHelper.ItemsHoverBackground="{DynamicResource Primary}"
pu:ListBoxHelper.ItemsSelectedBackground="{DynamicResource SecondaryLight}"
Background="{DynamicResource SecondaryLighter}"
BorderBrush="{DynamicResource Primary}"
BorderThickness="2"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Grid>-->
</Grid>
</pu:WindowX>

View File

@ -0,0 +1,40 @@
using HKW.HKWUtils;
using Panuon.WPF.UI;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using VPet.Solution.ViewModels.SaveViewer;
using VPet.Solution.ViewModels.SettingEditor;
namespace VPet.Solution.Views.SaveViewer;
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class SaveWindow : WindowX
{
public static SaveWindow Instance { get; private set; }
public SaveWindowVM ViewModel => (SaveWindowVM)DataContext;
public SaveWindow()
{
InitializeComponent();
this.SetViewModel<SaveWindowVM>();
this.SetCloseState(WindowCloseState.Hidden);
ListBoxItem_SaveData.Tag = new SaveDataPage();
ListBoxItem_SaveStatistic.Tag = new SaveStatisticPage();
ListBox_Pages.SelectedIndex = 0;
Instance = this;
}
private void Frame_Main_ContentRendered(object sender, EventArgs e)
{
if (sender is not Frame frame)
return;
// 清理过时页面
while (frame.CanGoBack)
frame.RemoveBackEntry();
GC.Collect();
}
}

View File

@ -9,7 +9,7 @@
xmlns:pu="https://opensource.panuon.com/wpf-ui"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:vm="clr-namespace:VPet.Solution.ViewModels.SettingEditor"
Title="{ll:Str 'VPET 问题解决工具'}"
Title="{ll:Str 'VPET 设置编辑器'}"
Width="800"
Height="450"
MinWidth="400"
@ -29,7 +29,10 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Style="{DynamicResource StandardTextBoxStyle}" Text="{Binding SearchSetting, UpdateSourceTrigger=PropertyChanged}" />
<TextBox
pu:TextBoxHelper.Watermark="{ll:Str 搜索设置}"
Style="{DynamicResource StandardTextBoxStyle}"
Text="{Binding SearchSetting, UpdateSourceTrigger=PropertyChanged}" />
<ListBox
x:Name="ListBox_Saves"
Grid.Row="1"