修复流程图编辑器界面及初步的功能
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
using Moq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Media.Imaging;
|
||||
using XP.Common.Logging.Interfaces;
|
||||
using XplorePlane.Models;
|
||||
using XplorePlane.Services;
|
||||
@@ -104,6 +107,36 @@ namespace XplorePlane.Tests.Pipeline
|
||||
Assert.Equal(i, vm.PipelineNodes[i].Order);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadImageFromFile_SetsSourceImage()
|
||||
{
|
||||
var vm = CreateVm();
|
||||
var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".png");
|
||||
|
||||
try
|
||||
{
|
||||
var bitmap = TestHelpers.CreateTestBitmap(8, 8);
|
||||
var encoder = new PngBitmapEncoder();
|
||||
encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
||||
|
||||
using (var stream = File.Create(tempPath))
|
||||
{
|
||||
encoder.Save(stream);
|
||||
}
|
||||
|
||||
vm.LoadImageFromFile(tempPath);
|
||||
|
||||
Assert.NotNull(vm.SourceImage);
|
||||
Assert.NotNull(vm.PreviewImage);
|
||||
Assert.Contains(Path.GetFileName(tempPath), vm.StatusMessage);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(tempPath))
|
||||
File.Delete(tempPath);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 6.2 RemoveOperatorCommand ─────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using Moq;
|
||||
using XP.Common.Logging.Interfaces;
|
||||
using XplorePlane.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace XplorePlane.Tests.Services
|
||||
{
|
||||
public class ImageProcessingServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void DiscoverProcessors_LoadsKnownProcessors()
|
||||
{
|
||||
var logger = new Mock<ILoggerService>();
|
||||
logger.Setup(l => l.ForModule<ImageProcessingService>()).Returns(logger.Object);
|
||||
|
||||
using var service = new ImageProcessingService(logger.Object);
|
||||
|
||||
var processors = service.GetAvailableProcessors();
|
||||
|
||||
Assert.Contains("GaussianBlur", processors);
|
||||
Assert.Contains("ShockFilter", processors);
|
||||
Assert.Contains("BandPassFilter", processors);
|
||||
Assert.Contains("Division", processors);
|
||||
Assert.Contains("Contour", processors);
|
||||
Assert.True(processors.Count >= 20, $"Expected many discovered processors, got {processors.Count}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +268,6 @@ namespace XplorePlane
|
||||
|
||||
// 注册视图和视图模型
|
||||
containerRegistry.RegisterForNavigation<MainWindow>();
|
||||
containerRegistry.RegisterForNavigation<MainWindowB>();
|
||||
containerRegistry.Register<MainViewModel>();
|
||||
containerRegistry.RegisterSingleton<NavigationPropertyPanelViewModel>();
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("XplorePlane.Tests")]
|
||||
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
|
||||
namespace XplorePlane.Services
|
||||
{
|
||||
internal static class ProcessorUiMetadata
|
||||
{
|
||||
private static readonly (string Category, string CategoryIcon, int Order)[] CategoryDefinitions =
|
||||
{
|
||||
("滤波与平滑", "🌀", 0),
|
||||
("图像增强", "✨", 1),
|
||||
("图像变换", "🔁", 2),
|
||||
("数学运算", "➗", 3),
|
||||
("形态学处理", "⬚", 4),
|
||||
("边缘检测", "📐", 5),
|
||||
("检测分析", "🔎", 6),
|
||||
("其他", "⚙", 99),
|
||||
};
|
||||
|
||||
internal static (string Category, string CategoryIcon, string OperatorIcon) Get(string operatorKey)
|
||||
{
|
||||
var category = GetCategory(operatorKey);
|
||||
return (category, GetCategoryIcon(category), GetOperatorIcon(operatorKey, category));
|
||||
}
|
||||
|
||||
internal static string GetCategory(string operatorKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(operatorKey))
|
||||
return "其他";
|
||||
|
||||
if (ContainsAny(operatorKey, "Blur", "Filter", "Shock"))
|
||||
return "滤波与平滑";
|
||||
|
||||
if (ContainsAny(operatorKey, "Contrast", "Gamma", "Retinex", "Histogram", "Sharpen", "Layer",
|
||||
"SubPixel", "SuperResolution", "HDR", "Effect", "PseudoColor", "Color"))
|
||||
return "图像增强";
|
||||
|
||||
if (ContainsAny(operatorKey, "Mirror", "Rotate", "Grayscale", "Threshold"))
|
||||
return "图像变换";
|
||||
|
||||
if (ContainsAny(operatorKey, "Division", "Multiplication", "Difference", "Integral", "Or"))
|
||||
return "数学运算";
|
||||
|
||||
if (ContainsAny(operatorKey, "Morphology"))
|
||||
return "形态学处理";
|
||||
|
||||
if (ContainsAny(operatorKey, "Edge"))
|
||||
return "边缘检测";
|
||||
|
||||
if (ContainsAny(operatorKey, "Measurement", "Detection", "Contour", "FillRate", "Void", "Line", "PointToLine", "Ellipse", "Bga"))
|
||||
return "检测分析";
|
||||
|
||||
return "其他";
|
||||
}
|
||||
|
||||
internal static int GetCategoryOrder(string category)
|
||||
{
|
||||
foreach (var definition in CategoryDefinitions)
|
||||
{
|
||||
if (string.Equals(definition.Category, category, StringComparison.Ordinal))
|
||||
return definition.Order;
|
||||
}
|
||||
|
||||
return 99;
|
||||
}
|
||||
|
||||
internal static string GetCategoryIcon(string category)
|
||||
{
|
||||
foreach (var definition in CategoryDefinitions)
|
||||
{
|
||||
if (string.Equals(definition.Category, category, StringComparison.Ordinal))
|
||||
return definition.CategoryIcon;
|
||||
}
|
||||
|
||||
return "⚙";
|
||||
}
|
||||
|
||||
internal static string GetOperatorIcon(string operatorKey) => GetOperatorIcon(operatorKey, GetCategory(operatorKey));
|
||||
|
||||
private static string GetOperatorIcon(string operatorKey, string category)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(operatorKey))
|
||||
return GetCategoryIcon(category);
|
||||
|
||||
if (ContainsAny(operatorKey, "Shock"))
|
||||
return "⚡";
|
||||
if (ContainsAny(operatorKey, "BandPass"))
|
||||
return "📶";
|
||||
if (ContainsAny(operatorKey, "GaussianBlur", "MeanFilter", "MedianFilter", "BilateralFilter", "LowPassFilter", "HighPassFilter"))
|
||||
return "🌀";
|
||||
if (ContainsAny(operatorKey, "Contrast"))
|
||||
return "🌗";
|
||||
if (ContainsAny(operatorKey, "Gamma"))
|
||||
return "γ";
|
||||
if (ContainsAny(operatorKey, "Retinex"))
|
||||
return "🎛";
|
||||
if (ContainsAny(operatorKey, "Histogram"))
|
||||
return "📊";
|
||||
if (ContainsAny(operatorKey, "Sharpen"))
|
||||
return "✦";
|
||||
if (ContainsAny(operatorKey, "SubPixel", "SuperResolution"))
|
||||
return "🔬";
|
||||
if (ContainsAny(operatorKey, "HDR"))
|
||||
return "💡";
|
||||
if (ContainsAny(operatorKey, "PseudoColor"))
|
||||
return "🎨";
|
||||
if (ContainsAny(operatorKey, "FilmEffect"))
|
||||
return "🎞";
|
||||
if (ContainsAny(operatorKey, "ColorLayer"))
|
||||
return "🧪";
|
||||
if (ContainsAny(operatorKey, "Mirror"))
|
||||
return "↔";
|
||||
if (ContainsAny(operatorKey, "Rotate"))
|
||||
return "⟳";
|
||||
if (ContainsAny(operatorKey, "Grayscale"))
|
||||
return "◻";
|
||||
if (ContainsAny(operatorKey, "Threshold"))
|
||||
return "▣";
|
||||
if (ContainsAny(operatorKey, "Division"))
|
||||
return "➗";
|
||||
if (ContainsAny(operatorKey, "Multiplication"))
|
||||
return "✕";
|
||||
if (ContainsAny(operatorKey, "Difference"))
|
||||
return "Δ";
|
||||
if (ContainsAny(operatorKey, "Integral"))
|
||||
return "∫";
|
||||
if (ContainsAny(operatorKey, "Or"))
|
||||
return "∨";
|
||||
if (ContainsAny(operatorKey, "Morphology"))
|
||||
return "⬚";
|
||||
if (ContainsAny(operatorKey, "Sobel", "Kirsch", "HorizontalEdge"))
|
||||
return "📐";
|
||||
if (ContainsAny(operatorKey, "Contour"))
|
||||
return "✏";
|
||||
if (ContainsAny(operatorKey, "Measurement"))
|
||||
return "📏";
|
||||
if (ContainsAny(operatorKey, "FillRate"))
|
||||
return "🧮";
|
||||
if (ContainsAny(operatorKey, "Void"))
|
||||
return "⚪";
|
||||
if (ContainsAny(operatorKey, "Ellipse"))
|
||||
return "⭕";
|
||||
if (ContainsAny(operatorKey, "PointToLine"))
|
||||
return "📍";
|
||||
if (ContainsAny(operatorKey, "Edge"))
|
||||
return "📐";
|
||||
|
||||
return GetCategoryIcon(category);
|
||||
}
|
||||
|
||||
private static bool ContainsAny(string value, params string[] terms)
|
||||
{
|
||||
foreach (var term in terms)
|
||||
{
|
||||
if (value.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ namespace XplorePlane.ViewModels
|
||||
SaveAsPipelineCommand = new DelegateCommand(async () => await SaveAsPipelineAsync());
|
||||
DeletePipelineCommand = new DelegateCommand(async () => await DeletePipelineAsync());
|
||||
LoadPipelineCommand = new DelegateCommand(async () => await LoadPipelineAsync());
|
||||
LoadImageCommand = new DelegateCommand(LoadImage);
|
||||
OpenToolboxCommand = new DelegateCommand(OpenToolbox);
|
||||
MoveNodeUpCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeUp);
|
||||
MoveNodeDownCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeDown);
|
||||
@@ -88,6 +89,7 @@ namespace XplorePlane.ViewModels
|
||||
if (SetProperty(ref _sourceImage, value))
|
||||
{
|
||||
ExecutePipelineCommand.RaiseCanExecuteChanged();
|
||||
RaisePropertyChanged(nameof(DisplayImage));
|
||||
TriggerDebouncedExecution();
|
||||
}
|
||||
}
|
||||
@@ -96,9 +98,15 @@ namespace XplorePlane.ViewModels
|
||||
public BitmapSource PreviewImage
|
||||
{
|
||||
get => _previewImage;
|
||||
set => SetProperty(ref _previewImage, value);
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _previewImage, value))
|
||||
RaisePropertyChanged(nameof(DisplayImage));
|
||||
}
|
||||
}
|
||||
|
||||
public BitmapSource DisplayImage => PreviewImage ?? SourceImage;
|
||||
|
||||
public string PipelineName
|
||||
{
|
||||
get => _pipelineName;
|
||||
@@ -142,6 +150,7 @@ namespace XplorePlane.ViewModels
|
||||
public DelegateCommand SaveAsPipelineCommand { get; }
|
||||
public DelegateCommand DeletePipelineCommand { get; }
|
||||
public DelegateCommand LoadPipelineCommand { get; }
|
||||
public DelegateCommand LoadImageCommand { get; }
|
||||
|
||||
public DelegateCommand OpenToolboxCommand { get; }
|
||||
|
||||
@@ -316,6 +325,45 @@ namespace XplorePlane.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadImage()
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
Title = "加载图像",
|
||||
Filter = "图像文件|*.bmp;*.png;*.jpg;*.jpeg;*.tif;*.tiff|所有文件|*.*"
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() != true)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
LoadImageFromFile(dialog.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusMessage = $"加载图像失败:{ex.Message}";
|
||||
_logger.Error(ex, "加载图像失败:{Path}", dialog.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
internal void LoadImageFromFile(string filePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filePath))
|
||||
throw new ArgumentException("图像路径不能为空", nameof(filePath));
|
||||
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.UriSource = new Uri(filePath, UriKind.Absolute);
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.EndInit();
|
||||
bitmap.Freeze();
|
||||
|
||||
SourceImage = bitmap;
|
||||
PreviewImage = bitmap;
|
||||
StatusMessage = $"已加载图像:{Path.GetFileName(filePath)}";
|
||||
}
|
||||
|
||||
private void CancelExecution()
|
||||
{
|
||||
_executionCts?.Cancel();
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="库版本信息"
|
||||
Width="850"
|
||||
Width="400"
|
||||
Height="600"
|
||||
ResizeMode="CanResizeWithGrip"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
@@ -4,11 +4,9 @@
|
||||
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:prism="http://prismlibrary.com/"
|
||||
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
|
||||
d:DesignHeight="700"
|
||||
d:DesignWidth="350"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
@@ -48,13 +46,14 @@
|
||||
<Grid.RowDefinitions>
|
||||
<!-- Row 0: 工具栏 -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Row 1: 流水线节点列表 -->
|
||||
<RowDefinition Height="3*" />
|
||||
<!-- Row 2: 分隔线 -->
|
||||
|
||||
<!-- Row 2: 流水线节点列表 -->
|
||||
<RowDefinition Height="2*" MinHeight="180" />
|
||||
<!-- Row 3: 分隔线 -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Row 3: 参数面板 -->
|
||||
<!-- Row 4: 参数面板 -->
|
||||
<RowDefinition Height="2*" MinHeight="80" />
|
||||
<!-- Row 4: 状态栏 -->
|
||||
<!-- Row 5: 状态栏 -->
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
@@ -90,6 +89,12 @@
|
||||
Content="加载"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="加载流水线" />
|
||||
<Button
|
||||
Width="64"
|
||||
Command="{Binding LoadImageCommand}"
|
||||
Content="加载图像"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="加载输入图像" />
|
||||
<Button
|
||||
Command="{Binding ExecutePipelineCommand}"
|
||||
Content="▶"
|
||||
@@ -109,6 +114,9 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 流水线节点列表(拖拽目标) -->
|
||||
<ListBox
|
||||
x:Name="PipelineListBox"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Prism.Ioc;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -22,6 +23,18 @@ namespace XplorePlane.Views
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataContext = ContainerLocator.Current?.Resolve<PipelineEditorViewModel>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.Error(ex, "PipelineEditorViewModel 解析失败");
|
||||
}
|
||||
}
|
||||
|
||||
_logger?.Info("PipelineEditorView DataContext 类型={Type}",
|
||||
DataContext?.GetType().Name);
|
||||
|
||||
@@ -50,7 +63,7 @@ namespace XplorePlane.Views
|
||||
|
||||
if (!e.Data.GetDataPresent(OperatorToolboxView.DragFormat))
|
||||
{
|
||||
_logger?.Warn("Drop 事件触发但数据中无 {Format}", OperatorToolboxView.DragFormat);
|
||||
_logger?.Warn("Drop 事件触发但数据中没有 {Format}", OperatorToolboxView.DragFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,46 @@
|
||||
<Window x:Class="XplorePlane.Views.PipelineEditorWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:roi="clr-namespace:XP.ImageProcessing.RoiControl.Controls;assembly=XP.ImageProcessing.RoiControl"
|
||||
xmlns:views="clr-namespace:XplorePlane.Views"
|
||||
Title="流水线编辑器"
|
||||
Width="700" Height="750"
|
||||
Width="1200"
|
||||
Height="750"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ShowInTaskbar="False">
|
||||
<Grid>
|
||||
<Grid Background="#F3F3F3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="240" MinWidth="200" />
|
||||
<ColumnDefinition Width="*" MinWidth="400" />
|
||||
<ColumnDefinition Width="250" MinWidth="250" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<views:OperatorToolboxView Grid.Column="0" />
|
||||
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Background="#E0E0E0" />
|
||||
<views:PipelineEditorView Grid.Column="2" />
|
||||
|
||||
<Border Grid.Column="0"
|
||||
Margin="8"
|
||||
Background="White"
|
||||
BorderBrush="#D0D0D0"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<views:OperatorToolboxView />
|
||||
</Border>
|
||||
|
||||
<Border Grid.Column="1"
|
||||
Margin="8,8,4,8"
|
||||
Background="White"
|
||||
BorderBrush="#D0D0D0"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<roi:PolygonRoiCanvas ImageSource="{Binding DisplayImage}"
|
||||
Background="White" />
|
||||
</Border>
|
||||
|
||||
<Border Grid.Column="2"
|
||||
Margin="4,8,8,8"
|
||||
Background="White"
|
||||
BorderBrush="#D0D0D0"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<views:PipelineEditorView />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,4 +1,7 @@
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using XplorePlane.ViewModels;
|
||||
|
||||
namespace XplorePlane.Views
|
||||
{
|
||||
@@ -7,6 +10,15 @@ namespace XplorePlane.Views
|
||||
public PipelineEditorWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
try
|
||||
{
|
||||
DataContext = ContainerLocator.Current?.Resolve<PipelineEditorViewModel>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:roi="clr-namespace:XP.ImageProcessing.RoiControl.Controls;assembly=XP.ImageProcessing.RoiControl"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
d:DesignHeight="400"
|
||||
d:DesignWidth="600"
|
||||
@@ -22,14 +23,10 @@
|
||||
FontWeight="SemiBold" Foreground="#333333" Text="实时图像" />
|
||||
</Border>
|
||||
|
||||
<!-- 图像显示区域,支持滚动 -->
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Image Source="{Binding ImageSource}"
|
||||
Stretch="None"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
RenderOptions.BitmapScalingMode="NearestNeighbor" />
|
||||
</ScrollViewer>
|
||||
<!-- 图像显示区域,支持滚动、缩放和ROI -->
|
||||
<roi:PolygonRoiCanvas Grid.Row="1"
|
||||
ImageSource="{Binding ImageSource}"
|
||||
Background="White" />
|
||||
|
||||
<!-- 图像信息栏 -->
|
||||
<Border Grid.Row="2" Background="#F0F0F0" BorderBrush="#DDDDDD" BorderThickness="0,1,0,0">
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="MainWindow.xaml" />
|
||||
<Page Remove="Views\Main\MainWindowB.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- NuGet 包引用 -->
|
||||
@@ -144,6 +145,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Link>Libs\Hardware\zh-TW\%(Filename)%(Extension)</Link>
|
||||
</None>
|
||||
<Compile Remove="Views\Main\MainWindowB.xaml.cs" />
|
||||
|
||||
<Resource Include="XplorerPlane.ico" />
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ CNC及矩阵功能的设计与评审,包含以下功能: √
|
||||
2026.4.20
|
||||
----------------------
|
||||
1、图像算子工具箱的图标 √
|
||||
2、最新的图像算子集成到图像工具箱
|
||||
3、修复流程图编辑器
|
||||
2、最新的图像算子集成到图像工具箱 √
|
||||
3、修复流程图编辑器界面及初步的功能 √
|
||||
4、主页面加载图像的功能
|
||||
5、
|
||||
|
||||
|
||||
Reference in New Issue
Block a user