refactor: refactor project
This commit is contained in:
1 parent
6c07355601
commit
ba53ad1da4
65 files changed
+547
-403
No files matched your search
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BallanceTasEditor.Backend {
|
||||
public class FileWatcher : IDisposable {
|
||||
/// <summary>
|
||||
/// Create a file watcher.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This new created file watcher is not watching specified file
|
||||
/// unless you explicitly call <see cref="Start"/> method.
|
||||
/// </remarks>
|
||||
/// <param name="filepath">The path to watching file.</param>
|
||||
public FileWatcher(string filepath) {
|
||||
m_FilePath = filepath;
|
||||
m_IsWatching = false;
|
||||
m_EventMutex = new Mutex();
|
||||
m_IsEventProcessing = false;
|
||||
|
||||
// Get directory and file info
|
||||
string directory = Path.GetDirectoryName(filepath) ?? throw new ArgumentException("Invalid file path", nameof(filepath));
|
||||
string filename = Path.GetFileName(filepath);
|
||||
|
||||
// Create FileSystemWatcher
|
||||
m_FileSystemWatcher = new FileSystemWatcher(directory, filename) {
|
||||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName,
|
||||
EnableRaisingEvents = false
|
||||
};
|
||||
m_FileSystemWatcher.Changed += OnFileSystemChanged;
|
||||
m_FileSystemWatcher.Deleted += OnFileSystemDeleted;
|
||||
m_FileSystemWatcher.Renamed += OnFileSystemRenamed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The path to watching file.
|
||||
/// </summary>
|
||||
private string m_FilePath;
|
||||
/// <summary>
|
||||
/// Whether the file watcher is watching file.
|
||||
/// </summary>
|
||||
private bool m_IsWatching;
|
||||
/// <summary>
|
||||
/// The FileSystemWatcher instance.
|
||||
/// </summary>
|
||||
private readonly FileSystemWatcher m_FileSystemWatcher;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to indicate if disposed.
|
||||
/// </summary>
|
||||
private bool m_Disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Start watching file.
|
||||
/// </summary>
|
||||
public void Start() {
|
||||
if (m_Disposed) throw new ObjectDisposedException(nameof(FileWatcher));
|
||||
|
||||
if (m_IsWatching) {
|
||||
throw new InvalidOperationException("File watcher is already watching file.");
|
||||
} else {
|
||||
m_FileSystemWatcher.EnableRaisingEvents = true;
|
||||
m_IsWatching = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop watching file.
|
||||
/// </summary>
|
||||
public void Stop() {
|
||||
if (m_Disposed) throw new ObjectDisposedException(nameof(FileWatcher));
|
||||
|
||||
if (m_IsWatching) {
|
||||
m_FileSystemWatcher.EnableRaisingEvents = false;
|
||||
m_IsWatching = false;
|
||||
} else {
|
||||
throw new InvalidOperationException("File watcher is not watching file.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the file watcher and release resources.
|
||||
/// </summary>
|
||||
public void Dispose() {
|
||||
if (!m_Disposed) {
|
||||
// Stop watching.
|
||||
if (m_IsWatching) {
|
||||
Stop();
|
||||
}
|
||||
// Dispose members
|
||||
m_FileSystemWatcher.Dispose();
|
||||
m_EventMutex.Dispose();
|
||||
m_Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The event handler when file is modified.
|
||||
/// </summary>
|
||||
public delegate void FileModifiedHandler();
|
||||
/// <summary>
|
||||
/// The event handler when file is deleted.
|
||||
/// </summary>
|
||||
public delegate void FileDeletedHandler();
|
||||
|
||||
/// <summary>
|
||||
/// The event when file is modified.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Before user process this event completely,
|
||||
/// there is no any other event will be triggered.
|
||||
/// </remarks>
|
||||
public event FileModifiedHandler? FileModified;
|
||||
/// <summary>
|
||||
/// The event when file is deleted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Before user process this event completely,
|
||||
/// there is no any other event will be triggered.
|
||||
/// </remarks>
|
||||
public event FileDeletedHandler? FileDeleted;
|
||||
|
||||
private Mutex m_EventMutex;
|
||||
private bool m_IsEventProcessing;
|
||||
|
||||
private void OnFileModified() {
|
||||
if (FileModified is not null) {
|
||||
lock (m_EventMutex) {
|
||||
if (m_IsEventProcessing) return;
|
||||
else m_IsEventProcessing = true;
|
||||
}
|
||||
try {
|
||||
FileModified.Invoke();
|
||||
}
|
||||
finally {
|
||||
lock (m_EventMutex) {
|
||||
m_IsEventProcessing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnFileDeleted() {
|
||||
if (FileDeleted is not null) {
|
||||
lock (m_EventMutex) {
|
||||
if (m_IsEventProcessing) return;
|
||||
else m_IsEventProcessing = true;
|
||||
}
|
||||
try {
|
||||
FileDeleted.Invoke();
|
||||
}
|
||||
finally {
|
||||
lock (m_EventMutex) {
|
||||
m_IsEventProcessing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for FileSystemWatcher Changed event.
|
||||
/// </summary>
|
||||
private void OnFileSystemChanged(object sender, FileSystemEventArgs e) {
|
||||
// Filter out our own change notifications to avoid infinite loops
|
||||
if (e.ChangeType == WatcherChangeTypes.Changed) {
|
||||
OnFileModified();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for FileSystemWatcher Deleted event.
|
||||
/// </summary>
|
||||
private void OnFileSystemDeleted(object sender, FileSystemEventArgs e) {
|
||||
OnFileDeleted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for FileSystemWatcher Renamed event.
|
||||
/// </summary>
|
||||
private void OnFileSystemRenamed(object sender, RenamedEventArgs e) {
|
||||
// Treat rename as a delete since the original file is gone
|
||||
OnFileDeleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace BallanceTasEditor.Backend {
|
||||
/// <summary>
|
||||
/// 描述TAS文件中一帧的结构。
|
||||
/// </summary>
|
||||
public class TasFrame {
|
||||
public class TasFrame : IEquatable<TasFrame> {
|
||||
/// <summary>
|
||||
/// 以指定的FPS,无任何按键初始化当前帧。
|
||||
/// </summary>
|
||||
@@ -43,6 +43,15 @@ namespace BallanceTasEditor.Backend {
|
||||
m_KeyFlags = raw.KeyFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将原始TAS数据覆写到自身
|
||||
/// </summary>
|
||||
/// <param name="raw">要写入的原始TAS数据</param>
|
||||
public void FromRaw(RawTasFrame raw) {
|
||||
m_TimeDelta = raw.TimeDelta;
|
||||
m_KeyFlags = raw.KeyFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为原始TAS数据。
|
||||
/// </summary>
|
||||
@@ -156,6 +165,38 @@ namespace BallanceTasEditor.Backend {
|
||||
m_KeyFlags = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示当前对象是否等于另一个 TasFrame 对象。
|
||||
/// </summary>
|
||||
/// <param name="other">要比较的 TasFrame 对象。</param>
|
||||
/// <returns>如果两个对象相等则为 true,否则为 false。</returns>
|
||||
public bool Equals(TasFrame? other) {
|
||||
return other is not null &&
|
||||
m_TimeDelta == other.m_TimeDelta &&
|
||||
m_KeyFlags == other.m_KeyFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示当前对象是否等于另一个对象。
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的对象。</param>
|
||||
/// <returns>如果两个对象相等则为 true,否则为 false。</returns>
|
||||
public override bool Equals(object? obj) {
|
||||
if (obj is TasFrame other) {
|
||||
return Equals(other);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此实例的哈希代码。
|
||||
/// </summary>
|
||||
/// <returns>32 位有符号整数哈希代码。</returns>
|
||||
public override int GetHashCode() {
|
||||
return HashCode.Combine(m_TimeDelta, m_KeyFlags);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Assets\*.ico" />
|
||||
<Resource Include="Frontend\Assets\*.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -19,4 +19,8 @@
|
||||
<PackageReference Include="DotNetZip" Version="1.9.1.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Frontend\Utils\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-3
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BallanceTasEditor.Converters {
|
||||
namespace BallanceTasEditor.Frontend.Converters {
|
||||
[ValueConversion(typeof(int), typeof(string))]
|
||||
public class FpsConverter : IValueConverter {
|
||||
public static FpsConverter Instance = new FpsConverter();
|
||||
@@ -15,7 +15,7 @@ namespace BallanceTasEditor.Converters {
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (value is int tv) {
|
||||
if (tv <= 0) return DependencyProperty.UnsetValue;
|
||||
else return Utils.FpsConverter.ToDelta(tv).ToString();
|
||||
else return Backend.FpsConverter.ToDelta(tv).ToString();
|
||||
} else {
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BallanceTasEditor.Converters {
|
||||
namespace BallanceTasEditor.Frontend.Converters {
|
||||
|
||||
[ValueConversion(typeof(int?), typeof(string))]
|
||||
public class StringifyIntegerConverter : IValueConverter {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -7,7 +7,7 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace BallanceTasEditor.Styles {
|
||||
namespace BallanceTasEditor.Frontend.Styles {
|
||||
|
||||
public class AccessoryIcon {
|
||||
public static ImageSource GetIcon(DependencyObject obj) {
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Styles">
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Styles">
|
||||
<DataTemplate x:Key="AccessoryIconDataTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="{Binding Path=(local:AccessoryIcon.Icon), RelativeSource={RelativeSource AncestorType=Control, AncestorLevel=1}}"
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style x:Key="OkButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Padding" Value="5"/>
|
||||
@@ -8,7 +8,7 @@
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="/Assets/Ok.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Ok.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
<ContentControl Content="{Binding}" Margin="5,0,0,0" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
@@ -24,7 +24,7 @@
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="/Assets/Cancel.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Cancel.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
<ContentControl Content="{Binding}" Margin="5,0,0,0" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
File renamed without changes.
+1
-2
@@ -1,4 +1,3 @@
|
||||
using BallanceTasEditor.Utils;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
@@ -8,7 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BallanceTasEditor.ViewModels {
|
||||
namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
|
||||
public struct NewFileDialogResult {
|
||||
public int Count { get; set; }
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.AboutDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.AboutDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="About Ballance TAS Editor" Width="340" Height="480" Icon="/Assets/About.ico">
|
||||
Title="About Ballance TAS Editor" Width="340" Height="480" Icon="/Frontend/Assets/About.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -15,7 +15,7 @@
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- 图标 -->
|
||||
<Image Source="/Assets/App.ico" Grid.Row="0" Margin="10" HorizontalAlignment="Center"
|
||||
<Image Source="/Frontend/Assets/App.ico" Grid.Row="0" Margin="10" HorizontalAlignment="Center"
|
||||
Width="64" Height="64" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
|
||||
<!-- 应用名称和简介 -->
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for AboutDialog.xaml
|
||||
/// </summary>
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.AddFrameDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.AddFrameDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="Add Frame" Height="250" Width="400" Icon="/Assets/AddFrame.ico">
|
||||
Title="Add Frame" Height="250" Width="400" Icon="/Frontend/Assets/AddFrame.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -34,9 +34,9 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Source="/Assets/Count.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Count.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Grid.Column="0" Grid.Row="0" Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
<Image Source="/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Grid.Column="0" Grid.Row="1" Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Margin="5" Grid.Column="1" Grid.Row="0" Text="Count" VerticalAlignment="Center"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for AddFrameDialog.xaml
|
||||
/// </summary>
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.EditFpsDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.EditFpsDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="Edit FPS" Height="220" Width="400" Icon="/Assets/SetFps.ico">
|
||||
Title="Edit FPS" Height="220" Width="400" Icon="/Frontend/Assets/SetFps.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -33,7 +33,7 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Source="/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Grid.Column="0" Grid.Row="0" Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Margin="5" Grid.Column="1" Grid.Row="0" Text="FPS" VerticalAlignment="Center"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for EditFpsDialog.xaml
|
||||
/// </summary>
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.GotoDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.GotoDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="Goto..." Height="180" Width="400" Icon="/Assets/Goto.ico">
|
||||
Title="Goto..." Height="180" Width="400" Icon="/Frontend/Assets/Goto.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for GotoDialog.xaml
|
||||
/// </summary>
|
||||
+40
-40
@@ -1,12 +1,12 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.MainWindow"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.MainWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:styles="clr-namespace:BallanceTasEditor.Styles"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
xmlns:styles="clr-namespace:BallanceTasEditor.Frontend.Styles"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
|
||||
Title="Ballance TAS Editor" Height="600" Width="800" Icon="/Assets/App.ico">
|
||||
Title="Ballance TAS Editor" Height="600" Width="800" Icon="/Frontend/Assets/App.ico">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -19,28 +19,28 @@
|
||||
<Menu Grid.Row="0">
|
||||
<Menu.Resources>
|
||||
<!-- Menu Icons -->
|
||||
<Image x:Key="IconNewFile" Source="/Assets/NewFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconOpenFile" Source="/Assets/OpenFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFile" Source="/Assets/SaveFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFileAs" Source="/Assets/SaveFileAs.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFileThenRunGame" Source="/Assets/SaveFileThenRunGame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCloseFile" Source="/Assets/CloseFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconExit" Source="/Assets/Exit.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUndo" Source="/Assets/Undo.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconRedo" Source="/Assets/Redo.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconNextItem" Source="/Assets/NextItem.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconNextPage" Source="/Assets/NextPage.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreviousItem" Source="/Assets/PreviousItem.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreviousPage" Source="/Assets/PreviousPage.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconGoto" Source="/Assets/Goto.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconDrawMode" Source="/Assets/DrawMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFillMode" Source="/Assets/FillMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSelectMode" Source="/Assets/SelectMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconClearKeys" Source="/Assets/ClearKeys.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUniformFps" Source="/Assets/SetFps.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreference" Source="/Assets/Preference.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconReportBug" Source="/Assets/ReportBug.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconAbout" Source="/Assets/About.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconNewFile" Source="/Frontend/Assets/NewFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconOpenFile" Source="/Frontend/Assets/OpenFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFile" Source="/Frontend/Assets/SaveFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFileAs" Source="/Frontend/Assets/SaveFileAs.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSaveFileThenRunGame" Source="/Frontend/Assets/SaveFileThenRunGame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCloseFile" Source="/Frontend/Assets/CloseFile.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconExit" Source="/Frontend/Assets/Exit.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUndo" Source="/Frontend/Assets/Undo.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconRedo" Source="/Frontend/Assets/Redo.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconNextItem" Source="/Frontend/Assets/NextItem.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconNextPage" Source="/Frontend/Assets/NextPage.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreviousItem" Source="/Frontend/Assets/PreviousItem.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreviousPage" Source="/Frontend/Assets/PreviousPage.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconGoto" Source="/Frontend/Assets/Goto.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconDrawMode" Source="/Frontend/Assets/DrawMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFillMode" Source="/Frontend/Assets/FillMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSelectMode" Source="/Frontend/Assets/SelectMode.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconClearKeys" Source="/Frontend/Assets/ClearKeys.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUniformFps" Source="/Frontend/Assets/SetFps.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPreference" Source="/Frontend/Assets/Preference.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconReportBug" Source="/Frontend/Assets/ReportBug.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconAbout" Source="/Frontend/Assets/About.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
</Menu.Resources>
|
||||
|
||||
<MenuItem Header="_File" Padding="5">
|
||||
@@ -87,15 +87,15 @@
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0">
|
||||
<Button Content="Select Mode" Margin="5" Padding="5"
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Assets/SelectMode.ico"/>
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Frontend/Assets/SelectMode.ico"/>
|
||||
<Button Content="Fill Mode" Margin="5" Padding="5"
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Assets/FillMode.ico"/>
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Frontend/Assets/FillMode.ico"/>
|
||||
<Button Content="Draw Mode" Margin="5" Padding="5"
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Assets/DrawMode.ico"/>
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Frontend/Assets/DrawMode.ico"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Content="Save File then Run Game" Grid.Column="1" Margin="5" Padding="5"
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Assets/SaveFileThenRunGame.ico"/>
|
||||
Style="{StaticResource AccessoryIconButton}" styles:AccessoryIcon.Icon="/Frontend/Assets/SaveFileThenRunGame.ico"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" AllowDrop="True">
|
||||
<Rectangle StrokeThickness="4" Stroke="Gray" StrokeDashArray="4 4" Fill="Transparent"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="20">
|
||||
<Image Source="/Assets/OpenFile.ico" Width="24" Height="24" Margin="5" VerticalAlignment="Center"/>
|
||||
<Image Source="/Frontend/Assets/OpenFile.ico" Width="24" Height="24" Margin="5" VerticalAlignment="Center"/>
|
||||
<TextBlock Margin="5" Text="Create, Open or Drop a TAS File in There for Editing" Foreground="Gray" FontSize="16" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -113,15 +113,15 @@
|
||||
<ContextMenu>
|
||||
<ContextMenu.Resources>
|
||||
<!-- Context Menu Icons -->
|
||||
<Image x:Key="IconSet" Source="/Assets/SetCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUnset" Source="/Assets/UnsetCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFlip" Source="/Assets/FlipCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCut" Source="/Assets/CutFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCopy" Source="/Assets/CopyFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPaste" Source="/Assets/PasteFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconDelete" Source="/Assets/DeleteFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconAdd" Source="/Assets/AddFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFps" Source="/Assets/SetFps.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconSet" Source="/Frontend/Assets/SetCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconUnset" Source="/Frontend/Assets/UnsetCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFlip" Source="/Frontend/Assets/FlipCell.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCut" Source="/Frontend/Assets/CutFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconCopy" Source="/Frontend/Assets/CopyFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconPaste" Source="/Frontend/Assets/PasteFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconDelete" Source="/Frontend/Assets/DeleteFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconAdd" Source="/Frontend/Assets/AddFrame.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Image x:Key="IconFps" Source="/Frontend/Assets/SetFps.ico" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
</ContextMenu.Resources>
|
||||
|
||||
<MenuItem Header="Set" Icon="{StaticResource IconSet}"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -13,7 +13,7 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
+6
-6
@@ -1,14 +1,14 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.NewFileDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.NewFileDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:vm="clr-namespace:BallanceTasEditor.ViewModels"
|
||||
xmlns:conveter="clr-namespace:BallanceTasEditor.Converters"
|
||||
xmlns:vm="clr-namespace:BallanceTasEditor.Frontend.ViewModels"
|
||||
xmlns:conveter="clr-namespace:BallanceTasEditor.Frontend.Converters"
|
||||
d:DataContext="{d:DesignInstance vm:NewFileDialog}"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="New File" Height="250" Width="400" Icon="/Assets/NewFile.ico">
|
||||
Title="New File" Height="250" Width="400" Icon="/Frontend/Assets/NewFile.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -37,9 +37,9 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Source="/Assets/Count.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Count.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Grid.Column="0" Grid.Row="0" Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
<Image Source="/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/Fps.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Grid.Column="0" Grid.Row="1" Width="16" Height="16" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Margin="5" Grid.Column="1" Grid.Row="0" Text="Count" VerticalAlignment="Center"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for NewFileDialog.xaml
|
||||
/// </summary>
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
<Window x:Class="BallanceTasEditor.Views.PreferenceDialog"
|
||||
<Window x:Class="BallanceTasEditor.Frontend.Views.PreferenceDialog"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:styles="clr-namespace:BallanceTasEditor.Styles"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
xmlns:styles="clr-namespace:BallanceTasEditor.Frontend.Styles"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="Editor Preference" Height="450" Width="400" Icon="/Assets/Preference.ico">
|
||||
Title="Editor Preference" Height="450" Width="400" Icon="/Frontend/Assets/Preference.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -17,7 +17,7 @@
|
||||
<StackPanel Orientation="Vertical">
|
||||
<!-- TODO: This icon is wrong. -->
|
||||
<GroupBox Header="Editor Layout" Margin="10" Padding="10"
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Assets/EditorLayout.ico">
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Frontend/Assets/EditorLayout.ico">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@@ -28,7 +28,7 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Paste Behavior" Margin="10" Padding="10"
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Assets/PasteFrame.ico">
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Frontend/Assets/PasteFrame.ico">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@@ -39,11 +39,11 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Frame Count" Margin="10" Padding="10"
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Assets/Count.ico">
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Frontend/Assets/Count.ico">
|
||||
<TextBox Padding="3"/>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Game Path" Margin="10" Padding="10"
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Assets/SaveFileThenRunGame.ico">
|
||||
Style="{StaticResource AccessoryIconGroupBox}" styles:AccessoryIcon.Icon="/Frontend/Assets/SaveFileThenRunGame.ico">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,7 +12,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for PreferenceDialog.xaml
|
||||
/// </summary>
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
<UserControl x:Class="BallanceTasEditor.Views.TasViewer"
|
||||
<UserControl x:Class="BallanceTasEditor.Frontend.Views.TasViewer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Views"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -13,7 +13,7 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BallanceTasEditor.Views {
|
||||
namespace BallanceTasEditor.Frontend.Views {
|
||||
/// <summary>
|
||||
/// Interaction logic for TasViewer.xaml
|
||||
/// </summary>
|
||||
@@ -1,97 +0,0 @@
|
||||
using LanguageExt.Common;
|
||||
using LanguageExt.TypeClasses;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BallanceTasEditor.Utils {
|
||||
|
||||
// YYC MARK:
|
||||
// 这些验证器尽管服务于UI,但是并不遵循WPF或者CommunityToolkit.Mvvm的Validator模型,
|
||||
// 所以我把他们放在这里。
|
||||
|
||||
/// <summary>
|
||||
/// 验证器接口。
|
||||
/// </summary>
|
||||
/// <typeparam name="TIn">验证器接受的待验证数据的类型。</typeparam>
|
||||
/// <typeparam name="TOut">验证器验证完毕后,会输出的类型。</typeparam>
|
||||
public interface IValidator<TIn, TOut> {
|
||||
/// <summary>
|
||||
/// 验证给定数据是否正确。
|
||||
/// </summary>
|
||||
/// <param name="data">要验证的数据。</param>
|
||||
/// <returns>数据正确,或对应的错误信息。</returns>
|
||||
ValidationResult Validate(TIn data);
|
||||
|
||||
/// <summary>
|
||||
/// 获取验证无误数据转换后的数据。
|
||||
/// </summary>
|
||||
/// <param name="data">验证无误,用于获取输出的数据。</param>
|
||||
/// <returns>输出的数据。</returns>
|
||||
/// <exception cref="ArgumentException">给定数据验证时出现错误。</exception>
|
||||
TOut Fetch(TIn data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以字符串呈现的数据的通用验证器
|
||||
/// </summary>
|
||||
public abstract class StringifiedValueValidator<T> : IValidator<string, T> where T : notnull {
|
||||
/// <summary>
|
||||
/// 用户需要实现的验证函数。
|
||||
/// </summary>
|
||||
/// <param name="stringifiedValue">要进行验证的数据。</param>
|
||||
/// <returns>验证完毕用于输出的数值,或者验证失败时的错误消息。</returns>
|
||||
protected abstract Either<T, string> ValidateValue(string stringifiedValue);
|
||||
|
||||
public ValidationResult Validate(string data) {
|
||||
return ValidateValue(data).Match(
|
||||
Left: (_) => ValidationResult.Success,
|
||||
Right: (v) => new ValidationResult(v)
|
||||
);
|
||||
}
|
||||
|
||||
public T Fetch(string data) {
|
||||
return ValidateValue(data).Match(
|
||||
Left: (v) => v,
|
||||
Right: (msg) => throw new ArgumentException($"Given value can not pass Validator due to {msg}.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class IntegerValidator : StringifiedValueValidator<int> {
|
||||
protected override Either<int, string> ValidateValue(string stringifiedValue) {
|
||||
if (int.TryParse(stringifiedValue, out int val)) {
|
||||
return Left(val);
|
||||
} else {
|
||||
return Right("Given string do not represent any valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FpsValidator : IntegerValidator {
|
||||
public static FpsValidator Instance = new FpsValidator();
|
||||
|
||||
protected override Either<int, string> ValidateValue(string stringifiedValue) {
|
||||
return base.ValidateValue(stringifiedValue).BindLeft<int>((v) => {
|
||||
if (v <= 0) return Right("Fps must be greater than zero.");
|
||||
else return Left(v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class CountValidator : IntegerValidator {
|
||||
public static FpsValidator Instance = new FpsValidator();
|
||||
|
||||
protected override Either<int, string> ValidateValue(string stringifiedValue) {
|
||||
return base.ValidateValue(stringifiedValue).BindLeft<int>((v) => {
|
||||
if (v < 0) return Right("Count can not lower than zero.");
|
||||
else return Left(v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using BallanceTasEditor.Backend;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BallanceTasEditorTests.Backend {
|
||||
[TestClass]
|
||||
public class TasSequenceTests {
|
||||
|
||||
private static readonly TasFrame[] BLANK = { };
|
||||
private static readonly TasFrame[] PROBE = {
|
||||
new TasFrame(10),
|
||||
new TasFrame(20),
|
||||
new TasFrame(30),
|
||||
new TasFrame(40),
|
||||
new TasFrame(50),
|
||||
};
|
||||
|
||||
private static CountableEnumerable<TasFrame> GetCountableProbe() {
|
||||
return new CountableEnumerable<TasFrame>(PROBE);
|
||||
}
|
||||
|
||||
private static CountableEnumerable<TasFrame> GetCountableBlank() {
|
||||
return new CountableEnumerable<TasFrame>(BLANK);
|
||||
}
|
||||
|
||||
private static IEnumerable<object[]> TasSequenceInstanceProvider {
|
||||
get {
|
||||
yield return new object[] { new ListTasSequence() };
|
||||
yield return new object[] { new LegacyTasSequence() };
|
||||
// TODO: Add GapBufferTasSequence once we finish it.
|
||||
//yield return new object[] { new GapBufferTasSequence() };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void VisitTest(ITasSequence sequence) {
|
||||
// 空时访问
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(-1));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(0));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(1));
|
||||
|
||||
// 设置数据
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
// 访问数据
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(-1));
|
||||
for (int i = 0; i < PROBE.Length; i++) {
|
||||
Assert.AreEqual(sequence.Visit(i), PROBE[i]);
|
||||
}
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(PROBE.Length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void InsertTest(ITasSequence sequence) {
|
||||
// 需要在不同的存储器上,分别检测在空的时候插入,
|
||||
// 和在非空时的头,中,尾分别插入的结果。
|
||||
|
||||
// 先检测空插入
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Insert(-1, GetCountableProbe()));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Insert(1, GetCountableProbe()));
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
for (int i = 0; i < PROBE.Length; i++) {
|
||||
Assert.AreEqual(sequence.Visit(i), PROBE[i]);
|
||||
}
|
||||
|
||||
// 再检测有数据的插入,分别在头尾和中间进行
|
||||
var indices = new int[] { 0, PROBE.Length / 2, PROBE.Length - 1, PROBE.Length };
|
||||
foreach (var index in indices) {
|
||||
// 清空,一次插入,然后二次插入
|
||||
sequence.Clear();
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
sequence.Insert(index, GetCountableProbe());
|
||||
|
||||
// 用List做正确模拟
|
||||
var expected = new List<TasFrame>();
|
||||
expected.AddRange(PROBE);
|
||||
expected.InsertRange(index, PROBE);
|
||||
|
||||
// 检查结果
|
||||
Assert.AreEqual(sequence.GetCount(), expected.Count);
|
||||
for (int i = 0; i < expected.Count; i++) {
|
||||
Assert.AreEqual(sequence.Visit(i), expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void RemoveTest(ITasSequence sequence) {
|
||||
// 在空的时候删除0项
|
||||
sequence.Remove(0, 0);
|
||||
|
||||
// 插入项目后尝试在头中尾分别删除
|
||||
var indices = new int[] { 0, PROBE.Length / 2, PROBE.Length - 1 };
|
||||
foreach (var index in indices) {
|
||||
// 清空,插入,删除
|
||||
sequence.Clear();
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
sequence.Remove(index, 1);
|
||||
|
||||
// 用List做正确模拟
|
||||
var expected = new List<TasFrame>();
|
||||
expected.AddRange(PROBE);
|
||||
expected.RemoveRange(index, 1);
|
||||
|
||||
// 检查结果
|
||||
Assert.AreEqual(sequence.GetCount(), expected.Count);
|
||||
for (int i = 0; i < expected.Count; i++) {
|
||||
Assert.AreEqual(sequence.Visit(i), expected[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void ClearTest(ITasSequence sequence) {
|
||||
// 设置数据后清空
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
sequence.Clear();
|
||||
|
||||
// 检查是否为空
|
||||
Assert.IsTrue(sequence.IsEmpty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsEmpty函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void IsEmptyTest(ITasSequence sequence) {
|
||||
// 检查是否为空
|
||||
Assert.IsTrue(sequence.IsEmpty());
|
||||
|
||||
// 插入数据后再检查
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
Assert.IsFalse(sequence.IsEmpty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetCount函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void GetCountTest(ITasSequence sequence) {
|
||||
// 检查长度为0
|
||||
Assert.AreEqual(sequence.GetCount(), 0);
|
||||
|
||||
// 插入数据后再检查
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
Assert.AreEqual(sequence.GetCount(), PROBE.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 混合检查Visit,Clear,GetCount,IsEmpty。
|
||||
/// </summary>
|
||||
/// <param name="sequence"></param>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasSequenceInstanceProvider))]
|
||||
public void HybridTest(ITasSequence sequence) {
|
||||
// 检查空和大小
|
||||
Assert.IsTrue(sequence.IsEmpty());
|
||||
Assert.AreEqual(sequence.GetCount(), 0);
|
||||
|
||||
// 设置内容
|
||||
sequence.Insert(0, GetCountableProbe());
|
||||
// 并再次检查大小
|
||||
Assert.IsFalse(sequence.IsEmpty());
|
||||
Assert.AreEqual(sequence.GetCount(), PROBE.Length);
|
||||
|
||||
// 访问数据
|
||||
var len = PROBE.Length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Assert.AreEqual(sequence.Visit(i), PROBE[i]);
|
||||
}
|
||||
|
||||
// 清空数据
|
||||
sequence.Clear();
|
||||
// 再次检查数据
|
||||
Assert.IsTrue(sequence.IsEmpty());
|
||||
Assert.AreEqual(sequence.GetCount(), 0);
|
||||
|
||||
// 清空后插入0项,然后确认
|
||||
sequence.Clear();
|
||||
sequence.Insert(0, GetCountableBlank());
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(-1));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(0));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => sequence.Visit(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BallanceTasEditor.Utils;
|
||||
|
||||
namespace BallanceTasEditorTests.Utils {
|
||||
[TestClass]
|
||||
public class TasStorageTests {
|
||||
|
||||
private static readonly int[] BLANK = { };
|
||||
private static readonly int[] PROBE = { 10, 20, 30, 40, 50 };
|
||||
|
||||
private static CountableEnumerable<int> GetCountableProbe() {
|
||||
return new CountableEnumerable<int>(PROBE);
|
||||
}
|
||||
|
||||
private static CountableEnumerable<int> GetCountableBlank() {
|
||||
return new CountableEnumerable<int>(BLANK);
|
||||
}
|
||||
|
||||
private static IEnumerable<object[]> TasStorageInstanceProvider {
|
||||
get {
|
||||
yield return new object[] { new ListTasStorage<int>() };
|
||||
yield return new object[] { new LegacyTasStorage<int>() };
|
||||
// TODO: Add GapBufferTasStorage once we finish it.
|
||||
//yield return new object[] { new GapBufferTasStorage<int>() };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void VisitTest(ITasStorage<int> storage) {
|
||||
// 空时访问
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(-1));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(0));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(1));
|
||||
|
||||
// 设置数据
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
// 访问数据
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(-1));
|
||||
for (int i = 0; i < PROBE.Length; i++) {
|
||||
Assert.AreEqual(storage.Visit(i), PROBE[i]);
|
||||
}
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(PROBE.Length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void InsertTest(ITasStorage<int> storage) {
|
||||
// 需要在不同的存储器上,分别检测在空的时候插入,
|
||||
// 和在非空时的头,中,尾分别插入的结果。
|
||||
|
||||
// 先检测空插入
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Insert(-1, GetCountableProbe()));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Insert(1, GetCountableProbe()));
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
for (int i = 0; i < PROBE.Length; i++) {
|
||||
Assert.AreEqual(storage.Visit(i), PROBE[i]);
|
||||
}
|
||||
|
||||
// 再检测有数据的插入,分别在头尾和中间进行
|
||||
var indices = new int[] { 0, PROBE.Length / 2, PROBE.Length - 1, PROBE.Length };
|
||||
foreach (var index in indices) {
|
||||
// 清空,一次插入,然后二次插入
|
||||
storage.Clear();
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
storage.Insert(index, GetCountableProbe());
|
||||
|
||||
// 用List做正确模拟
|
||||
var expected = new List<int>();
|
||||
expected.AddRange(PROBE);
|
||||
expected.InsertRange(index, PROBE);
|
||||
|
||||
// 检查结果
|
||||
Assert.AreEqual(storage.GetCount(), expected.Count);
|
||||
for (int i = 0; i < expected.Count; i++) {
|
||||
Assert.AreEqual(storage.Visit(i), expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void RemoveTest(ITasStorage<int> storage) {
|
||||
// 在空的时候删除0项
|
||||
storage.Remove(0, 0);
|
||||
|
||||
// 插入项目后尝试在头中尾分别删除
|
||||
var indices = new int[] { 0, PROBE.Length / 2, PROBE.Length - 1 };
|
||||
foreach (var index in indices) {
|
||||
// 清空,插入,删除
|
||||
storage.Clear();
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
storage.Remove(index, 1);
|
||||
|
||||
// 用List做正确模拟
|
||||
var expected = new List<int>();
|
||||
expected.AddRange(PROBE);
|
||||
expected.RemoveRange(index, 1);
|
||||
|
||||
// 检查结果
|
||||
Assert.AreEqual(storage.GetCount(), expected.Count);
|
||||
for (int i = 0; i < expected.Count; i++) {
|
||||
Assert.AreEqual(storage.Visit(i), expected[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void ClearTest(ITasStorage<int> storage) {
|
||||
// 设置数据后清空
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
storage.Clear();
|
||||
|
||||
// 检查是否为空
|
||||
Assert.IsTrue(storage.IsEmpty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsEmpty函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void IsEmptyTest(ITasStorage<int> storage) {
|
||||
// 检查是否为空
|
||||
Assert.IsTrue(storage.IsEmpty());
|
||||
|
||||
// 插入数据后再检查
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
Assert.IsFalse(storage.IsEmpty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetCount函数独立测试。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void GetCountTest(ITasStorage<int> storage) {
|
||||
// 检查长度为0
|
||||
Assert.AreEqual(storage.GetCount(), 0);
|
||||
|
||||
// 插入数据后再检查
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
Assert.AreEqual(storage.GetCount(), PROBE.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 混合检查Visit,Clear,GetCount,IsEmpty。
|
||||
/// </summary>
|
||||
/// <param name="storage"></param>
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(TasStorageInstanceProvider))]
|
||||
public void HybridTest(ITasStorage<int> storage) {
|
||||
// 检查空和大小
|
||||
Assert.IsTrue(storage.IsEmpty());
|
||||
Assert.AreEqual(storage.GetCount(), 0);
|
||||
|
||||
// 设置内容
|
||||
storage.Insert(0, GetCountableProbe());
|
||||
// 并再次检查大小
|
||||
Assert.IsFalse(storage.IsEmpty());
|
||||
Assert.AreEqual(storage.GetCount(), PROBE.Length);
|
||||
|
||||
// 访问数据
|
||||
var len = PROBE.Length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Assert.AreEqual(storage.Visit(i), PROBE[i]);
|
||||
}
|
||||
|
||||
// 清空数据
|
||||
storage.Clear();
|
||||
// 再次检查数据
|
||||
Assert.IsTrue(storage.IsEmpty());
|
||||
Assert.AreEqual(storage.GetCount(), 0);
|
||||
|
||||
// 清空后插入0项,然后确认
|
||||
storage.Clear();
|
||||
storage.Insert(0, GetCountableBlank());
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(-1));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(0));
|
||||
AssertExtension.ThrowsDerivedException<ArgumentException>(() => storage.Visit(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user