添加项目文件。
This commit is contained in:
54
UIShare/Behaviors/MouseDoubleClickBehavior.cs
Normal file
54
UIShare/Behaviors/MouseDoubleClickBehavior.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace UIShare.Behaviors
|
||||
{
|
||||
//给Border添加双击事件
|
||||
public class MouseDoubleClickBehavior : Behavior<Border>
|
||||
{
|
||||
public static readonly DependencyProperty CommandProperty =
|
||||
DependencyProperty.Register("Command", typeof(ICommand), typeof(MouseDoubleClickBehavior), new PropertyMetadata(null));
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand)GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty =
|
||||
DependencyProperty.Register("CommandParameter", typeof(object), typeof(MouseDoubleClickBehavior), new PropertyMetadata(null));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
// 确保 Border 的 Background 不为 null,否则无法触发点击事件
|
||||
this.AssociatedObject.MouseLeftButtonDown += OnMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
this.AssociatedObject.MouseLeftButtonDown -= OnMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// 判断点击次数是否为 2
|
||||
if (e.ClickCount == 2)
|
||||
{
|
||||
if (Command != null && Command.CanExecute(CommandParameter))
|
||||
{
|
||||
Command.Execute(CommandParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
UIShare/Behaviors/TabControlSelectionChangedBehavior.cs
Normal file
59
UIShare/Behaviors/TabControlSelectionChangedBehavior.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace UIShare.Behaviors
|
||||
{
|
||||
public class TabControlSelectionChangedBehavior : Behavior<TabControl>
|
||||
{
|
||||
public static readonly DependencyProperty CommandProperty =
|
||||
DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(TabControlSelectionChangedBehavior), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty =
|
||||
DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(TabControlSelectionChangedBehavior), new PropertyMetadata(null));
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
if (AssociatedObject != null)
|
||||
{
|
||||
AssociatedObject.SelectionChanged += OnSelectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
if (AssociatedObject != null)
|
||||
{
|
||||
AssociatedObject.SelectionChanged -= OnSelectionChanged;
|
||||
}
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var tabItem = AssociatedObject.SelectedItem as TabItem;
|
||||
// 获取选中 TabItem 的 Header
|
||||
if (Command != null && Command.CanExecute(tabItem.Header))
|
||||
{
|
||||
// 使用选中 TabItem 的 Header 作为 CommandParameter
|
||||
Command.Execute(((TabItem)AssociatedObject.SelectedItem)?.Header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
UIShare/Converters/BoolArrayConverter.cs
Normal file
40
UIShare/Converters/BoolArrayConverter.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class BoolArrayConverter : IValueConverter
|
||||
{
|
||||
// bool[] -> string
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool[] arr)
|
||||
return "[" + string.Join(",", arr.Select(b => b.ToString().ToLower())) + "]";
|
||||
return "";
|
||||
}
|
||||
|
||||
// string -> bool[]
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
s = s.Trim('[', ']', ' ');
|
||||
if (string.IsNullOrWhiteSpace(s)) return Array.Empty<bool>();
|
||||
var parts = s.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
return parts.Select(p =>
|
||||
{
|
||||
if (bool.TryParse(p, out var b)) return b;
|
||||
if (p == "1") return true;
|
||||
if (p == "0") return false;
|
||||
return false;
|
||||
}).ToArray();
|
||||
}
|
||||
return Array.Empty<bool>();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
UIShare/Converters/BooleanToVisibilityConverter.cs
Normal file
40
UIShare/Converters/BooleanToVisibilityConverter.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class BooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
// 同时接受 "invert" / "inverse" / "inverted" / "reverse"(大小写不敏感)作为反转参数,
|
||||
// 避免因 XAML 处用了 ConverterParameter=Inverse 而静默失效。
|
||||
private static bool IsInvert(object parameter)
|
||||
{
|
||||
var s = parameter?.ToString()?.ToLowerInvariant();
|
||||
return s == "invert" || s == "inverse" || s == "inverted" || s == "reverse";
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
bool input = value is bool b && b;
|
||||
if (IsInvert(parameter))
|
||||
input = !input;
|
||||
|
||||
return input ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
bool output = value is Visibility v && v == Visibility.Visible;
|
||||
if (IsInvert(parameter))
|
||||
output = !output;
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
UIShare/Converters/DeviceNameConverter.cs
Normal file
49
UIShare/Converters/DeviceNameConverter.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class DeviceNameConverter : IValueConverter
|
||||
{
|
||||
private readonly string[] specialName = { "奇偶" };
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string name)
|
||||
{
|
||||
if (specialName.Contains(name))
|
||||
{
|
||||
if (parameter?.ToString() == "Inverse")
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
else if (parameter?.ToString() == "Items")
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "奇偶":
|
||||
return new List<string> { "无", "奇", "偶" };
|
||||
}
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
if (parameter?.ToString() == "Inverse")
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
UIShare/Converters/EnumValueConverter.cs
Normal file
82
UIShare/Converters/EnumValueConverter.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class EnumValueConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
// 验证输入参数
|
||||
if (values.Length < 2 || values[0] == null || values[1] == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 获取枚举类型
|
||||
Type enumType = values[0] as Type;
|
||||
if (enumType == null || !enumType.IsEnum)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取数值
|
||||
object value = values[1];
|
||||
|
||||
// 确保数值类型匹配枚举的底层类型
|
||||
Type underlyingType = Enum.GetUnderlyingType(enumType);
|
||||
object convertedValue;
|
||||
|
||||
try
|
||||
{
|
||||
convertedValue = System.Convert.ChangeType(value, underlyingType);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果转换失败,尝试直接使用原始值
|
||||
convertedValue = value;
|
||||
}
|
||||
|
||||
// 将数值转换为枚举值
|
||||
return Enum.ToObject(enumType, convertedValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 发生任何异常时返回null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 获取枚举值的底层数值
|
||||
Type enumType = value.GetType();
|
||||
if (!enumType.IsEnum)
|
||||
{
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
Type underlyingType = Enum.GetUnderlyingType(enumType);
|
||||
object numericValue = System.Convert.ChangeType(value, underlyingType);
|
||||
|
||||
// 返回枚举类型和对应的数值
|
||||
return [enumType, numericValue];
|
||||
}
|
||||
catch
|
||||
{
|
||||
return [null, null];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
UIShare/Converters/EnumValuesConverter.cs
Normal file
23
UIShare/Converters/EnumValuesConverter.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class EnumValuesConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Type type && type.IsEnum)
|
||||
{
|
||||
return Enum.GetValues(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
UIShare/Converters/FilteredParametersConverter.cs
Normal file
74
UIShare/Converters/FilteredParametersConverter.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
using UIShare.UIViewModel;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class FilteredParametersConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values.Length < 2 || values[0] == null || values[1] == null)
|
||||
return null;
|
||||
|
||||
Type currentParamType = values[0] as Type;
|
||||
var allParameters = values[1] as System.Collections.IEnumerable;
|
||||
|
||||
if (currentParamType == null || allParameters == null)
|
||||
return allParameters;
|
||||
|
||||
// 过滤出类型匹配的参数
|
||||
return allParameters.Cast<ParameterModel>()
|
||||
.Where(p => IsTypeMatch(currentParamType, p.Type))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool IsTypeMatch(Type currentType, Type candidateType)
|
||||
{
|
||||
if (candidateType == null) return false;
|
||||
|
||||
// 如果候选参数类型是 object,则匹配所有类型
|
||||
if (candidateType == typeof(object)) return true;
|
||||
|
||||
// 如果类型完全相同,则匹配
|
||||
if (candidateType == currentType) return true;
|
||||
|
||||
// 处理数值类型的兼容性
|
||||
if (IsNumericType(currentType) && IsNumericType(candidateType))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsNumericType(Type type)
|
||||
{
|
||||
if (type == null) return false;
|
||||
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.Decimal:
|
||||
case TypeCode.Double:
|
||||
case TypeCode.Single:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
UIShare/Converters/HexConverter.cs
Normal file
40
UIShare/Converters/HexConverter.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class HexConverter : IValueConverter
|
||||
{
|
||||
// 显示时:int → hex 字符串
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
return $"0x{i:X}"; // 例如 255 → 0xFF
|
||||
return "0x0";
|
||||
}
|
||||
|
||||
// 用户输入时:hex 字符串 → int
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var str = value?.ToString()?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return 0;
|
||||
|
||||
if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
str = str.Substring(2);
|
||||
|
||||
if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int result))
|
||||
return result;
|
||||
|
||||
return 0; // 或 return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
22
UIShare/Converters/InverseBooleanConverter.cs
Normal file
22
UIShare/Converters/InverseBooleanConverter.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class InverseBooleanConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
// null 视为 false,再取反 → true
|
||||
var b = value as bool?;
|
||||
return !(b ?? false);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var b = value as bool?;
|
||||
return !(b ?? false);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
UIShare/Converters/IsEnumTypeConverter .cs
Normal file
36
UIShare/Converters/IsEnumTypeConverter .cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class IsEnumTypeConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Type type)
|
||||
{
|
||||
// 检查是否为枚举类型
|
||||
bool isEnum = type.IsEnum;
|
||||
|
||||
// 根据参数决定返回值类型
|
||||
if (parameter is string strParam && strParam == "Collapse")
|
||||
{
|
||||
return isEnum ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
return isEnum ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
UIShare/Converters/LessThanConverter.cs
Normal file
27
UIShare/Converters/LessThanConverter.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters // 确保命名空间跟你项目一致
|
||||
{
|
||||
public class LessThanConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is double actualWidth && parameter != null)
|
||||
{
|
||||
if (double.TryParse(parameter.ToString(), out double targetWidth))
|
||||
{
|
||||
// 如果实际宽度 小于 设定的阈值(比如600),返回 True
|
||||
return actualWidth < targetWidth;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
UIShare/Converters/ParameterCategoryToStringConverter.cs
Normal file
41
UIShare/Converters/ParameterCategoryToStringConverter.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using static UIShare.UIViewModel.ParameterModel;
|
||||
|
||||
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class ParameterCategoryToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
|
||||
if (value is ParameterCategory category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case ParameterCategory.Input:
|
||||
return "输入";
|
||||
case ParameterCategory.Output:
|
||||
return "输出";
|
||||
case ParameterCategory.Temp:
|
||||
return "缓存";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
UIShare/Converters/ParameterCategoryToVisibilityConverter.cs
Normal file
41
UIShare/Converters/ParameterCategoryToVisibilityConverter.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using static UIShare.UIViewModel.ParameterModel;
|
||||
|
||||
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class ParameterCategoryToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is ParameterCategory category)
|
||||
{
|
||||
if (parameter?.ToString() == "Item")
|
||||
{
|
||||
if (category == ParameterCategory.Temp) { return Visibility.Collapsed; }
|
||||
else { return Visibility.Visible; }
|
||||
}
|
||||
bool boolValue = category == ParameterCategory.Input;
|
||||
if (parameter?.ToString() == "Inverse")
|
||||
{
|
||||
boolValue = !boolValue;
|
||||
}
|
||||
return boolValue ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
31
UIShare/Converters/ParameterTypeToBoolConverter.cs
Normal file
31
UIShare/Converters/ParameterTypeToBoolConverter.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class ParameterTypeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if(value is Type type)
|
||||
{
|
||||
if(type == typeof(CancellationToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
UIShare/Converters/ParameterValueToStringConverter.cs
Normal file
37
UIShare/Converters/ParameterValueToStringConverter.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class ParameterValueToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is IEnumerable enumerable && !(value is string))
|
||||
{
|
||||
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
|
||||
return $"[{string.Join(", ", elements)}]";
|
||||
}
|
||||
else if(value != null)
|
||||
{
|
||||
return value.ToString()!;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return value.ToString()!;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
35
UIShare/Converters/StringToVisibilityConverter.cs
Normal file
35
UIShare/Converters/StringToVisibilityConverter.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class StringToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if(value is string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
UIShare/Converters/TimeSpanToStringConverter.cs
Normal file
38
UIShare/Converters/TimeSpanToStringConverter.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UIShare.Converters
|
||||
{
|
||||
public class TimeSpanToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is TimeSpan timeSpan)
|
||||
{
|
||||
// 如果天数大于0,则显示天数
|
||||
if (timeSpan.Days > 0)
|
||||
{
|
||||
return $"{timeSpan.Days}天{timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果不超过一天,则只显示时:分:秒
|
||||
return $"{timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
|
||||
}
|
||||
}
|
||||
|
||||
return "00:00:00";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
// 通常不需要从字符串转换回TimeSpan,所以这里返回UnsetValue
|
||||
return System.Windows.DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
85
UIShare/GlobalVariable/ConfigService.cs
Normal file
85
UIShare/GlobalVariable/ConfigService.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Logger;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public static class ConfigService
|
||||
{
|
||||
private static readonly object _fileLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 根据标题(格子标识)加载独立的配置文件
|
||||
/// </summary>
|
||||
public static SystemConfig Load(string title)
|
||||
{
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
throw new ArgumentException("配置标题不能为空", nameof(title));
|
||||
}
|
||||
|
||||
// 临时实例化一个对象以获取默认的 SystemPath
|
||||
var dummy = new SystemConfig();
|
||||
string configPath = Path.Combine(dummy.SystemPath, $"{title}.json");
|
||||
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
// 如果不存在,创建一个带 Title 的默认配置并保存
|
||||
var defaultConfig = new SystemConfig { Title = title };
|
||||
Save(defaultConfig);
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
lock (_fileLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(configPath);
|
||||
var config = JsonConvert.DeserializeObject<SystemConfig>(json, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
return config ?? new SystemConfig { Title = title };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"格子 [{title}] 配置加载失败: {ex.Message}");
|
||||
return new SystemConfig { Title = title };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存指定的配置实例
|
||||
/// </summary>
|
||||
public static void Save(SystemConfig config)
|
||||
{
|
||||
if (config == null || string.IsNullOrEmpty(config.Title)) return;
|
||||
|
||||
lock (_fileLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(config.SystemPath))
|
||||
Directory.CreateDirectory(config.SystemPath);
|
||||
|
||||
string configPath = Path.Combine(config.SystemPath, $"{config.Title}.json");
|
||||
|
||||
string json = JsonConvert.SerializeObject(config, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
File.WriteAllText(configPath, json);
|
||||
LoggerHelper.InfoWithNotify($"配置 [{config.Title}] 已保存。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"配置 [{config.Title}] 保存失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
UIShare/GlobalVariable/GlobalInfo.cs
Normal file
37
UIShare/GlobalVariable/GlobalInfo.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class GlobalInfo:BindableBase
|
||||
{
|
||||
public event EventHandler? ScopeChanged;
|
||||
public Dictionary<string,ScopedContext> ContextDic { get; set; }
|
||||
public Dictionary<string,StepRunning> StepRunningDic { get; set; }
|
||||
public String UserName { get; set; } = "Not Logged in";
|
||||
public bool IsAdmin { get; set; } = true;
|
||||
private string _currentScope = "default";
|
||||
public string CurrentScope
|
||||
{
|
||||
get => _currentScope;
|
||||
set
|
||||
{
|
||||
if (_currentScope != value)
|
||||
{
|
||||
_currentScope = value;
|
||||
ScopeChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
public GlobalInfo()
|
||||
{
|
||||
ContextDic = new();
|
||||
StepRunningDic = new();
|
||||
CurrentScope = "default";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
42
UIShare/GlobalVariable/ScopedContext.cs
Normal file
42
UIShare/GlobalVariable/ScopedContext.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.UIViewModel;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class ScopedContext
|
||||
{
|
||||
private static readonly Random _randomSeed = new Random();
|
||||
public ProgramModel Program { get; set; } = new();
|
||||
public String SelectedStepList { get; set; } = "主程序";
|
||||
public string CurrentFilePath { get; set; }
|
||||
public bool? IsStop { get; set; }
|
||||
public bool SingleStep { get; set; }
|
||||
public string RunState { get; set; } = "运行";
|
||||
public TimeSpan RunningTime { get; set; } = TimeSpan.Zero;
|
||||
public Stopwatch SW { get; set; } = new();
|
||||
public bool IsTerminate { get; set; } = false;
|
||||
public ObservableCollection<Assembly> Assemblies { get; set; } = new();
|
||||
public PackIconKind RunIcon { get; set; } = PackIconKind.Play;
|
||||
public StepModel SelectedStep { get; set; }
|
||||
public ParameterModel SelectedParameter { get; set; }
|
||||
// 【新增测试属性】:每个实例被 new 出来时独一无二的随机身份
|
||||
// 证 ID
|
||||
public int DebugRandomId { get; private set; }
|
||||
public ScopedContext()
|
||||
{
|
||||
lock (_randomSeed)
|
||||
{
|
||||
// 每次诞生一个新上下文,就在 10000 到 99999 之间随机摇一个数
|
||||
DebugRandomId = _randomSeed.Next(10000, 100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
730
UIShare/GlobalVariable/StepRunning.cs
Normal file
730
UIShare/GlobalVariable/StepRunning.cs
Normal file
@@ -0,0 +1,730 @@
|
||||
using UIShare.UIViewModel;
|
||||
using UIShare.PubEvent;
|
||||
using Common.Tools;
|
||||
using Logger;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.GlobalVariable;
|
||||
using static UIShare.UIViewModel.ParameterModel;
|
||||
|
||||
|
||||
namespace UIShare
|
||||
{
|
||||
public class StepRunning
|
||||
{
|
||||
private ScopedContext _scopedContext;
|
||||
private SystemConfig _systemConfig;
|
||||
//private Devices _devices;
|
||||
private IContainerProvider containerProvider;
|
||||
private IEventAggregator _eventAggregator;
|
||||
|
||||
private readonly Dictionary<Guid, ParameterModel> tmpParameters = [];
|
||||
|
||||
private readonly Stopwatch stepStopwatch = new();
|
||||
|
||||
private readonly Stack<Stopwatch> loopStopwatchStack = new();
|
||||
|
||||
private readonly Stack<LoopContext> loopStack = new();
|
||||
|
||||
public CancellationTokenSource stepCTS = new();
|
||||
public CancellationTokenSource errorStepCTS = new();
|
||||
private bool SubSingleStep = false;
|
||||
|
||||
private Guid TestRoundID;
|
||||
public StepRunning(ScopedContext ScopedContext, SystemConfig systemConfig,IEventAggregator eventAggregator,IContainerProvider containerProvider)
|
||||
{
|
||||
_scopedContext = ScopedContext;
|
||||
_systemConfig = systemConfig;
|
||||
_eventAggregator = eventAggregator;
|
||||
//_devices = containerProvider.Resolve<Devices>();
|
||||
}
|
||||
public async Task<bool> ExecuteErrorSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int index = 0;
|
||||
bool stepSuccess = false;
|
||||
if (depth == 0)
|
||||
{
|
||||
loopStack.Clear();
|
||||
loopStopwatchStack.Clear();
|
||||
ResetAllStepStatus(program.ErrorStepCollection);
|
||||
tmpParameters.Clear();
|
||||
TestRoundID = Guid.NewGuid();
|
||||
}
|
||||
foreach (var item in program.Parameters)
|
||||
{
|
||||
tmpParameters.TryAdd(item.ID, item);
|
||||
}
|
||||
|
||||
while (index < program.ErrorStepCollection.Count)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var step = program.ErrorStepCollection[index];
|
||||
if (!step.IsUsed)
|
||||
{
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
step.Result = 0;
|
||||
if (step.StepType == "循环开始")
|
||||
{
|
||||
var endStep = program.ErrorStepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
|
||||
if (endStep != null)
|
||||
{
|
||||
endStep.Result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理循环开始
|
||||
if (step.StepType == "循环开始")
|
||||
{
|
||||
Stopwatch loopStopwatch = new();
|
||||
loopStopwatch.Start();
|
||||
loopStopwatchStack.Push(loopStopwatch);
|
||||
var context = new LoopContext
|
||||
{
|
||||
LoopCount = step.LoopCount ?? 1,
|
||||
CurrentLoop = 0,
|
||||
StartIndex = index,
|
||||
LoopStartStep = step
|
||||
};
|
||||
loopStack.Push(context);
|
||||
step.CurrentLoopCount = context.LoopCount;
|
||||
LoggerHelper.InfoWithNotify($"循环开始,共{context.LoopCount}次", depth);
|
||||
index++;
|
||||
}
|
||||
|
||||
// 处理循环结束
|
||||
else if (step.StepType == "循环结束")
|
||||
{
|
||||
if (loopStack.Count == 0)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth: depth);
|
||||
step.Result = 2;
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var context = loopStack.Peek();
|
||||
context.CurrentLoop++;
|
||||
|
||||
// 更新循环开始步骤的显示
|
||||
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
|
||||
|
||||
if (context.CurrentLoop < context.LoopCount)
|
||||
{
|
||||
// 继续循环:跳转到循环开始后的第一条指令
|
||||
index = context.StartIndex + 1;
|
||||
LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 循环结束
|
||||
loopStack.Pop();
|
||||
var loopStopwatch = loopStopwatchStack.Peek();
|
||||
index++;
|
||||
LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth);
|
||||
if (depth == 0 && loopStopwatch.IsRunning)
|
||||
{
|
||||
loopStopwatch.Stop();
|
||||
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
|
||||
step.Result = 1;
|
||||
program.ErrorStepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
|
||||
loopStopwatchStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理普通步骤
|
||||
else
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
stepStopwatch.Restart();
|
||||
}
|
||||
|
||||
if (step.SubProgram != null)
|
||||
{
|
||||
if (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||||
{
|
||||
SubSingleStep = true;
|
||||
_scopedContext.SingleStep = false;
|
||||
}
|
||||
LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
|
||||
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
|
||||
UpdateCurrentStepResult(step, true, stepSuccess, depth);
|
||||
if (SubSingleStep)
|
||||
{
|
||||
SubSingleStep = false;
|
||||
_scopedContext.SingleStep = true;
|
||||
}
|
||||
}
|
||||
else if (step.Method != null)
|
||||
{
|
||||
LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
|
||||
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
|
||||
stepSuccess = step.Result == 1;
|
||||
if (step.NGGotoStepID != null && !stepSuccess)
|
||||
{
|
||||
var tmp = program.ErrorStepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
|
||||
if (tmp != null)
|
||||
{
|
||||
index = tmp.Index - 2;
|
||||
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||
}
|
||||
}
|
||||
if (step.OKGotoStepID != null && stepSuccess)
|
||||
{
|
||||
var tmp = program.ErrorStepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
|
||||
if (tmp != null)
|
||||
{
|
||||
index = tmp.Index - 2;
|
||||
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
|
||||
if (depth == 0 && stepStopwatch.IsRunning)
|
||||
{
|
||||
stepStopwatch.Stop();
|
||||
step.RunTime = (int)stepStopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loopStack.Count == 0 && stepSuccess;
|
||||
}
|
||||
public async Task<bool> ExecuteSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int index = 0;
|
||||
bool stepSuccess = false;
|
||||
if (depth == 0)
|
||||
{
|
||||
loopStack.Clear();
|
||||
loopStopwatchStack.Clear();
|
||||
ResetAllStepStatus(program.StepCollection);
|
||||
tmpParameters.Clear();
|
||||
TestRoundID = Guid.NewGuid();
|
||||
}
|
||||
foreach (var item in program.Parameters)
|
||||
{
|
||||
tmpParameters.TryAdd(item.ID, item);
|
||||
}
|
||||
|
||||
while (index < program.StepCollection.Count)
|
||||
{
|
||||
while (_scopedContext.IsStop == true)
|
||||
{
|
||||
await Task.Delay(50);
|
||||
}
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var step = program.StepCollection[index];
|
||||
if (!step.IsUsed)
|
||||
{
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
step.Result = 0;
|
||||
if (step.StepType == "循环开始")
|
||||
{
|
||||
var endStep = program.StepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
|
||||
if (endStep != null)
|
||||
{
|
||||
endStep.Result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理循环开始
|
||||
if (step.StepType == "循环开始")
|
||||
{
|
||||
Stopwatch loopStopwatch = new();
|
||||
loopStopwatch.Start();
|
||||
loopStopwatchStack.Push(loopStopwatch);
|
||||
var context = new LoopContext
|
||||
{
|
||||
LoopCount = step.LoopCount ?? 1,
|
||||
CurrentLoop = 0,
|
||||
StartIndex = index,
|
||||
LoopStartStep = step
|
||||
};
|
||||
loopStack.Push(context);
|
||||
step.CurrentLoopCount = context.LoopCount;
|
||||
LoggerHelper.InfoWithNotify($"循环开始({step.Name}),共{context.LoopCount}次", depth);
|
||||
index++;
|
||||
}
|
||||
|
||||
// 处理循环结束
|
||||
else if (step.StepType == "循环结束")
|
||||
{
|
||||
if (loopStack.Count == 0)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth:depth);
|
||||
step.Result = 2;
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var context = loopStack.Peek();
|
||||
context.CurrentLoop++;
|
||||
|
||||
// 更新循环开始步骤的显示
|
||||
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
|
||||
|
||||
if (context.CurrentLoop < context.LoopCount)
|
||||
{
|
||||
// 继续循环:跳转到循环开始后的第一条指令
|
||||
index = context.StartIndex + 1;
|
||||
LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 循环结束
|
||||
loopStack.Pop();
|
||||
var loopStopwatch = loopStopwatchStack.Peek();
|
||||
index++;
|
||||
LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth);
|
||||
if (depth == 0 && loopStopwatch.IsRunning)
|
||||
{
|
||||
loopStopwatch.Stop();
|
||||
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
|
||||
step.Result = 1;
|
||||
program.StepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
|
||||
loopStopwatchStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理普通步骤
|
||||
else
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
stepStopwatch.Restart();
|
||||
}
|
||||
|
||||
if (step.SubProgram != null)
|
||||
{
|
||||
if (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||||
{
|
||||
SubSingleStep = true;
|
||||
_scopedContext.SingleStep = false;
|
||||
}
|
||||
LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
|
||||
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
|
||||
UpdateCurrentStepResult(step, true, stepSuccess, depth);
|
||||
if (SubSingleStep)
|
||||
{
|
||||
SubSingleStep = false;
|
||||
_scopedContext.SingleStep = true;
|
||||
}
|
||||
}
|
||||
else if (step.Method != null)
|
||||
{
|
||||
LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
|
||||
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
|
||||
stepSuccess = step.Result == 1;
|
||||
if (step.NGGotoStepID != null && !stepSuccess)
|
||||
{
|
||||
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
|
||||
if (tmp != null)
|
||||
{
|
||||
index = tmp.Index - 2;
|
||||
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||
}
|
||||
}
|
||||
if (step.OKGotoStepID != null && stepSuccess)
|
||||
{
|
||||
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
|
||||
if (tmp != null)
|
||||
{
|
||||
index = tmp.Index - 2;
|
||||
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
|
||||
if (depth == 0 && stepStopwatch.IsRunning)
|
||||
{
|
||||
stepStopwatch.Stop();
|
||||
step.RunTime = (int)stepStopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
if (_scopedContext.SingleStep)
|
||||
{
|
||||
_scopedContext.IsStop = true;
|
||||
_scopedContext.RunState = "运行";
|
||||
_scopedContext.SingleStep = false;
|
||||
_eventAggregator.GetEvent<RunSingalCompletedEvent>().Publish("Play");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loopStack.Count == 0 && stepSuccess;
|
||||
}
|
||||
|
||||
public async Task ExecuteMethodStep(StepModel step, Dictionary<Guid, ParameterModel> parameters, int depth, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(_scopedContext.Program.StepCollection.Count>1)
|
||||
_scopedContext.SelectedStep = null;
|
||||
await Task.Delay(_systemConfig.PerformanceLevel);
|
||||
|
||||
|
||||
// 1. 查找类型
|
||||
Type? targetType = null;
|
||||
foreach (var assembly in _scopedContext.Assemblies)
|
||||
{
|
||||
targetType = assembly.GetType(step.Method!.FullName!);
|
||||
if (targetType != null) break;
|
||||
}
|
||||
if (targetType == null)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth);
|
||||
step.Result = 2;
|
||||
}
|
||||
|
||||
// 2. 创建实例(仅当方法不是静态时才需要)
|
||||
object? instance = null;
|
||||
bool isMethod = false;
|
||||
|
||||
// 3. 准备参数
|
||||
var inputParams = new List<object?>();
|
||||
var paramTypes = new List<Type>();
|
||||
ParameterModel? outputParam = null;
|
||||
foreach (var param in step.Method!.Parameters)
|
||||
{
|
||||
if (param.Category == ParameterCategory.Input)
|
||||
{
|
||||
if (param.Type == typeof(CancellationToken))
|
||||
{
|
||||
inputParams.Add(stepCTS.Token);
|
||||
paramTypes.Add(param.Type!);
|
||||
continue;
|
||||
}
|
||||
var actualValue = param.GetActualValue(tmpParameters);
|
||||
// 类型转换处理
|
||||
if (actualValue != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(actualValue.ToString()))
|
||||
{
|
||||
actualValue = null;
|
||||
}
|
||||
if (actualValue != null && param.Type != null && actualValue.GetType() != param.Type)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (param.Type.IsArray)
|
||||
{
|
||||
// 获取数组元素类型
|
||||
Type elementType = param.Type.GetElementType()!;
|
||||
|
||||
// 解析字符串为字符串数组
|
||||
string[] stringArray = actualValue.ToString()!
|
||||
.Trim('[', ']')
|
||||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.Trim())
|
||||
.ToArray();
|
||||
|
||||
// 创建目标类型数组
|
||||
Array array = Array.CreateInstance(elementType, stringArray.Length);
|
||||
|
||||
// 转换每个元素
|
||||
for (int i = 0; i < stringArray.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 特殊处理字符串类型
|
||||
if (elementType == typeof(string))
|
||||
{
|
||||
array.SetValue(stringArray[i], i);
|
||||
}
|
||||
// 特殊处理枚举类型
|
||||
else if (elementType.IsEnum)
|
||||
{
|
||||
array.SetValue(Enum.Parse(elementType, stringArray[i]), i);
|
||||
}
|
||||
// 常规类型转换
|
||||
else
|
||||
{
|
||||
if (stringArray[i] is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 先转成整数
|
||||
var intValue = Convert.ToInt64(s, 16);
|
||||
|
||||
// 再转成目标类型
|
||||
array.SetValue(Convert.ChangeType(intValue, elementType), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
array.SetValue(Convert.ChangeType(stringArray[i], elementType), i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new InvalidCastException($"指令 [ {step.Index} ] 执行错误:元素 '{stringArray[i]}' 无法转换为 {elementType.Name}[]");
|
||||
}
|
||||
}
|
||||
actualValue = array;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param.Type.BaseType == typeof(Enum))
|
||||
{
|
||||
actualValue = Enum.Parse(param.Type, param.Value!.ToString()!);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actualValue is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 先转成整数
|
||||
var intValue = Convert.ToInt64(s, 16);
|
||||
|
||||
// 再转成目标类型
|
||||
actualValue = Convert.ChangeType(intValue, param.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
actualValue = Convert.ChangeType(actualValue, param.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputParams.Add(actualValue);
|
||||
paramTypes.Add(param.Type!);
|
||||
}
|
||||
else if (param.Category == ParameterCategory.Output)
|
||||
{
|
||||
outputParam = param;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 获取方法
|
||||
var method = targetType!.GetMethod(
|
||||
step.Method.Name!,
|
||||
BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
|
||||
null,
|
||||
paramTypes.ToArray(),
|
||||
null
|
||||
);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth);
|
||||
step.Result = 2;
|
||||
}
|
||||
|
||||
// 检查是否是静态方法
|
||||
bool isStaticMethod = method!.IsStatic;
|
||||
|
||||
// 如果是实例方法,需要创建实例
|
||||
if (!isStaticMethod)
|
||||
{
|
||||
try
|
||||
{
|
||||
//instance = _devices.DeviceDic[targetType.Name];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth);
|
||||
step.Result = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 执行方法
|
||||
|
||||
object? returnValue = method.Invoke(instance, inputParams.ToArray());
|
||||
try
|
||||
{
|
||||
// 处理异步方法
|
||||
if (returnValue is Task task)
|
||||
{
|
||||
await task.ConfigureAwait(false);
|
||||
// 获取结果(如果是Task<T>)
|
||||
if (task.GetType().IsGenericType)
|
||||
{
|
||||
var returnValueProperty = task.GetType().GetProperty("Result");
|
||||
returnValue = returnValueProperty?.GetValue(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理VoidTaskreturnValue类型
|
||||
if (returnValue != null && returnValue.GetType().FullName == "System.Threading.Tasks.VoidTaskreturnValue")
|
||||
{
|
||||
returnValue = null;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
|
||||
step.Result = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 处理输出
|
||||
bool paraResult = true; //记录参数上下限是否NG
|
||||
if (outputParam != null)
|
||||
{
|
||||
outputParam.Value = returnValue;
|
||||
var currentPara = outputParam.GetCurrentParameter(tmpParameters);
|
||||
if (currentPara != null)
|
||||
{
|
||||
currentPara.Value = returnValue;
|
||||
var tmp = currentPara.GetResult();
|
||||
currentPara.Result = tmp.Item1;
|
||||
paraResult = tmp.Item1;
|
||||
if (tmp.Item2 != null)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify(tmp.Item2);
|
||||
}
|
||||
//if (currentPara.IsSave && _scopedContext.Program.Parameters.FirstOrDefault(x => x.ID == currentPara.ID) != null)
|
||||
//{
|
||||
// _ = SaveDataToDatabase(_scopedContext.Program.ID, currentPara);
|
||||
//}
|
||||
}
|
||||
var returnType = returnValue?.GetType();
|
||||
if (returnType != null)
|
||||
{
|
||||
if (!returnType.IsArray)
|
||||
{
|
||||
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (returnValue is IEnumerable enumerable)
|
||||
{
|
||||
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
|
||||
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LoggerHelper.SuccessWithNotify($"指令 [ {step.Index} ] 执行成功", depth);
|
||||
UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
|
||||
step.Result = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetAllStepStatus(ObservableCollection<StepModel> StepCollection)
|
||||
{
|
||||
foreach (var step in StepCollection)
|
||||
{
|
||||
step.Result = -1;
|
||||
step.RunTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCurrentStepResult(StepModel step, bool paraResult = true, bool stepResult = true, int depth = 0)
|
||||
{
|
||||
if (stepResult && paraResult)
|
||||
{
|
||||
if (string.IsNullOrEmpty(step.OKExpression))
|
||||
{
|
||||
step.Result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary<string, object> paraDic = [];
|
||||
foreach (var item in tmpParameters)
|
||||
{
|
||||
paraDic.TryAdd(item.Value.Name, item.Value.Value!);
|
||||
}
|
||||
if (step.SubProgram != null)
|
||||
{
|
||||
foreach (var item in step.SubProgram.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||||
{
|
||||
paraDic.TryAdd(item.Name, item.Value!);
|
||||
}
|
||||
}
|
||||
else if (step.Method != null)
|
||||
{
|
||||
foreach (var item in step.Method.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||||
{
|
||||
paraDic.TryAdd(item.Name, item.Value!);
|
||||
}
|
||||
}
|
||||
bool re = ExpressionEvaluator.EvaluateExpression(step.OKExpression, paraDic);
|
||||
step.Result = re ? 1 : 2;
|
||||
if (step.Result == 2)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!paraResult)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify("参数限值校验失败", depth: depth);
|
||||
}
|
||||
step.Result = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region 私有类
|
||||
|
||||
private class LoopContext
|
||||
{
|
||||
public int LoopCount { get; set; }
|
||||
public int CurrentLoop { get; set; }
|
||||
public int StartIndex { get; set; }
|
||||
public StepModel? LoopStartStep { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
41
UIShare/GlobalVariable/SystemConfig.cs
Normal file
41
UIShare/GlobalVariable/SystemConfig.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Logger;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.UIViewModel;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
[JsonIgnore]
|
||||
public string SystemPath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "UIShare");
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public int PerformanceLevel { get; set; } = 50;
|
||||
public string DLLFilePath { get; set; } = @"D:\ADP\指令\";
|
||||
public string SubProgramFilePath { get; set; } = @"D:\ADP\子程序\";
|
||||
public string DefaultProgramFilePath { get; set; } = "";
|
||||
public string DefaultBLFFilePath { get; set; } = "";
|
||||
public string DefaultDBCFilePath { get; set; } = "";
|
||||
public string TSMasterName { get; set; } = "ADP测试上位机";
|
||||
|
||||
/// <summary>
|
||||
/// 设备列表:每个工位独立一份(SystemConfig 已注册为 Scoped)。
|
||||
/// 当前阶段预置几条模拟设备,便于设置界面直接展示左侧列表。
|
||||
/// </summary>
|
||||
public ObservableCollection<DeviceInfoModel> DeviceList { get; set; } = new()
|
||||
{
|
||||
new DeviceInfoModel { DeviceName = "DAQ_001", DeviceType = "数据采集卡", Remark = "8 通道电压采集", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "PSU_002", DeviceType = "可编程电源", Remark = "0-30V / 0-5A", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "CAN_003", DeviceType = "CAN 通讯卡", Remark = "双通道 CAN-FD", IsEnabled = false, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "IO_004", DeviceType = "数字 I/O", Remark = "16 进 16 出", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "Serial_005", DeviceType = "串口", Remark = "RS232 / RS485", IsEnabled = true, IsConnected = false },
|
||||
};
|
||||
}
|
||||
}
|
||||
52
UIShare/Helpers/PasswordBoxHelper.cs
Normal file
52
UIShare/Helpers/PasswordBoxHelper.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace UIShare.Helpers
|
||||
{
|
||||
public static class PasswordBoxHelper
|
||||
{
|
||||
public static readonly DependencyProperty PasswordProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"Password",
|
||||
typeof(string),
|
||||
typeof(PasswordBoxHelper),
|
||||
new FrameworkPropertyMetadata(
|
||||
string.Empty,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnPasswordPropertyChanged));
|
||||
|
||||
public static void SetPassword(DependencyObject d, string value)
|
||||
=> d.SetValue(PasswordProperty, value);
|
||||
|
||||
public static string GetPassword(DependencyObject d)
|
||||
=> (string)d.GetValue(PasswordProperty);
|
||||
|
||||
private static void OnPasswordPropertyChanged(
|
||||
DependencyObject d,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is PasswordBox pb)
|
||||
{
|
||||
pb.PasswordChanged -= PasswordChanged;
|
||||
if (pb.Password != (string)e.NewValue)
|
||||
{
|
||||
pb.Password = (string)e.NewValue;
|
||||
}
|
||||
pb.PasswordChanged += PasswordChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is PasswordBox pb)
|
||||
{
|
||||
SetPassword(pb, pb.Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
UIShare/Helpers/WindowDragHelper.cs
Normal file
41
UIShare/Helpers/WindowDragHelper.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace UIShare.Helpers
|
||||
{
|
||||
public static class WindowDragHelper
|
||||
{
|
||||
public static readonly DependencyProperty EnableWindowDragProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"EnableWindowDrag",
|
||||
typeof(bool),
|
||||
typeof(WindowDragHelper),
|
||||
new PropertyMetadata(false, OnEnableWindowDragChanged));
|
||||
|
||||
public static bool GetEnableWindowDrag(DependencyObject obj) =>
|
||||
(bool)obj.GetValue(EnableWindowDragProperty);
|
||||
|
||||
public static void SetEnableWindowDrag(DependencyObject obj, bool value) =>
|
||||
obj.SetValue(EnableWindowDragProperty, value);
|
||||
|
||||
private static void OnEnableWindowDragChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is FrameworkElement element)
|
||||
{
|
||||
if ((bool)e.NewValue)
|
||||
element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
||||
else
|
||||
element.MouseLeftButtonDown -= Element_MouseLeftButtonDown;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
var window = Window.GetWindow(element);
|
||||
window?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/AlarmEvent.cs
Normal file
12
UIShare/PubEvent/AlarmEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class AlarmEvent :PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/ChangeCurrentTagEvent.cs
Normal file
12
UIShare/PubEvent/ChangeCurrentTagEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class ChangeCurrentTagEvent:PubSubEvent<string>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/CollectedCANMessageChangedEvent.cs
Normal file
12
UIShare/PubEvent/CollectedCANMessageChangedEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class CollectedCANMessageChangedEvent:PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/ConnectionChangeEvent.cs
Normal file
12
UIShare/PubEvent/ConnectionChangeEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class ConnectionChangeEvent:PubSubEvent<(string,bool)>
|
||||
{
|
||||
}
|
||||
}
|
||||
13
UIShare/PubEvent/CurveDataEvent.cs
Normal file
13
UIShare/PubEvent/CurveDataEvent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class CurveDataEvent:PubSubEvent<(string, Dictionary<string,double>)>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/CurveInteractionEvent.cs
Normal file
12
UIShare/PubEvent/CurveInteractionEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class CurveInteractionEvent:PubSubEvent<(bool,double)>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/DeletedStepEvent.cs
Normal file
12
UIShare/PubEvent/DeletedStepEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class DeletedStepEvent : PubSubEvent<Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/EditSetpEvent.cs
Normal file
12
UIShare/PubEvent/EditSetpEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class EditSetpEvent : PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/ExpandViewEvent.cs
Normal file
12
UIShare/PubEvent/ExpandViewEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class ExpandViewEvent:PubSubEvent<string>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/LoginSuccessEvent.cs
Normal file
12
UIShare/PubEvent/LoginSuccessEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class LoginSuccessEvent:PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/OverlayEvent.cs
Normal file
12
UIShare/PubEvent/OverlayEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class OverlayEvent : PubSubEvent<bool>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/ParamsChangedEvent.cs
Normal file
12
UIShare/PubEvent/ParamsChangedEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class ParamsChangedEvent:PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/RunSingalCompletedEvent.cs
Normal file
12
UIShare/PubEvent/RunSingalCompletedEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class RunSingalCompletedEvent : PubSubEvent<string>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/SettingChangedEvent.cs
Normal file
12
UIShare/PubEvent/SettingChangedEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class SettingChangedEvent:PubSubEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/StartProcessEvent.cs
Normal file
12
UIShare/PubEvent/StartProcessEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class StartProcessEvent:PubSubEvent<(string,bool)>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
UIShare/PubEvent/WaitingEvent.cs
Normal file
12
UIShare/PubEvent/WaitingEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.PubEvent
|
||||
{
|
||||
public class WaitingEvent : PubSubEvent<bool>
|
||||
{
|
||||
}
|
||||
}
|
||||
21
UIShare/Styles/CommonStyle.xaml
Normal file
21
UIShare/Styles/CommonStyle.xaml
Normal file
@@ -0,0 +1,21 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- 引用MaterialDesign和MahApps的资源 -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Fonts.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Flyout.xaml" />
|
||||
|
||||
<!-- MahApps资源 -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
|
||||
|
||||
<!-- Material Design资源 -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Secondary/MaterialDesignColor.Lime.xaml" />
|
||||
<!--自定义style-->
|
||||
<ResourceDictionary Source="/UIShare;component/Styles/WindowStyle.xaml"></ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
22
UIShare/Styles/WindowStyle.xaml
Normal file
22
UIShare/Styles/WindowStyle.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style x:Key="DialogUserManageStyle"
|
||||
TargetType="Window">
|
||||
<Setter Property="WindowStyle"
|
||||
Value="None" />
|
||||
<Setter Property="Topmost"
|
||||
Value="True" />
|
||||
<Setter Property="ResizeMode"
|
||||
Value="NoResize" />
|
||||
<Setter Property="ShowInTaskbar"
|
||||
Value="False" />
|
||||
<Setter Property="AllowsTransparency"
|
||||
Value="true" />
|
||||
<Setter Property="Background"
|
||||
Value="Transparent" />
|
||||
<Setter Property="SizeToContent"
|
||||
Value="WidthAndHeight" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
23
UIShare/UIShare.csproj
Normal file
23
UIShare/UIShare.csproj
Normal file
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MahApps.Metro" Version="3.0.0-rc0529" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.142" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.5-beta1" />
|
||||
<PackageReference Include="Prism.Unity" Version="9.0.537" />
|
||||
<PackageReference Include="MaterialDesignColors" Version="5.3.0" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="5.3.0" />
|
||||
<PackageReference Include="MaterialDesignThemes.MahApps" Version="5.3.0" />
|
||||
<PackageReference Include="Notifications.Wpf.Core" Version="2.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\Logger\Logger.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
71
UIShare/UIViewModel/CanMessageShowModel.cs
Normal file
71
UIShare/UIViewModel/CanMessageShowModel.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class CanMessageShowModel : BindableBase
|
||||
{
|
||||
// 字段声明
|
||||
private byte _通道;
|
||||
private int _报文ID;
|
||||
private ulong _时间戳;
|
||||
private byte _长度;
|
||||
private bool _fd;
|
||||
private bool _isTx;
|
||||
private byte[] _bytes = new byte[64];
|
||||
private string _报文;
|
||||
|
||||
// 通道属性
|
||||
public byte 通道
|
||||
{
|
||||
get { return _通道; }
|
||||
set { SetProperty(ref _通道, value); }
|
||||
}
|
||||
|
||||
// 报文ID属性
|
||||
public int 报文ID
|
||||
{
|
||||
get { return _报文ID; }
|
||||
set { SetProperty(ref _报文ID, value); }
|
||||
}
|
||||
|
||||
// 时间戳属性
|
||||
public ulong 时间戳
|
||||
{
|
||||
get { return _时间戳; }
|
||||
set { SetProperty(ref _时间戳, value); }
|
||||
}
|
||||
|
||||
// 长度属性
|
||||
public byte 长度
|
||||
{
|
||||
get { return _长度; }
|
||||
set { SetProperty(ref _长度, value); }
|
||||
}
|
||||
|
||||
// FD属性
|
||||
public bool FD
|
||||
{
|
||||
get { return _fd; }
|
||||
set { SetProperty(ref _fd, value); }
|
||||
}
|
||||
|
||||
// IsTx属性
|
||||
public bool IsTx
|
||||
{
|
||||
get { return _isTx; }
|
||||
set { SetProperty(ref _isTx, value); }
|
||||
}
|
||||
|
||||
// Bytes属性
|
||||
public byte[] Bytes
|
||||
{
|
||||
get { return _bytes; }
|
||||
set { SetProperty(ref _bytes, value); }
|
||||
}
|
||||
|
||||
// 报文属性
|
||||
public string 报文
|
||||
{
|
||||
get { return _报文; }
|
||||
set { SetProperty(ref _报文, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
22
UIShare/UIViewModel/CustomPanelItem.cs
Normal file
22
UIShare/UIViewModel/CustomPanelItem.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Prism.Mvvm;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class CustomPanelItem : BindableBase
|
||||
{
|
||||
private string _name;
|
||||
private string _pointY;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetProperty(ref _name, value);
|
||||
}
|
||||
|
||||
public string PointY
|
||||
{
|
||||
get => _pointY;
|
||||
set => SetProperty(ref _pointY, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
UIShare/UIViewModel/DeviceInfoModel.cs
Normal file
44
UIShare/UIViewModel/DeviceInfoModel.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class DeviceInfoModel : BindableBase
|
||||
{
|
||||
private string _deviceName;
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private string _deviceType;
|
||||
public string DeviceType
|
||||
{
|
||||
get => _deviceType;
|
||||
set => SetProperty(ref _deviceType, value);
|
||||
}
|
||||
|
||||
private string _remark;
|
||||
public string Remark
|
||||
{
|
||||
get => _remark;
|
||||
set => SetProperty(ref _remark, value);
|
||||
}
|
||||
|
||||
private bool _isEnabled;
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set => SetProperty(ref _isEnabled, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
18
UIShare/UIViewModel/InstructionNode.cs
Normal file
18
UIShare/UIViewModel/InstructionNode.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class InstructionNode
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ObservableCollection<InstructionNode> Children { get; set; } = new();
|
||||
public object Tag { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
40
UIShare/UIViewModel/MethodModel.cs
Normal file
40
UIShare/UIViewModel/MethodModel.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class MethodModel
|
||||
{
|
||||
|
||||
#region 构造函数
|
||||
|
||||
public MethodModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MethodModel(MethodModel source)
|
||||
{
|
||||
if (source == null) return;
|
||||
|
||||
Name = source.Name;
|
||||
FullName = source.FullName;
|
||||
|
||||
// 深拷贝参数
|
||||
Parameters = new ObservableCollection<ParameterModel>(
|
||||
source.Parameters.Select(p => new ParameterModel(p)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? FullName { get; set; }
|
||||
|
||||
public ObservableCollection<ParameterModel> Parameters { get; set; } = [];
|
||||
}
|
||||
}
|
||||
316
UIShare/UIViewModel/ParameterModel.cs
Normal file
316
UIShare/UIViewModel/ParameterModel.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
using Newtonsoft.Json;
|
||||
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class ParameterModel : BindableBase
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
public ParameterModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ParameterModel(ParameterModel source)
|
||||
{
|
||||
if (source == null) return;
|
||||
|
||||
ID = source.ID;
|
||||
Name = source.Name;
|
||||
Type = source.Type;
|
||||
Category = source.Category;
|
||||
IsUseVar = source.IsUseVar;
|
||||
IsSave = source.IsSave;
|
||||
VariableName = source.VariableName;
|
||||
VariableID = source.VariableID;
|
||||
IsGlobal = source.IsGlobal;
|
||||
Value = source.Value;
|
||||
LowerLimit = source.LowerLimit;
|
||||
UpperLimit = source.UpperLimit;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Guid _id = Guid.NewGuid();
|
||||
public Guid ID
|
||||
{
|
||||
get => _id;
|
||||
set => SetProperty(ref _id, value);
|
||||
}
|
||||
|
||||
private bool _isVisible = true;
|
||||
public bool IsVisible
|
||||
{
|
||||
get => _isVisible;
|
||||
set => SetProperty(ref _isVisible, value);
|
||||
}
|
||||
|
||||
private string _name;
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetProperty(ref _name, value);
|
||||
}
|
||||
|
||||
private Type _type = typeof(string);
|
||||
public Type Type
|
||||
{
|
||||
get => _type;
|
||||
set => SetProperty(ref _type, value);
|
||||
}
|
||||
|
||||
private ParameterCategory _category = ParameterCategory.Temp;
|
||||
public ParameterCategory Category
|
||||
{
|
||||
get => _category;
|
||||
set => SetProperty(ref _category, value);
|
||||
}
|
||||
|
||||
private bool _isGlobal;
|
||||
public bool IsGlobal
|
||||
{
|
||||
get => _isGlobal;
|
||||
set => SetProperty(ref _isGlobal, value);
|
||||
}
|
||||
|
||||
private object? _value;
|
||||
public object? Value
|
||||
{
|
||||
get => _value;
|
||||
set => SetProperty(ref _value, value);
|
||||
}
|
||||
|
||||
private object? _lowerLimit;
|
||||
public object? LowerLimit
|
||||
{
|
||||
get => _lowerLimit;
|
||||
set => SetProperty(ref _lowerLimit, value);
|
||||
}
|
||||
|
||||
private object? _upperLimit;
|
||||
public object? UpperLimit
|
||||
{
|
||||
get => _upperLimit;
|
||||
set => SetProperty(ref _upperLimit, value);
|
||||
}
|
||||
|
||||
private bool _result = true;
|
||||
public bool Result
|
||||
{
|
||||
get => _result;
|
||||
set => SetProperty(ref _result, value);
|
||||
}
|
||||
|
||||
private bool _isUseVar;
|
||||
public bool IsUseVar
|
||||
{
|
||||
get => _isUseVar;
|
||||
set => SetProperty(ref _isUseVar, value);
|
||||
}
|
||||
|
||||
private bool _isSave;
|
||||
public bool IsSave
|
||||
{
|
||||
get => _isSave;
|
||||
set => SetProperty(ref _isSave, value);
|
||||
}
|
||||
|
||||
private string? _variableName;
|
||||
public string? VariableName
|
||||
{
|
||||
get => _variableName;
|
||||
set => SetProperty(ref _variableName, value);
|
||||
}
|
||||
|
||||
private Guid? _variableID;
|
||||
public Guid? VariableID
|
||||
{
|
||||
get => _variableID;
|
||||
set => SetProperty(ref _variableID, value);
|
||||
}
|
||||
|
||||
public enum ParameterCategory
|
||||
{
|
||||
Input,
|
||||
Output,
|
||||
Temp
|
||||
}
|
||||
|
||||
public object? GetActualValue(Dictionary<Guid, ParameterModel> paraList)
|
||||
{
|
||||
HashSet<Guid> visitedIds = new HashSet<Guid>();
|
||||
ParameterModel current = this;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
if (!current.IsUseVar)
|
||||
{
|
||||
return current.Value;
|
||||
}
|
||||
|
||||
if (visitedIds.Contains(current.ID))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
visitedIds.Add(current.ID);
|
||||
|
||||
if (current.VariableID == null)
|
||||
{
|
||||
if (Type != null && Value != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ChangeType(Value, Type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParameterModel? next = paraList[(Guid)current.VariableID!];
|
||||
if (next == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ParameterModel? GetCurrentParameter(Dictionary<Guid, ParameterModel> paraList)
|
||||
{
|
||||
HashSet<Guid> visitedIds = new HashSet<Guid>();
|
||||
ParameterModel current = this;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
if (current.VariableID == null)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
if (visitedIds.Contains(current.ID))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
visitedIds.Add(current.ID);
|
||||
|
||||
if (current.VariableID == null)
|
||||
{
|
||||
if (Type != null && Value != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return current;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParameterModel? next = paraList[(Guid)current.VariableID!];
|
||||
if (next == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public (bool, string?) GetResult()
|
||||
{
|
||||
if (Type == typeof(string) && (!string.IsNullOrWhiteSpace(LowerLimit?.ToString()) || !string.IsNullOrWhiteSpace(UpperLimit?.ToString())))
|
||||
{
|
||||
return (true, $"参数 [ {Name}({Type}) ] 不可比较");
|
||||
}
|
||||
|
||||
if (Value == null || (LowerLimit == null && UpperLimit == null))
|
||||
{
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Value?.ToString()) || (string.IsNullOrWhiteSpace(LowerLimit?.ToString()) && string.IsNullOrWhiteSpace(UpperLimit?.ToString())))
|
||||
{
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
object? comparableValue = ConvertToComparable(Value);
|
||||
object? comparableLower = LowerLimit != null ? ConvertToComparable(LowerLimit) : null;
|
||||
object? comparableUpper = UpperLimit != null ? ConvertToComparable(UpperLimit) : null;
|
||||
|
||||
if (comparableValue == null)
|
||||
{
|
||||
return (true, $"参数 [ {Name}({Type}) ] 不可比较");
|
||||
}
|
||||
|
||||
bool lowerValid = true;
|
||||
bool upperValid = true;
|
||||
|
||||
if (comparableLower != null)
|
||||
{
|
||||
lowerValid = CompareValues(comparableValue, comparableLower) >= 0;
|
||||
}
|
||||
|
||||
if (comparableUpper != null)
|
||||
{
|
||||
upperValid = CompareValues(comparableValue, comparableUpper) <= 0;
|
||||
}
|
||||
|
||||
return (lowerValid && upperValid, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (true, $"参数 [ {Name}({Type}) ] 上下限比较失败:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static object? ConvertToComparable(object value)
|
||||
{
|
||||
if (value is IConvertible convertible)
|
||||
{
|
||||
try
|
||||
{
|
||||
return convertible.ToDouble(null);
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
return convertible.ToDateTime(null);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int CompareValues(object a, object b)
|
||||
{
|
||||
if (a is double aDouble && b is double bDouble)
|
||||
{
|
||||
return aDouble.CompareTo(bDouble);
|
||||
}
|
||||
|
||||
if (a is DateTime aDate && b is DateTime bDate)
|
||||
{
|
||||
return aDate.CompareTo(bDate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
51
UIShare/UIViewModel/ProgramModel.cs
Normal file
51
UIShare/UIViewModel/ProgramModel.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class ProgramModel : BindableBase
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
public ProgramModel()
|
||||
{
|
||||
// 可以进行初始化操作
|
||||
}
|
||||
|
||||
public ProgramModel(ProgramModel source)
|
||||
{
|
||||
ID = source.ID;
|
||||
StepCollection = new ObservableCollection<StepModel>(source.StepCollection.Select(p => new StepModel(p)));
|
||||
ErrorStepCollection = new ObservableCollection<StepModel>(source.ErrorStepCollection.Select(p => new StepModel(p)));
|
||||
Parameters = new ObservableCollection<ParameterModel>(source.Parameters.Select(p => new ParameterModel(p)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Guid ID { get; set; } = Guid.NewGuid();
|
||||
|
||||
private ObservableCollection<StepModel> _stepCollection = new ObservableCollection<StepModel>();
|
||||
public ObservableCollection<StepModel> StepCollection
|
||||
{
|
||||
get => _stepCollection;
|
||||
set => SetProperty(ref _stepCollection, value);
|
||||
}
|
||||
private ObservableCollection<StepModel> _errorStepCollection = new ObservableCollection<StepModel>();
|
||||
public ObservableCollection<StepModel> ErrorStepCollection
|
||||
{
|
||||
get => _errorStepCollection;
|
||||
set => SetProperty(ref _errorStepCollection, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<ParameterModel> _parameters = new ObservableCollection<ParameterModel>();
|
||||
public ObservableCollection<ParameterModel> Parameters
|
||||
{
|
||||
get => _parameters;
|
||||
set => SetProperty(ref _parameters, value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
178
UIShare/UIViewModel/StepModel.cs
Normal file
178
UIShare/UIViewModel/StepModel.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using Newtonsoft.Json;
|
||||
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||
using System;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class StepModel : BindableBase
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
public StepModel() { }
|
||||
|
||||
public StepModel(StepModel source)
|
||||
{
|
||||
if (source == null) return;
|
||||
|
||||
ID = source.ID;
|
||||
Index = source.Index;
|
||||
Name = source.Name;
|
||||
StepType = source.StepType;
|
||||
LoopCount = source.LoopCount;
|
||||
LoopStartStepId = source.LoopStartStepId;
|
||||
OKExpression = source.OKExpression;
|
||||
OKGotoStepID = source.OKGotoStepID;
|
||||
GotoSettingString = source.GotoSettingString;
|
||||
NGGotoStepID = source.NGGotoStepID;
|
||||
Description = source.Description;
|
||||
IsUsed = source.IsUsed;
|
||||
|
||||
if (source.Method != null)
|
||||
{
|
||||
Method = new MethodModel(source.Method);
|
||||
}
|
||||
if (source.SubProgram != null)
|
||||
{
|
||||
SubProgram = new ProgramModel(source.SubProgram);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Guid _id = Guid.NewGuid();
|
||||
|
||||
public Guid ID
|
||||
{
|
||||
get => _id;
|
||||
set => SetProperty(ref _id, value);
|
||||
}
|
||||
|
||||
private bool _isUsed = true;
|
||||
|
||||
public bool IsUsed
|
||||
{
|
||||
get => _isUsed;
|
||||
set => SetProperty(ref _isUsed, value);
|
||||
}
|
||||
|
||||
private int _index;
|
||||
|
||||
public int Index
|
||||
{
|
||||
get => _index;
|
||||
set => SetProperty(ref _index, value);
|
||||
}
|
||||
|
||||
private string? _name;
|
||||
|
||||
public string? Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetProperty(ref _name, value);
|
||||
}
|
||||
|
||||
private string? _stepType;
|
||||
|
||||
public string? StepType
|
||||
{
|
||||
get => _stepType;
|
||||
set => SetProperty(ref _stepType, value);
|
||||
}
|
||||
|
||||
private MethodModel? _method;
|
||||
|
||||
public MethodModel? Method
|
||||
{
|
||||
get => _method;
|
||||
set => SetProperty(ref _method, value);
|
||||
}
|
||||
|
||||
private ProgramModel? _subProgram;
|
||||
|
||||
public ProgramModel? SubProgram
|
||||
{
|
||||
get => _subProgram;
|
||||
set => SetProperty(ref _subProgram, value);
|
||||
}
|
||||
|
||||
private int? _loopCount;
|
||||
|
||||
public int? LoopCount
|
||||
{
|
||||
get => _loopCount;
|
||||
set => SetProperty(ref _loopCount, value);
|
||||
}
|
||||
[JsonIgnore]
|
||||
private int? _currentLoopCount;
|
||||
[JsonIgnore]
|
||||
public int? CurrentLoopCount
|
||||
{
|
||||
get => _currentLoopCount;
|
||||
set => SetProperty(ref _currentLoopCount, value);
|
||||
}
|
||||
|
||||
private Guid? _loopStartStepId;
|
||||
|
||||
public Guid? LoopStartStepId
|
||||
{
|
||||
get => _loopStartStepId;
|
||||
set => SetProperty(ref _loopStartStepId, value);
|
||||
}
|
||||
[JsonIgnore]
|
||||
private int _result = -1;
|
||||
[JsonIgnore]
|
||||
public int Result
|
||||
{
|
||||
get => _result;
|
||||
set => SetProperty(ref _result, value);
|
||||
}
|
||||
[JsonIgnore]
|
||||
private int? _runTime;
|
||||
[JsonIgnore]
|
||||
public int? RunTime
|
||||
{
|
||||
get => _runTime;
|
||||
set => SetProperty(ref _runTime, value);
|
||||
}
|
||||
|
||||
private string? _okExpression;
|
||||
|
||||
public string? OKExpression
|
||||
{
|
||||
get => _okExpression;
|
||||
set => SetProperty(ref _okExpression, value);
|
||||
}
|
||||
|
||||
private string _gotoSettingString = "";
|
||||
|
||||
public string GotoSettingString
|
||||
{
|
||||
get => _gotoSettingString;
|
||||
set => SetProperty(ref _gotoSettingString, value);
|
||||
}
|
||||
|
||||
private Guid? _okGotoStepID;
|
||||
|
||||
public Guid? OKGotoStepID
|
||||
{
|
||||
get => _okGotoStepID;
|
||||
set => SetProperty(ref _okGotoStepID, value);
|
||||
}
|
||||
|
||||
private Guid? _ngGotoStepID;
|
||||
|
||||
public Guid? NGGotoStepID
|
||||
{
|
||||
get => _ngGotoStepID;
|
||||
set => SetProperty(ref _ngGotoStepID, value);
|
||||
}
|
||||
|
||||
private string? _description;
|
||||
|
||||
public string? Description
|
||||
{
|
||||
get => _description;
|
||||
set => SetProperty(ref _description, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
UIShare/UIViewModel/SubProgramItem.cs
Normal file
15
UIShare/UIViewModel/SubProgramItem.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.UIViewModel
|
||||
{
|
||||
public class SubProgramItem
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
public string FilePath { get; set; } = "";
|
||||
}
|
||||
}
|
||||
27
UIShare/ViewModelBase/DialogViewModelBase.cs
Normal file
27
UIShare/ViewModelBase/DialogViewModelBase.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Notifications.Wpf.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.ViewModelBase
|
||||
{
|
||||
public abstract class DialogViewModelBase : BindableBase,IDialogAware
|
||||
{
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
public IEventAggregator _eventAggregator;
|
||||
private INotificationManager _notificationManager;
|
||||
public DialogViewModelBase(IContainerProvider containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
_notificationManager = containerProvider.Resolve<INotificationManager>();
|
||||
}
|
||||
#region Dialog
|
||||
|
||||
public virtual bool CanCloseDialog() => true;
|
||||
public virtual void OnDialogClosed() { }
|
||||
public virtual void OnDialogOpened(IDialogParameters parameters) { }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
63
UIShare/ViewModelBase/NavigateViewModelBase.cs
Normal file
63
UIShare/ViewModelBase/NavigateViewModelBase.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Notifications.Wpf.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.GlobalVariable;
|
||||
|
||||
namespace UIShare.ViewModelBase
|
||||
{
|
||||
public abstract class NavigateViewModelBase : BindableBase, INavigationAware
|
||||
{
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
public IEventAggregator _eventAggregator;
|
||||
public IDialogService _dialogService;
|
||||
public IRegionManager _regionManager;
|
||||
private INotificationManager _notificationManager;
|
||||
private GlobalInfo _globalInfo;
|
||||
public NavigateViewModelBase(IContainerProvider containerProvider)
|
||||
{
|
||||
_globalInfo=containerProvider.Resolve<GlobalInfo>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
_dialogService = containerProvider.Resolve<IDialogService>();
|
||||
_regionManager = containerProvider.Resolve<IRegionManager>();
|
||||
_notificationManager = containerProvider.Resolve<INotificationManager>();
|
||||
}
|
||||
|
||||
protected void ShowInfoMessageBox(string Message,Action callback)
|
||||
{
|
||||
var dialogParams = new DialogParameters();
|
||||
dialogParams.Add("Title", "提示");
|
||||
dialogParams.Add("Message", Message);
|
||||
dialogParams.Add("Icon", "info");
|
||||
dialogParams.Add("ShowOk", true);
|
||||
_dialogService.ShowDialog("MessageBoxView", dialogParams, result =>
|
||||
{
|
||||
callback();
|
||||
});
|
||||
}
|
||||
protected void ShowErrorMessageBox(string Message,Action callback)
|
||||
{
|
||||
var dialogParams = new DialogParameters();
|
||||
dialogParams.Add("Title", "错误");
|
||||
dialogParams.Add("Message", Message);
|
||||
dialogParams.Add("Icon", "info");
|
||||
dialogParams.Add("ShowOk", true);
|
||||
_dialogService.ShowDialog("MessageBoxView", dialogParams, result =>
|
||||
{
|
||||
callback();
|
||||
});
|
||||
}
|
||||
#region Navigation
|
||||
|
||||
public virtual void OnNavigatedTo(NavigationContext navigationContext) { }
|
||||
|
||||
public virtual bool IsNavigationTarget(NavigationContext navigationContext) => true;
|
||||
|
||||
public virtual void OnNavigatedFrom(NavigationContext navigationContext) { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user