mirror of
https://github.com/LorisYounger/VPet.git
synced 2024-08-30 18:42:36 +00:00
初始化 VPet.Solution
This commit is contained in:
parent
4c0d985854
commit
92bb88ec14
@ -1,9 +1,17 @@
|
||||
<Application x:Class="VPet.Solution.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:VPet.Solution"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
<Application
|
||||
x:Class="VPet.Solution.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="Views/MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Panuon.WPF.UI;component/Control.xaml" />
|
||||
<ResourceDictionary Source="/VPet-Simulator.Windows.Interface;component/ResourceStyle.xaml" />
|
||||
<ResourceDictionary Source="Converters.xaml" />
|
||||
<ResourceDictionary Source="Templates.xaml" />
|
||||
<ResourceDictionary Source="Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
@ -1,42 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using VPet_Simulator.Windows.Interface;
|
||||
|
||||
namespace VPet.Solution
|
||||
namespace VPet.Solution;
|
||||
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
public static bool IsDone { get; set; } = false;
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
public static bool IsDone { get; set; } = false;
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
if (e.Args != null && e.Args.Count() > 0)
|
||||
{
|
||||
if (e.Args != null && e.Args.Count() > 0)
|
||||
IsDone = true;
|
||||
switch (e.Args[0].ToLower())
|
||||
{
|
||||
IsDone = true;
|
||||
switch (e.Args[0].ToLower())
|
||||
{
|
||||
case "removestarup":
|
||||
var path = Environment.GetFolderPath(Environment.SpecialFolder.Startup) + @"\VPET_Simulator.lnk";
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
return;
|
||||
case "launchsteam":
|
||||
Process.Start("steam://rungameid/1920960");
|
||||
return;
|
||||
}
|
||||
case "removestarup":
|
||||
var path =
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.Startup)
|
||||
+ @"\VPET_Simulator.lnk";
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
return;
|
||||
case "launchsteam":
|
||||
Process.Start("steam://rungameid/1920960");
|
||||
return;
|
||||
}
|
||||
IsDone = false;
|
||||
}
|
||||
IsDone = false;
|
||||
}
|
||||
}
|
||||
|
15
VPet.Solution/Converters.xaml
Normal file
15
VPet.Solution/Converters.xaml
Normal file
@ -0,0 +1,15 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:c="clr-namespace:VPet.House.Converters">
|
||||
<c:MarginConverter x:Key="MarginConverter" />
|
||||
<c:RatioMarginConverter x:Key="RatioMarginConverter" />
|
||||
<c:CalculatorConverter x:Key="CalculatorConverter" />
|
||||
<c:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<c:BrushToMediaColorConverter x:Key="BrushToMediaColorConverter" />
|
||||
<c:MaxConverter x:Key="MaxConverter" />
|
||||
<c:FalseToHiddenConverter x:Key="FalseToHiddenConverter" />
|
||||
<c:EqualsConverter x:Key="EqualsConverter" />
|
||||
<c:NotEqualsConverter x:Key="NotEqualsConverter" />
|
||||
<c:NullToFalseConverter x:Key="NullToFalseConverter" />
|
||||
</ResourceDictionary>
|
22
VPet.Solution/Converters/BrushToMediaColorConverter.cs
Normal file
22
VPet.Solution/Converters/BrushToMediaColorConverter.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class BrushToMediaColorConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not SolidColorBrush brush)
|
||||
throw new ArgumentException("Not SolidColorBrush", nameof(value));
|
||||
return brush.Color;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Color color)
|
||||
throw new ArgumentException("Not media color", nameof(value));
|
||||
return new SolidColorBrush(color);
|
||||
}
|
||||
}
|
97
VPet.Solution/Converters/CalculatorConverter.cs
Normal file
97
VPet.Solution/Converters/CalculatorConverter.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// 计算器转换器
|
||||
/// <para>示例:
|
||||
/// <code><![CDATA[
|
||||
/// <MultiBinding Converter="{StaticResource CalculatorConverter}">
|
||||
/// <Binding Path="Num1" />
|
||||
/// <Binding Source="+" />
|
||||
/// <Binding Path="Num2" />
|
||||
/// <Binding Source="-" />
|
||||
/// <Binding Path="Num3" />
|
||||
/// <Binding Source="*" />
|
||||
/// <Binding Path="Num4" />
|
||||
/// <Binding Source="/" />
|
||||
/// <Binding Path="Num5" />
|
||||
/// </MultiBinding>
|
||||
/// //
|
||||
/// <MultiBinding Converter="{StaticResource CalculatorConverter}" ConverterParameter="+-*/">
|
||||
/// <Binding Path="Num1" />
|
||||
/// <Binding Path="Num2" />
|
||||
/// <Binding Path="Num3" />
|
||||
/// <Binding Path="Num4" />
|
||||
/// <Binding Path="Num5" />
|
||||
/// </MultiBinding>
|
||||
/// ]]></code></para>
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">绑定的数量不正确</exception>
|
||||
public class CalculatorConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values.Any(i => i == DependencyProperty.UnsetValue))
|
||||
return 0.0;
|
||||
if (values.Length == 1)
|
||||
return values[0];
|
||||
double result = System.Convert.ToDouble(values[0]);
|
||||
if (parameter is string operators)
|
||||
{
|
||||
if (operators.Length != values.Length - 1)
|
||||
throw new Exception("Parameter error: operator must be one more than parameter");
|
||||
for (int i = 1; i < values.Length - 1; i++)
|
||||
result = Operation(result, operators[i - 1], System.Convert.ToDouble(values[i]));
|
||||
result = Operation(result, operators.Last(), System.Convert.ToDouble(values.Last()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (System.Convert.ToBoolean(values.Length & 1) is false)
|
||||
throw new Exception("Parameter error: Incorrect quantity");
|
||||
bool isNumber = false;
|
||||
char currentOperator = '0';
|
||||
for (int i = 1; i < values.Length - 1; i++)
|
||||
{
|
||||
if (isNumber is false)
|
||||
{
|
||||
currentOperator = ((string)values[i])[0];
|
||||
isNumber = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = System.Convert.ToDouble(values[i]);
|
||||
result = Operation(result, currentOperator, value);
|
||||
isNumber = false;
|
||||
}
|
||||
}
|
||||
result = Operation(result, currentOperator, System.Convert.ToDouble(values.Last()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double Operation(double value1, char operatorChar, double value2)
|
||||
{
|
||||
return operatorChar switch
|
||||
{
|
||||
'+' => value1 + value2,
|
||||
'-' => value1 - value2,
|
||||
'*' => value1 * value2,
|
||||
'/' => value1 / value2,
|
||||
'%' => value1 % value2,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
28
VPet.Solution/Converters/EqualsConverter.cs
Normal file
28
VPet.Solution/Converters/EqualsConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class EqualsConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
if (values.Length != 2)
|
||||
throw new NotImplementedException("Values length must be 2");
|
||||
return values[0].Equals(values[1]);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
20
VPet.Solution/Converters/FalseToCollapsedConverter.cs
Normal file
20
VPet.Solution/Converters/FalseToCollapsedConverter.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class FalseToCollapsedConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (bool.TryParse(value.ToString(), out var result) && result)
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is Visibility visibility && visibility == Visibility.Collapsed;
|
||||
}
|
||||
}
|
20
VPet.Solution/Converters/FalseToHiddenConverter.cs
Normal file
20
VPet.Solution/Converters/FalseToHiddenConverter.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class FalseToHiddenConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (bool.TryParse(value.ToString(), out var result) && result)
|
||||
? Visibility.Visible
|
||||
: Visibility.Hidden;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is Visibility visibility && visibility == Visibility.Hidden;
|
||||
}
|
||||
}
|
84
VPet.Solution/Converters/MarginConverter.cs
Normal file
84
VPet.Solution/Converters/MarginConverter.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// 边距转换器
|
||||
/// <para>示例:
|
||||
/// <code><![CDATA[
|
||||
/// <MultiBinding Converter="{StaticResource MarginConverter}">
|
||||
/// <Binding Path="Left" />
|
||||
/// <Binding Path="Top" />
|
||||
/// <Binding Path="Right" />
|
||||
/// <Binding Path="Bottom" />
|
||||
/// </MultiBinding>
|
||||
/// ]]></code></para>
|
||||
/// </summary>
|
||||
public class MarginConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
if (values.Length == 0)
|
||||
{
|
||||
return new Thickness();
|
||||
}
|
||||
else if (values.Length == 1)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[0]),
|
||||
Top = default,
|
||||
Right = default,
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 2)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[0]),
|
||||
Top = System.Convert.ToDouble(values[1]),
|
||||
Right = default,
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 3)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[0]),
|
||||
Top = System.Convert.ToDouble(values[1]),
|
||||
Right = System.Convert.ToDouble(values[2]),
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 4)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[0]),
|
||||
Top = System.Convert.ToDouble(values[1]),
|
||||
Right = System.Convert.ToDouble(values[2]),
|
||||
Bottom = System.Convert.ToDouble(values[3])
|
||||
};
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
26
VPet.Solution/Converters/MaxConverter.cs
Normal file
26
VPet.Solution/Converters/MaxConverter.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class MaxConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
return values.Max(i => (double)i);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
22
VPet.Solution/Converters/MediaColorToBrushConverter.cs
Normal file
22
VPet.Solution/Converters/MediaColorToBrushConverter.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class MediaColorToBrushConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Color color)
|
||||
throw new ArgumentException("Not media color", nameof(value));
|
||||
return new SolidColorBrush(color);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not SolidColorBrush brush)
|
||||
throw new ArgumentException("Not SolidColorBrush", nameof(value));
|
||||
return brush.Color;
|
||||
}
|
||||
}
|
28
VPet.Solution/Converters/NotEqualsConverter.cs
Normal file
28
VPet.Solution/Converters/NotEqualsConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class NotEqualsConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
if (values.Length != 2)
|
||||
throw new NotImplementedException("Values length must be 2");
|
||||
return !values[0].Equals(values[1]);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
17
VPet.Solution/Converters/NullToFalseConverter.cs
Normal file
17
VPet.Solution/Converters/NullToFalseConverter.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
public class NullToFalseConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is not null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
91
VPet.Solution/Converters/RatioMarginConverter.cs
Normal file
91
VPet.Solution/Converters/RatioMarginConverter.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// 边距转换器
|
||||
/// <para>示例:
|
||||
/// <code><![CDATA[
|
||||
/// <MultiBinding Converter="{StaticResource RatioMarginConverter}">
|
||||
/// <Binding Path="Left" />
|
||||
/// <Binding Path="Top" />
|
||||
/// <Binding Path="Right" />
|
||||
/// <Binding Path="Bottom" />
|
||||
/// </MultiBinding>
|
||||
/// ]]></code></para>
|
||||
/// </summary>
|
||||
public class RatioMarginConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
if (values.Any(i => i == DependencyProperty.UnsetValue))
|
||||
return new Thickness();
|
||||
if (values.Length == 0)
|
||||
{
|
||||
return new Thickness();
|
||||
}
|
||||
else if (values.Length == 1)
|
||||
{
|
||||
return new Thickness();
|
||||
}
|
||||
var ratio = System.Convert.ToDouble(values[0]);
|
||||
if (values.Length == 2)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[1]) * ratio,
|
||||
Top = default,
|
||||
Right = default,
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 3)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[1]) * ratio,
|
||||
Top = System.Convert.ToDouble(values[2]) * ratio,
|
||||
Right = default,
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 4)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[1]) * ratio,
|
||||
Top = System.Convert.ToDouble(values[2]) * ratio,
|
||||
Right = System.Convert.ToDouble(values[3]) * ratio,
|
||||
Bottom = default
|
||||
};
|
||||
}
|
||||
else if (values.Length == 5)
|
||||
{
|
||||
return new Thickness()
|
||||
{
|
||||
Left = System.Convert.ToDouble(values[1]) * ratio,
|
||||
Top = System.Convert.ToDouble(values[2]) * ratio,
|
||||
Right = System.Convert.ToDouble(values[3]) * ratio,
|
||||
Bottom = System.Convert.ToDouble(values[4]) * ratio
|
||||
};
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
51
VPet.Solution/Converters/StringFormatConverter.cs
Normal file
51
VPet.Solution/Converters/StringFormatConverter.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace VPet.House.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// 边距转换器
|
||||
/// <para>示例:
|
||||
/// <code><![CDATA[
|
||||
/// <MultiBinding Converter="{StaticResource MarginConverter}">
|
||||
/// <Binding Path="StringFormat" />
|
||||
/// <Binding Path="Value1" />
|
||||
/// <Binding Path="Value2" />
|
||||
/// </MultiBinding>
|
||||
/// OR
|
||||
/// <MultiBinding Converter="{StaticResource MarginConverter}" ConverterParameter="{}{0}{1}">
|
||||
/// <Binding Path="Value1" />
|
||||
/// <Binding Path="Value2" />
|
||||
/// </MultiBinding>
|
||||
/// ]]></code></para>
|
||||
/// </summary>
|
||||
public class StringFormatConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(
|
||||
object[] values,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
var formatStr = (string)parameter;
|
||||
if (string.IsNullOrWhiteSpace(formatStr))
|
||||
{
|
||||
formatStr = (string)values[0];
|
||||
return string.Format(formatStr, values.Skip(1).ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Format(formatStr, values);
|
||||
}
|
||||
}
|
||||
|
||||
public object[] ConvertBack(
|
||||
object value,
|
||||
Type[] targetTypes,
|
||||
object parameter,
|
||||
System.Globalization.CultureInfo culture
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<Window x:Class="VPet.Solution.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:VPet.Solution"
|
||||
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF" mc:Ignorable="d"
|
||||
xmlns:pu="clr-namespace:Panuon.WPF.UI;assembly=Panuon.WPF.UI" Title="{ll:Str 'VPET 问题解决工具'}" Height="450" Width="800">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
@ -1,33 +0,0 @@
|
||||
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;
|
||||
|
||||
namespace VPet.Solution
|
||||
{
|
||||
/// <summary>
|
||||
/// MainWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
if (App.IsDone)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
12
VPet.Solution/NativeStyles.xaml
Normal file
12
VPet.Solution/NativeStyles.xaml
Normal file
@ -0,0 +1,12 @@
|
||||
<ResourceDictionary
|
||||
x:Class="VPet.Solution.NativeStyles"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Panuon.WPF.UI;component/Control.xaml" />
|
||||
<ResourceDictionary Source="/VPet-Simulator.Windows.Interface;component/ResourceStyle.xaml" />
|
||||
<ResourceDictionary Source="Converters.xaml" />
|
||||
<ResourceDictionary Source="Templates.xaml" />
|
||||
<ResourceDictionary Source="Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
11
VPet.Solution/NativeStyles.xaml.cs
Normal file
11
VPet.Solution/NativeStyles.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace VPet.Solution;
|
||||
|
||||
public partial class NativeStyles : ResourceDictionary
|
||||
{
|
||||
public NativeStyles()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
@ -33,14 +31,13 @@ using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//或应用程序资源字典中找到时使用)
|
||||
//(未在页面中找到资源时使用,
|
||||
//或应用程序资源字典中找到时使用)
|
||||
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//、应用程序或任何主题专用资源字典中找到时使用)
|
||||
//(未在页面中找到资源时使用,
|
||||
//、应用程序或任何主题专用资源字典中找到时使用)
|
||||
)]
|
||||
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
|
72
VPet.Solution/Resources/NativeResources.cs
Normal file
72
VPet.Solution/Resources/NativeResources.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace VPet.House.Resources;
|
||||
|
||||
/// <summary>
|
||||
/// 本地资源
|
||||
/// </summary>
|
||||
internal class NativeResources
|
||||
{
|
||||
#region Resources
|
||||
|
||||
public const string Wall = ResourcePath + "Wall.png";
|
||||
public const string Floor = ResourcePath + "Floor.png";
|
||||
public const string Chair = ResourcePath + "Chair.png";
|
||||
public const string Table = ResourcePath + "Table.png";
|
||||
public const string Bed = ResourcePath + "Bed.png";
|
||||
|
||||
public const string OakPlanks = ResourcePath + "oak_planks.png";
|
||||
public const string Stone = ResourcePath + "stone.png";
|
||||
|
||||
#endregion Resources
|
||||
|
||||
/// <summary>
|
||||
/// 资源基路径
|
||||
/// </summary>
|
||||
public const string ResourcePath = $"{nameof(VPet)}.{nameof(House)}.{nameof(Resources)}.";
|
||||
|
||||
#region Native
|
||||
|
||||
private static readonly Assembly _assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源流
|
||||
/// </summary>
|
||||
/// <param name="resourceName">资源名</param>
|
||||
/// <returns>资源流</returns>
|
||||
public static Stream GetStream(string resourceName) =>
|
||||
_assembly.GetManifestResourceStream(resourceName)!;
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取资源流
|
||||
/// </summary>
|
||||
/// <param name="resourceName">资源名</param>
|
||||
/// <param name="resourceStream">资源流</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
public static bool TryGetStream(string resourceName, out Stream resourceStream)
|
||||
{
|
||||
resourceStream = null;
|
||||
if (_assembly.GetManifestResourceStream(resourceName) is not Stream stream)
|
||||
return false;
|
||||
resourceStream = stream;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将流保存至文件
|
||||
/// </summary>
|
||||
/// <param name="resourceName">资源名</param>
|
||||
/// <param name="path">文件路径</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
public static bool SaveTo(string resourceName, string path)
|
||||
{
|
||||
if (_assembly.GetManifestResourceStream(resourceName) is not Stream stream)
|
||||
return false;
|
||||
using var sr = new StreamReader(stream);
|
||||
using var sw = new StreamWriter(path);
|
||||
sr.BaseStream.CopyTo(sw.BaseStream);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Native
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 通知属性改变后接口
|
||||
/// </summary>
|
||||
public interface INotifyPropertyChangedX<TSender>
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知属性改变后事件
|
||||
/// </summary>
|
||||
public event PropertyChangedXEventHandler<TSender>? PropertyChangedX;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 通知属性改变前接口
|
||||
/// </summary>
|
||||
public interface INotifyPropertyChangingX<TSender>
|
||||
{
|
||||
/// <summary>
|
||||
/// 属性改变前事件
|
||||
/// </summary>
|
||||
public event PropertyChangingXEventHandler<TSender>? PropertyChangingX;
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 可观察对象
|
||||
/// <para>示例:<code><![CDATA[
|
||||
/// public class ObservableClassExample : ObservableClass<ObservableClassExample>
|
||||
/// {
|
||||
/// int _value = 0;
|
||||
/// public int Value
|
||||
/// {
|
||||
/// get => _value;
|
||||
/// set => SetProperty(ref _value, value);
|
||||
/// }
|
||||
/// }]]></code></para>
|
||||
/// </summary>
|
||||
public abstract class ObservableClass<TObject>
|
||||
: INotifyPropertyChanging,
|
||||
INotifyPropertyChanged,
|
||||
INotifyPropertyChangingX<TObject>,
|
||||
INotifyPropertyChangedX<TObject>
|
||||
where TObject : ObservableClass<TObject>
|
||||
{
|
||||
#region OnPropertyChange
|
||||
/// <summary>
|
||||
/// 设置属性值
|
||||
/// </summary>
|
||||
/// <param name="value">值</param>
|
||||
/// <param name="newValue">新值</param>
|
||||
/// <param name="propertyName">属性名称</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual bool SetProperty<TValue>(
|
||||
ref TValue value,
|
||||
TValue newValue,
|
||||
[CallerMemberName] string propertyName = null!
|
||||
)
|
||||
{
|
||||
if (EqualityComparer<TValue>.Default.Equals(value, newValue) is true)
|
||||
return false;
|
||||
var oldValue = value;
|
||||
if (OnPropertyChanging(oldValue, newValue, propertyName))
|
||||
return false;
|
||||
value = newValue;
|
||||
OnPropertyChanged(oldValue, newValue, propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变前
|
||||
/// </summary>
|
||||
/// <param name="oldValue">旧值</param>
|
||||
/// <param name="newValue">新值</param>
|
||||
/// <param name="propertyName">属性名称</param>
|
||||
/// <returns>取消为 <see langword="true"/> 否则为 <see langword="false"/></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual bool OnPropertyChanging(
|
||||
object? oldValue,
|
||||
object? newValue,
|
||||
[CallerMemberName] string propertyName = null!
|
||||
)
|
||||
{
|
||||
PropertyChanging?.Invoke(this, new(propertyName));
|
||||
if (PropertyChangingX is null)
|
||||
return false;
|
||||
var e = new PropertyChangingXEventArgs(propertyName, oldValue, newValue);
|
||||
PropertyChangingX?.Invoke((TObject)this, e);
|
||||
if (e.Cancel)
|
||||
PropertyChanged?.Invoke(this, new(propertyName));
|
||||
return e.Cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变后
|
||||
/// </summary>
|
||||
/// <param name="oldValue">旧值</param>
|
||||
/// <param name="newValue">新值</param>
|
||||
/// <param name="propertyName">属性名称</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual void OnPropertyChanged(
|
||||
object? oldValue,
|
||||
object? newValue,
|
||||
[CallerMemberName] string propertyName = null!
|
||||
)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new(propertyName));
|
||||
PropertyChangedX?.Invoke((TObject)this, new(propertyName, oldValue, newValue));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangingEventHandler? PropertyChanging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangingXEventHandler<TObject>? PropertyChangingX;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedXEventHandler<TObject>? PropertyChangedX;
|
||||
#endregion
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变后事件参数
|
||||
/// </summary>
|
||||
public class PropertyChangedXEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 属性名
|
||||
/// </summary>
|
||||
public string PropertyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 旧值
|
||||
/// </summary>
|
||||
public object? OldValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 新值
|
||||
/// </summary>
|
||||
public object? NewValue { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <param name="oldValue">旧值</param>
|
||||
/// <param name="newValue">新值</param>
|
||||
public PropertyChangedXEventArgs(string propertyName, object? oldValue, object? newValue)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
OldValue = oldValue;
|
||||
NewValue = newValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变后事件
|
||||
/// </summary>
|
||||
/// <param name="sender">发送者</param>
|
||||
/// <param name="e">参数</param>
|
||||
public delegate void PropertyChangedXEventHandler<TSender>(
|
||||
TSender sender,
|
||||
PropertyChangedXEventArgs e
|
||||
);
|
@ -0,0 +1,35 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变前事件参数
|
||||
/// </summary>
|
||||
public class PropertyChangingXEventArgs : CancelEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 属性名
|
||||
/// </summary>
|
||||
public string PropertyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 旧值
|
||||
/// </summary>
|
||||
public object? OldValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 新值
|
||||
/// </summary>
|
||||
public object? NewValue { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <param name="oldValue">旧值</param>
|
||||
/// <param name="newValue">新值</param>
|
||||
public PropertyChangingXEventArgs(string propertyName, object? oldValue, object? newValue)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
OldValue = oldValue;
|
||||
NewValue = newValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 属性改变前事件
|
||||
/// </summary>
|
||||
/// <param name="sender">发送者</param>
|
||||
/// <param name="e">参数</param>
|
||||
public delegate void PropertyChangingXEventHandler<TSender>(
|
||||
TSender sender,
|
||||
PropertyChangingXEventArgs e
|
||||
);
|
@ -0,0 +1,12 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行命令事件
|
||||
/// </summary>
|
||||
public delegate Task ExecuteAsyncEventHandler();
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行命令事件
|
||||
/// </summary>
|
||||
/// <param name="parameter">值</param>
|
||||
public delegate Task ExecuteAsyncEventHandler<T>(T parameter);
|
@ -0,0 +1,12 @@
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 执行事件
|
||||
/// </summary>
|
||||
public delegate void ExecuteEventHandler();
|
||||
|
||||
/// <summary>
|
||||
/// 执行事件
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
public delegate void ExecuteEventHandler<T>(T parameter);
|
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 通知接收器
|
||||
/// </summary>
|
||||
/// <param name="sender">发送者</param>
|
||||
/// <param name="e">参数</param>
|
||||
public delegate void NotifyReceivedEventHandler(ICommand sender, CancelEventArgs e);
|
@ -0,0 +1,115 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 可观察命令
|
||||
/// </summary>
|
||||
[DebuggerDisplay("\\{ObservableCommand, CanExecute = {IsCanExecute.Value}\\}")]
|
||||
public class ObservableCommand : ObservableClass<ObservableCommand>, ICommand
|
||||
{
|
||||
bool _isCanExecute = true;
|
||||
|
||||
/// <summary>
|
||||
/// 能执行的属性
|
||||
/// </summary>
|
||||
public bool IsCanExecute
|
||||
{
|
||||
get => _isCanExecute;
|
||||
set => SetProperty(ref _isCanExecute, value);
|
||||
}
|
||||
|
||||
bool _currentCanExecute = true;
|
||||
|
||||
/// <summary>
|
||||
/// 当前可执行状态
|
||||
/// <para>
|
||||
/// 在执行异步事件时会强制为 <see langword="false"/>, 但异步结束后会恢复为 <see cref="IsCanExecute"/> 的值
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool CurrentCanExecute
|
||||
{
|
||||
get => _currentCanExecute;
|
||||
private set => SetProperty(ref _currentCanExecute, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCommand()
|
||||
{
|
||||
PropertyChanged += OnCanExecuteChanged;
|
||||
}
|
||||
|
||||
private void OnCanExecuteChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
CanExecuteChanged?.Invoke(this, new());
|
||||
}
|
||||
|
||||
#region ICommand
|
||||
/// <summary>
|
||||
/// 能否被执行
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
/// <returns>能被执行为 <see langword="true"/> 否则为 <see langword="false"/></returns>
|
||||
public bool CanExecute(object? parameter)
|
||||
{
|
||||
return CurrentCanExecute && IsCanExecute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
public async void Execute(object? parameter)
|
||||
{
|
||||
if (IsCanExecute is not true)
|
||||
return;
|
||||
ExecuteCommand?.Invoke();
|
||||
await ExecuteAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步方法, 会在等待中修改 <see cref="CurrentCanExecute"/>, 完成后恢复
|
||||
/// <para>
|
||||
/// 若要在执行此方法时触发 <see cref="ExecuteCommand"/> 事件, 请将 <paramref name="runAlone"/> 设置为 <see langword="true"/>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="runAlone">设置为 <see langword="true"/> 时触发 <see cref="ExecuteCommand"/> 事件</param>
|
||||
/// <returns>任务</returns>
|
||||
public async Task ExecuteAsync(bool runAlone = false)
|
||||
{
|
||||
if (IsCanExecute is not true)
|
||||
return;
|
||||
if (runAlone)
|
||||
ExecuteCommand?.Invoke();
|
||||
if (ExecuteAsyncCommand is null)
|
||||
return;
|
||||
CurrentCanExecute = false;
|
||||
foreach (
|
||||
var asyncEvent in ExecuteAsyncCommand
|
||||
.GetInvocationList()
|
||||
.Cast<ExecuteAsyncEventHandler>()
|
||||
)
|
||||
await asyncEvent.Invoke();
|
||||
CurrentCanExecute = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
/// <summary>
|
||||
/// 能否执行属性改变后事件
|
||||
/// </summary>
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 执行事件
|
||||
/// </summary>
|
||||
public event ExecuteEventHandler? ExecuteCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行事件
|
||||
/// </summary>
|
||||
public event ExecuteAsyncEventHandler? ExecuteAsyncCommand;
|
||||
#endregion
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HKW.HKWUtils.Observable;
|
||||
|
||||
/// <summary>
|
||||
/// 具有参数的可观察命令
|
||||
/// </summary>
|
||||
[DebuggerDisplay("\\{ObservableCommand, CanExecute = {IsCanExecute.Value}\\}")]
|
||||
public class ObservableCommand<T> : ObservableClass<ObservableCommand>, ICommand
|
||||
{
|
||||
bool _isCanExecute = true;
|
||||
|
||||
/// <summary>
|
||||
/// 能执行的属性
|
||||
/// </summary>
|
||||
public bool IsCanExecute
|
||||
{
|
||||
get => _isCanExecute;
|
||||
set => SetProperty(ref _isCanExecute, value);
|
||||
}
|
||||
|
||||
bool _currentCanExecute = true;
|
||||
|
||||
/// <summary>
|
||||
/// 当前可执行状态
|
||||
/// <para>
|
||||
/// 在执行异步事件时会强制为 <see langword="false"/>, 但异步结束后会恢复为 <see cref="IsCanExecute"/> 的值
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool CurrentCanExecute
|
||||
{
|
||||
get => _currentCanExecute;
|
||||
private set => SetProperty(ref _currentCanExecute, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCommand()
|
||||
{
|
||||
PropertyChanged += OnCanExecuteChanged;
|
||||
}
|
||||
|
||||
private void OnCanExecuteChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
CanExecuteChanged?.Invoke(this, new());
|
||||
}
|
||||
|
||||
#region ICommand
|
||||
/// <summary>
|
||||
/// 能否被执行
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
/// <returns>能被执行为 <see langword="true"/> 否则为 <see langword="false"/></returns>
|
||||
public bool CanExecute(object? parameter)
|
||||
{
|
||||
return CurrentCanExecute && IsCanExecute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
public async void Execute(object? parameter)
|
||||
{
|
||||
if (IsCanExecute is not true)
|
||||
return;
|
||||
ExecuteCommand?.Invoke((T)parameter!);
|
||||
await ExecuteAsync((T)parameter!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步方法, 会在等待中修改 <see cref="CurrentCanExecute"/>, 完成后恢复
|
||||
/// <para>
|
||||
/// 若要在执行此方法时触发 <see cref="ExecuteCommand"/> 事件, 请将 <paramref name="runAlone"/> 设置为 <see langword="true"/>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="parameter">参数</param>
|
||||
/// <param name="runAlone">设置为 <see langword="true"/> 时触发 <see cref="ExecuteCommand"/> 事件</param>
|
||||
/// <returns>任务</returns>
|
||||
public async Task ExecuteAsync(T parameter, bool runAlone = false)
|
||||
{
|
||||
if (IsCanExecute is not true)
|
||||
return;
|
||||
if (runAlone)
|
||||
ExecuteCommand?.Invoke(parameter);
|
||||
if (ExecuteAsyncCommand is null)
|
||||
return;
|
||||
CurrentCanExecute = false;
|
||||
foreach (
|
||||
var asyncEvent in ExecuteAsyncCommand
|
||||
.GetInvocationList()
|
||||
.Cast<ExecuteAsyncEventHandler<T>>()
|
||||
)
|
||||
await asyncEvent.Invoke(parameter);
|
||||
CurrentCanExecute = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
/// <summary>
|
||||
/// 能否执行属性改变后事件
|
||||
/// </summary>
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 执行事件
|
||||
/// </summary>
|
||||
public event ExecuteEventHandler<T>? ExecuteCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行事件
|
||||
/// </summary>
|
||||
public event ExecuteAsyncEventHandler<T>? ExecuteAsyncCommand;
|
||||
#endregion
|
||||
}
|
136
VPet.Solution/Styles.xaml
Normal file
136
VPet.Solution/Styles.xaml
Normal file
@ -0,0 +1,136 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:pu="https://opensource.panuon.com/wpf-ui">
|
||||
<Style
|
||||
x:Key="AddButton"
|
||||
BasedOn="{StaticResource {x:Type Button}}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Background" Value="{StaticResource DARKPrimary}" />
|
||||
<Setter Property="pu:ButtonHelper.ShadowColor" Value="{StaticResource ShadowColor}" />
|
||||
<Setter Property="FontSize" Value="24" />
|
||||
<Setter Property="Padding" Value="10" />
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="pu:ButtonHelper.CornerRadius" Value="24" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="Button_Cancel"
|
||||
BasedOn="{StaticResource ThemedButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Background" Value="{StaticResource PrimaryLight}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource SecondaryText}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="Button_HiddenOnTagNull"
|
||||
BasedOn="{StaticResource ThemedButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Mode=Self}}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="Button_CollapsedOnTagNull"
|
||||
BasedOn="{StaticResource ThemedButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Mode=Self}}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBlock_Wrap"
|
||||
BasedOn="{StaticResource {x:Type TextBlock}}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBlock_Center"
|
||||
BasedOn="{StaticResource {x:Type TextBlock}}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBlock_LeftCenter"
|
||||
BasedOn="{StaticResource {x:Type TextBlock}}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBox_Wrap"
|
||||
BasedOn="{StaticResource {x:Type TextBox}}"
|
||||
TargetType="TextBox">
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBox_Center"
|
||||
BasedOn="{StaticResource {x:Type TextBox}}"
|
||||
TargetType="TextBox">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TextBox_LeftCenter"
|
||||
BasedOn="{StaticResource {x:Type TextBox}}"
|
||||
TargetType="TextBox">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" />
|
||||
</Style>
|
||||
<Style x:Key="WindowXStyle" TargetType="pu:WindowX">
|
||||
<Setter Property="pu:WindowXCaption.Background" Value="{DynamicResource DARKPrimary}" />
|
||||
<Setter Property="pu:WindowXCaption.Foreground" Value="{DynamicResource DARKPrimaryText}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="Menu_Style"
|
||||
BasedOn="{StaticResource {x:Static pu:StyleKeys.MenuStyle}}"
|
||||
TargetType="Menu">
|
||||
<Setter Property="Height" Value="NaN" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource DARKPrimaryText}" />
|
||||
<Setter Property="Background" Value="{DynamicResource DARKPrimary}" />
|
||||
<Setter Property="pu:MenuHelper.CornerRadius" Value="4" />
|
||||
|
||||
<Setter Property="pu:DropDownHelper.CornerRadius" Value="4" />
|
||||
<!-- -->
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsBorderThickness" Value="0" />
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsPadding" Value="5,0,5,0" />
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsMargin" Value="0" />
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsHorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsBackground" Value="{DynamicResource DARKPrimary}" />
|
||||
<Setter Property="pu:MenuHelper.TopLevelItemsForeground" Value="{DynamicResource DARKPrimaryText}" />
|
||||
<!-- -->
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsBorderThickness" Value="0" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsBorderBrush" Value="{DynamicResource DARKPrimary}" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsWidth" Value="NaN" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsHeight" Value="NaN" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsPadding" Value="5" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsMargin" Value="0" />
|
||||
<!--<Setter Property="pu:MenuHelper.SubmenuItemsCornerRadius" Value="4" />-->
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsBackground" Value="{DynamicResource DARKPrimary}" />
|
||||
<Setter Property="pu:MenuHelper.SubmenuItemsForeground" Value="{DynamicResource DARKPrimaryText}" />
|
||||
<!--<Setter Property="Width" Value="NaN" />
|
||||
<Setter Property="Height" Value="NaN" />
|
||||
<Setter Property="Padding" Value="5" />
|
||||
<Setter Property="Background" Value="{DynamicResource BackgroundColor}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ForegroundColor}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource BodyFontSize}" />
|
||||
<Setter Property="pu:MenuItemHelper.HoverBackground" Value="{DynamicResource HoverColor}" />
|
||||
<Setter Property="pu:MenuItemHelper.ClickBackground" Value="{DynamicResource ClickColor}" />
|
||||
<Setter Property="pu:MenuItemHelper.CheckedBackground" Value="{DynamicResource CheckedColor}" />-->
|
||||
</Style>
|
||||
</ResourceDictionary>
|
58
VPet.Solution/Templates.xaml
Normal file
58
VPet.Solution/Templates.xaml
Normal file
@ -0,0 +1,58 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
|
||||
xmlns:pu="https://opensource.panuon.com/wpf-ui">
|
||||
<ContextMenu x:Key="ContextMenu_DataGridRow" x:Shared="false">
|
||||
<MenuItem
|
||||
Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource AncestorType=Page, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}}"
|
||||
Header="{ll:Str 修改}" />
|
||||
<MenuItem
|
||||
Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType=Page, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}}"
|
||||
Header="{ll:Str 删除}" />
|
||||
</ContextMenu>
|
||||
<ControlTemplate x:Key="ListBoxItem_RangeData" TargetType="ListBoxItem">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Label HorizontalContentAlignment="Center" Content="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="{ll:Str 最小值}" />
|
||||
<pu:NumberInput
|
||||
Grid.Column="1"
|
||||
ToolTip="{Binding Value, RelativeSource={RelativeSource Mode=Self}}"
|
||||
Value="{Binding DataContext.Min.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
<Label Grid.Row="1" Content="{ll:Str 最大值}" />
|
||||
<pu:NumberInput
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
ToolTip="{Binding Value, RelativeSource={RelativeSource Mode=Self}}"
|
||||
Value="{Binding DataContext.Max.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="ListBox_ShowLangs" TargetType="ListBox">
|
||||
<ListBox
|
||||
ItemsSource="{Binding I18nData.CultureNames}"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
SelectedItem="{Binding I18nData.CultureName.Value}">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource {x:Type ListBoxItem}}" TargetType="ListBoxItem">
|
||||
<Setter Property="Content" Value="{Binding}" />
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
</ListBox>
|
||||
</ControlTemplate>
|
||||
</ResourceDictionary>
|
6
VPet.Solution/Usings.cs
Normal file
6
VPet.Solution/Usings.cs
Normal file
@ -0,0 +1,6 @@
|
||||
global using global::HKW.HKWUtils.Observable;
|
||||
global using global::System;
|
||||
global using global::System.Collections.Generic;
|
||||
global using global::System.IO;
|
||||
global using global::System.Linq;
|
||||
global using global::System.Threading.Tasks;
|
312
VPet.Solution/Utils/Expansions.cs
Normal file
312
VPet.Solution/Utils/Expansions.cs
Normal file
@ -0,0 +1,312 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 拓展
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="comparisonType"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Contains(this string source, string value, StringComparison comparisonType)
|
||||
{
|
||||
return source.IndexOf(value, comparisonType) >= 0;
|
||||
}
|
||||
|
||||
//public static string GetSourceFile(this BitmapImage image)
|
||||
//{
|
||||
// return ((FileStream)image.StreamSource).Name;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭流
|
||||
/// </summary>
|
||||
/// <param name="source">图像资源</param>
|
||||
public static void CloseStream(this ImageSource source)
|
||||
{
|
||||
if (source is not BitmapImage image)
|
||||
return;
|
||||
image.StreamSource?.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 图像复制
|
||||
/// </summary>
|
||||
/// <param name="image">图像</param>
|
||||
/// <returns>复制的图像</returns>
|
||||
public static BitmapImage Copy(this BitmapImage image)
|
||||
{
|
||||
if (image is null)
|
||||
return null;
|
||||
BitmapImage newImage = new();
|
||||
newImage.BeginInit();
|
||||
newImage.DecodePixelWidth = image.DecodePixelWidth;
|
||||
newImage.DecodePixelHeight = image.DecodePixelHeight;
|
||||
try
|
||||
{
|
||||
using var bitmap = new Bitmap(image.StreamSource);
|
||||
var ms = new MemoryStream();
|
||||
bitmap.Save(ms, ImageFormat.Png);
|
||||
image.StreamSource.CopyTo(ms);
|
||||
newImage.StreamSource = ms;
|
||||
}
|
||||
finally
|
||||
{
|
||||
newImage.EndInit();
|
||||
}
|
||||
return newImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存至Png图片
|
||||
/// </summary>
|
||||
/// <param name="image">图片资源</param>
|
||||
/// <param name="path">路径</param>
|
||||
//public static void SaveToPng(this BitmapImage image, string path)
|
||||
//{
|
||||
// if (image is null)
|
||||
// return;
|
||||
// if (path.EndsWith(".png") is false)
|
||||
// path += ".png";
|
||||
// var encoder = new PngBitmapEncoder();
|
||||
// var stream = image.StreamSource;
|
||||
// // 保存位置
|
||||
// var position = stream.Position;
|
||||
// // 必须要重置位置, 否则EndInit将出错
|
||||
// stream.Seek(0, SeekOrigin.Begin);
|
||||
// encoder.Frames.Add(BitmapFrame.Create(image.StreamSource));
|
||||
// // 恢复位置
|
||||
// stream.Seek(position, SeekOrigin.Begin);
|
||||
// using var fs = new FileStream(path, FileMode.Create);
|
||||
// encoder.Save(fs);
|
||||
//}
|
||||
public static void SaveToPng(this BitmapImage image, string path)
|
||||
{
|
||||
if (image is null)
|
||||
return;
|
||||
if (path.EndsWith(".png") is false)
|
||||
path += ".png";
|
||||
var stream = image.StreamSource;
|
||||
// 保存位置
|
||||
var position = stream.Position;
|
||||
// 必须要重置位置, 否则EndInit将出错
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
using var fs = new FileStream(path, FileMode.Create);
|
||||
stream.CopyTo(fs);
|
||||
// 恢复位置
|
||||
stream.Seek(position, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试添加
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">键类型</typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="dictionary"></param>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
public static bool TryAdd<TKey, TValue>(
|
||||
this IDictionary<TKey, TValue> dictionary,
|
||||
TKey key,
|
||||
TValue value
|
||||
)
|
||||
{
|
||||
if (dictionary.ContainsKey(key))
|
||||
return false;
|
||||
dictionary.Add(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流内容对比
|
||||
/// </summary>
|
||||
/// <param name="source">原始流</param>
|
||||
/// <param name="target">目标流</param>
|
||||
/// <param name="bufferLength">缓冲区大小 (越大速度越快(流内容越大效果越明显), 但会提高内存占用 (bufferSize = bufferLength * sizeof(long) * 2))</param>
|
||||
/// <returns>内容相同为 <see langword="true"/> 否则为 <see langword="false"/></returns>
|
||||
public static bool ContentsEqual(this Stream source, Stream target, int bufferLength = 8)
|
||||
{
|
||||
int bufferSize = bufferLength * sizeof(long);
|
||||
var sourceBuffer = new byte[bufferSize];
|
||||
var targetBuffer = new byte[bufferSize];
|
||||
while (true)
|
||||
{
|
||||
int sourceCount = ReadFullBuffer(source, sourceBuffer);
|
||||
int targetCount = ReadFullBuffer(target, targetBuffer);
|
||||
if (sourceCount != targetCount)
|
||||
return false;
|
||||
if (sourceCount == 0)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < sourceCount; i += sizeof(long))
|
||||
if (BitConverter.ToInt64(sourceBuffer, i) != BitConverter.ToInt64(targetBuffer, i))
|
||||
return false;
|
||||
}
|
||||
static int ReadFullBuffer(Stream stream, byte[] buffer)
|
||||
{
|
||||
int bytesRead = 0;
|
||||
while (bytesRead < buffer.Length)
|
||||
{
|
||||
int read = stream.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||||
if (read == 0)
|
||||
return bytesRead;
|
||||
bytesRead += read;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
public static T? FindVisualChild<T>(this DependencyObject obj)
|
||||
where T : DependencyObject
|
||||
{
|
||||
if (obj is null)
|
||||
return null;
|
||||
var count = VisualTreeHelper.GetChildrenCount(obj);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(obj, i);
|
||||
if (child is T t)
|
||||
return t;
|
||||
if (FindVisualChild<T>(child) is T childItem)
|
||||
return childItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static T FindParent<T>(this DependencyObject obj)
|
||||
where T : class
|
||||
{
|
||||
while (obj != null)
|
||||
{
|
||||
if (obj is T)
|
||||
return obj as T;
|
||||
obj = VisualTreeHelper.GetParent(obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetFullInfo(this CultureInfo cultureInfo)
|
||||
{
|
||||
return $"{cultureInfo.DisplayName} [{cultureInfo.Name}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试使用索引获取值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">值类型</typeparam>
|
||||
/// <param name="list">列表</param>
|
||||
/// <param name="index">索引</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
public static bool TryGetValue<T>(this IList<T> list, int index, out T value)
|
||||
{
|
||||
value = default;
|
||||
if (index < 0 || index >= list.Count)
|
||||
return false;
|
||||
value = list[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试使用索引获取值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">值类型</typeparam>
|
||||
/// <param name="list">列表</param>
|
||||
/// <param name="index">索引</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>成功为 <see langword="true"/> 失败为 <see langword="false"/></returns>
|
||||
public static bool TryGetValue<T>(this IList list, int index, out object value)
|
||||
{
|
||||
value = default;
|
||||
if (index < 0 || index >= list.Count)
|
||||
return false;
|
||||
value = list[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取目标
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="weakReference">弱引用</param>
|
||||
/// <returns>获取成功返回目标值, 获取失败则返回 <see langword="null"/></returns>
|
||||
public static T? GetTarget<T>(this WeakReference<T> weakReference)
|
||||
where T : class
|
||||
{
|
||||
return weakReference.TryGetTarget(out var t) ? t : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 枚举出带有索引值的枚举值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">值类型</typeparam>
|
||||
/// <param name="collection">集合</param>
|
||||
/// <returns>带有索引的枚举值</returns>
|
||||
public static IEnumerable<ItemInfo<T>> Enumerate<T>(this IEnumerable<T> collection)
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
yield return new(index++, item);
|
||||
}
|
||||
|
||||
public static void SetDataContext<T>(this Window window)
|
||||
where T : new()
|
||||
{
|
||||
window.DataContext = new T();
|
||||
window.Closed += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
window.DataContext = null;
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 项信息
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DebuggerDisplay("[{Index}, {Value}]")]
|
||||
public readonly struct ItemInfo<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引值
|
||||
/// </summary>
|
||||
public int Index { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public T Value { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <param name="value">值</param>
|
||||
/// <param name="index">索引值</param>
|
||||
public ItemInfo(int index, T value)
|
||||
{
|
||||
Index = index;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{Index}, {Value}]";
|
||||
}
|
||||
}
|
66
VPet.Solution/Utils/HashCode.cs
Normal file
66
VPet.Solution/Utils/HashCode.cs
Normal file
@ -0,0 +1,66 @@
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 哈希值
|
||||
/// </summary>
|
||||
public class HashCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认种子
|
||||
/// </summary>
|
||||
public const int DefaultSeed = 114514;
|
||||
|
||||
/// <summary>
|
||||
/// 默认系数
|
||||
/// </summary>
|
||||
public const int DefaultFactor = 1919810;
|
||||
|
||||
/// <summary>
|
||||
/// 组合哈希值
|
||||
/// </summary>
|
||||
/// <param name="values">值</param>
|
||||
/// <returns>组合的哈希值</returns>
|
||||
public static int Combine(params object[] values)
|
||||
{
|
||||
return CustomHash(DefaultSeed, DefaultFactor, values.Select(v => v.GetHashCode()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组合哈希值
|
||||
/// </summary>
|
||||
/// <param name="seed">种子</param>
|
||||
/// <param name="factor">系数</param>
|
||||
/// <param name="values">值</param>
|
||||
/// <returns>组合的哈希值</returns>
|
||||
public static int Combine(int seed, int factor, params object[] values)
|
||||
{
|
||||
return CustomHash(seed, factor, values.Select(v => v.GetHashCode()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义组合哈希
|
||||
/// </summary>
|
||||
/// <param name="seed">种子</param>
|
||||
/// <param name="factor">系数</param>
|
||||
/// <param name="collection">哈希集合</param>
|
||||
/// <returns>组合的哈希</returns>
|
||||
public static int CustomHash(int seed, int factor, IEnumerable<int> collection)
|
||||
{
|
||||
int hash = seed;
|
||||
foreach (int i in collection)
|
||||
hash = unchecked((hash * factor) + i);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义组合哈希
|
||||
/// </summary>
|
||||
/// <param name="seed">种子</param>
|
||||
/// <param name="factor">系数</param>
|
||||
/// <param name="values">哈希集合</param>
|
||||
/// <returns>组合的哈希</returns>
|
||||
public static int CustomHash(int seed, int factor, params int[] values)
|
||||
{
|
||||
return CustomHash(seed, factor, collection: values);
|
||||
}
|
||||
}
|
72
VPet.Solution/Utils/ObservableEnumFlags.cs
Normal file
72
VPet.Solution/Utils/ObservableEnumFlags.cs
Normal file
@ -0,0 +1,72 @@
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 可观察的枚举标签模型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
public class ObservableEnumFlags<T> : ObservableClass<ObservableEnumFlags<T>>
|
||||
where T : Enum
|
||||
{
|
||||
private T _EnumValue;
|
||||
public T EnumValue
|
||||
{
|
||||
get => _EnumValue;
|
||||
set => SetProperty(ref _EnumValue, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加枚举命令
|
||||
/// </summary>
|
||||
public ObservableCommand<T> AddCommand { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 删除枚举命令
|
||||
/// </summary>
|
||||
public ObservableCommand<T> RemoveCommand { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 枚举类型
|
||||
/// </summary>
|
||||
public Type EnumType = typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// 枚举基类
|
||||
/// </summary>
|
||||
public Type UnderlyingType { get; } = Enum.GetUnderlyingType(typeof(T));
|
||||
|
||||
public ObservableEnumFlags()
|
||||
{
|
||||
if (Attribute.IsDefined(EnumType, typeof(FlagsAttribute)) is false)
|
||||
throw new Exception($"此枚举类型未使用特性 [{nameof(FlagsAttribute)}]");
|
||||
AddCommand.ExecuteCommand += AddCommand_Execute;
|
||||
RemoveCommand.ExecuteCommand += RemoveCommand_Execute;
|
||||
}
|
||||
|
||||
public ObservableEnumFlags(T value)
|
||||
: this()
|
||||
{
|
||||
EnumValue = value;
|
||||
}
|
||||
|
||||
private void AddCommand_Execute(T v)
|
||||
{
|
||||
if (UnderlyingType == typeof(int))
|
||||
{
|
||||
EnumValue = (T)
|
||||
Enum.Parse(EnumType, (Convert.ToInt32(EnumValue) | Convert.ToInt32(v)).ToString());
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException($"Value type: {UnderlyingType}");
|
||||
}
|
||||
|
||||
private void RemoveCommand_Execute(T v)
|
||||
{
|
||||
if (UnderlyingType == typeof(int))
|
||||
{
|
||||
EnumValue = (T)
|
||||
Enum.Parse(EnumType, (Convert.ToInt32(EnumValue) & ~Convert.ToInt32(v)).ToString());
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException($"Value type: {UnderlyingType}");
|
||||
}
|
||||
}
|
77
VPet.Solution/Utils/ObservablePoint.cs
Normal file
77
VPet.Solution/Utils/ObservablePoint.cs
Normal file
@ -0,0 +1,77 @@
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 可观察地点
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public class ObservablePoint<T>
|
||||
: ObservableClass<ObservablePoint<T>>,
|
||||
IEquatable<ObservablePoint<T>>
|
||||
{
|
||||
private T _x;
|
||||
public T X
|
||||
{
|
||||
get => _x;
|
||||
set => SetProperty(ref _x, value);
|
||||
}
|
||||
|
||||
private T _y;
|
||||
public T Y
|
||||
{
|
||||
get => _y;
|
||||
set => SetProperty(ref _y, value);
|
||||
}
|
||||
|
||||
public ObservablePoint() { }
|
||||
|
||||
public ObservablePoint(T x, T y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制一个新的对象
|
||||
/// </summary>
|
||||
/// <returns>新对象</returns>
|
||||
public ObservablePoint<T> Copy()
|
||||
{
|
||||
return new(X, Y);
|
||||
}
|
||||
|
||||
#region Other
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(X, Y);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ObservablePoint<T> temp
|
||||
&& EqualityComparer<T>.Default.Equals(X, temp.X)
|
||||
&& EqualityComparer<T>.Default.Equals(Y, temp.Y);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(ObservablePoint<T>? other)
|
||||
{
|
||||
return Equals(obj: other);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator ==(ObservablePoint<T> a, ObservablePoint<T> b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(ObservablePoint<T> a, ObservablePoint<T> b)
|
||||
{
|
||||
return Equals(a, b) is not true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
77
VPet.Solution/Utils/ObservableRange.cs
Normal file
77
VPet.Solution/Utils/ObservableRange.cs
Normal file
@ -0,0 +1,77 @@
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 可观察的范围
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public class ObservableRange<T>
|
||||
: ObservableClass<ObservableRange<T>>,
|
||||
IEquatable<ObservableRange<T>>
|
||||
{
|
||||
private T _min;
|
||||
public T Min
|
||||
{
|
||||
get => _min;
|
||||
set => SetProperty(ref _min, value);
|
||||
}
|
||||
|
||||
private T _max;
|
||||
public T Max
|
||||
{
|
||||
get => _max;
|
||||
set => SetProperty(ref _max, value);
|
||||
}
|
||||
|
||||
public ObservableRange() { }
|
||||
|
||||
public ObservableRange(T min, T max)
|
||||
{
|
||||
_min = min;
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制一个新的对象
|
||||
/// </summary>
|
||||
/// <returns>新对象</returns>
|
||||
public ObservableRange<T> Copy()
|
||||
{
|
||||
return new(Min, Max);
|
||||
}
|
||||
|
||||
#region Other
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Min, Max);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ObservableRange<T> temp
|
||||
&& EqualityComparer<T>.Default.Equals(Min, temp.Min)
|
||||
&& EqualityComparer<T>.Default.Equals(Max, temp.Max);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(ObservableRange<T>? other)
|
||||
{
|
||||
return Equals(obj: other);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator ==(ObservableRange<T> a, ObservableRange<T> b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(ObservableRange<T> a, ObservableRange<T> b)
|
||||
{
|
||||
return Equals(a, b) is not true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
89
VPet.Solution/Utils/ObservableRect.cs
Normal file
89
VPet.Solution/Utils/ObservableRect.cs
Normal file
@ -0,0 +1,89 @@
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
public class ObservableRect<T> : ObservableClass<ObservableRect<T>>, IEquatable<ObservableRect<T>>
|
||||
{
|
||||
private T _x;
|
||||
public T X
|
||||
{
|
||||
get => _x;
|
||||
set => SetProperty(ref _x, value);
|
||||
}
|
||||
|
||||
private T _y;
|
||||
public T Y
|
||||
{
|
||||
get => _y;
|
||||
set => SetProperty(ref _y, value);
|
||||
}
|
||||
|
||||
private T _width;
|
||||
public T Width
|
||||
{
|
||||
get => _width;
|
||||
set => SetProperty(ref _width, value);
|
||||
}
|
||||
|
||||
private T _heigth;
|
||||
public T Height
|
||||
{
|
||||
get => _heigth;
|
||||
set => SetProperty(ref _heigth, value);
|
||||
}
|
||||
|
||||
public ObservableRect() { }
|
||||
|
||||
public ObservableRect(T x, T y, T width, T hetght)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = hetght;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制一个新的对象
|
||||
/// </summary>
|
||||
/// <returns>新对象</returns>
|
||||
public ObservableRect<T> Copy()
|
||||
{
|
||||
return new(X, Y, Width, Height);
|
||||
}
|
||||
|
||||
#region Other
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(X, Y, Width, Height);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ObservableRect<T> temp
|
||||
&& EqualityComparer<T>.Default.Equals(X, temp.X)
|
||||
&& EqualityComparer<T>.Default.Equals(Y, temp.Y)
|
||||
&& EqualityComparer<T>.Default.Equals(Width, temp.Width)
|
||||
&& EqualityComparer<T>.Default.Equals(Height, temp.Height);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(ObservableRect<T>? other)
|
||||
{
|
||||
return Equals(obj: other);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator ==(ObservableRect<T> a, ObservableRect<T> b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(ObservableRect<T> a, ObservableRect<T> b)
|
||||
{
|
||||
return Equals(a, b) is not true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
79
VPet.Solution/Utils/Utils.cs
Normal file
79
VPet.Solution/Utils/Utils.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace HKW.HKWUtils;
|
||||
|
||||
/// <summary>
|
||||
/// 工具
|
||||
/// </summary>
|
||||
public static class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 解码像素宽度
|
||||
/// </summary>
|
||||
public const int DecodePixelWidth = 250;
|
||||
|
||||
/// <summary>
|
||||
/// 解码像素高度
|
||||
/// </summary>
|
||||
public const int DecodePixelHeight = 250;
|
||||
public static char[] Separator { get; } = new char[] { '_' };
|
||||
|
||||
//public static BitmapImage LoadImageToStream(string imagePath)
|
||||
//{
|
||||
// BitmapImage bitmapImage = new();
|
||||
// bitmapImage.BeginInit();
|
||||
// bitmapImage.DecodePixelWidth = DecodePixelWidth;
|
||||
// try
|
||||
// {
|
||||
// bitmapImage.StreamSource = new StreamReader(imagePath).BaseStream;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// bitmapImage.EndInit();
|
||||
// }
|
||||
// return bitmapImage;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 载入图片至内存流
|
||||
/// </summary>
|
||||
/// <param name="imagePath">图片路径</param>
|
||||
/// <returns></returns>
|
||||
public static BitmapImage LoadImageToMemoryStream(string imagePath)
|
||||
{
|
||||
BitmapImage bitmapImage = new();
|
||||
bitmapImage.BeginInit();
|
||||
try
|
||||
{
|
||||
var bytes = File.ReadAllBytes(imagePath);
|
||||
bitmapImage.StreamSource = new MemoryStream(bytes);
|
||||
bitmapImage.DecodePixelWidth = DecodePixelWidth;
|
||||
}
|
||||
finally
|
||||
{
|
||||
bitmapImage.EndInit();
|
||||
}
|
||||
return bitmapImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入图片至内存流
|
||||
/// </summary>
|
||||
/// <param name="imageStream">图片流</param>
|
||||
/// <returns></returns>
|
||||
public static BitmapImage LoadImageToMemoryStream(Stream imageStream)
|
||||
{
|
||||
BitmapImage bitmapImage = new();
|
||||
bitmapImage.BeginInit();
|
||||
try
|
||||
{
|
||||
bitmapImage.StreamSource = imageStream;
|
||||
bitmapImage.DecodePixelWidth = DecodePixelWidth;
|
||||
}
|
||||
finally
|
||||
{
|
||||
bitmapImage.EndInit();
|
||||
}
|
||||
return bitmapImage;
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -39,7 +41,8 @@
|
||||
<HintPath>..\packages\LinePutScript.1.9.2\lib\net462\LinePutScript.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="LinePutScript.Localization.WPF, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\LinePutScript.Localization.WPF.1.0.6\lib\net462\LinePutScript.Localization.WPF.dll</HintPath>
|
||||
<HintPath>
|
||||
..\packages\LinePutScript.Localization.WPF.1.0.6\lib\net462\LinePutScript.Localization.WPF.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Panuon.WPF, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Panuon.WPF.1.0.2\lib\net462\Panuon.WPF.dll</HintPath>
|
||||
@ -49,6 +52,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
@ -67,7 +71,7 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Page Include="Views\MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@ -75,9 +79,50 @@
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<Compile Include="ViewModels\MainWindowVM.cs" />
|
||||
<Compile Include="Views\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Converters\BrushToMediaColorConverter.cs" />
|
||||
<Compile Include="Converters\CalculatorConverter.cs" />
|
||||
<Compile Include="Converters\EqualsConverter.cs" />
|
||||
<Compile Include="Converters\FalseToCollapsedConverter.cs" />
|
||||
<Compile Include="Converters\FalseToHiddenConverter.cs" />
|
||||
<Compile Include="Converters\MediaColorToBrushConverter.cs" />
|
||||
<Compile Include="Converters\NotEqualsConverter.cs" />
|
||||
<Compile Include="Converters\NullToFalseConverter.cs" />
|
||||
<Compile Include="Converters\StringFormatConverter.cs" />
|
||||
<Compile Include="Converters\RatioMarginConverter.cs" />
|
||||
<Compile Include="Converters\MaxConverter.cs" />
|
||||
<Compile Include="Converters\MarginConverter.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\INotifyPropertyChangedX.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\INotifyPropertyChangingX.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\ObservableClass.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\PropertyChangedXEventArgs.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\PropertyChangedXEventHandler.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\PropertyChangingXEventArgs.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableClass\PropertyChangingXEventHandler.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableCommand\ExecuteAsyncEventHandler.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableCommand\ExecuteEventHandler.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableCommand\NotifyReceivedEventHandler.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableCommand\ObservableCommand.cs" />
|
||||
<Compile Include="SimpleObservable\ObservableCommand\ObservableCommandT.cs" />
|
||||
<Compile Include="Utils\ObservableEnumFlags.cs" />
|
||||
<Compile Include="Utils\Expansions.cs" />
|
||||
<Compile Include="Utils\HashCode.cs" />
|
||||
<Compile Include="Utils\ObservableRange.cs" />
|
||||
<Compile Include="Utils\ObservablePoint.cs" />
|
||||
<Compile Include="Utils\ObservableRect.cs" />
|
||||
<Compile Include="Utils\Utils.cs" />
|
||||
<Compile Include="Resources\NativeResources.cs" />
|
||||
<Compile Include="Usings.cs" />
|
||||
<Page Include="NativeStyles.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
|
||||
</Page>
|
||||
<Compile Include="NativeStyles.xaml.cs">
|
||||
<DependentUpon>NativeStyles.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -117,5 +162,8 @@
|
||||
<Name>VPet-Simulator.Windows.Interface</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
22
VPet.Solution/ViewModels/MainWindowVM.cs
Normal file
22
VPet.Solution/ViewModels/MainWindowVM.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VPet_Simulator.Core;
|
||||
using VPet_Simulator.Windows.Interface;
|
||||
|
||||
namespace VPet.Solution.ViewModels;
|
||||
|
||||
public class MainWindowVM : ObservableClass<MainWindowVM>
|
||||
{
|
||||
public MainWindowVM() { }
|
||||
|
||||
public static void LoadSettings(string path)
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(path))
|
||||
{
|
||||
var setting = new Setting(path);
|
||||
}
|
||||
}
|
||||
}
|
1849
VPet.Solution/Views/MainWindow.xaml
Normal file
1849
VPet.Solution/Views/MainWindow.xaml
Normal file
File diff suppressed because it is too large
Load Diff
19
VPet.Solution/Views/MainWindow.xaml.cs
Normal file
19
VPet.Solution/Views/MainWindow.xaml.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using Panuon.WPF.UI;
|
||||
|
||||
namespace VPet.Solution;
|
||||
|
||||
/// <summary>
|
||||
/// MainWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainWindow : WindowX
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
if (App.IsDone)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user