619 lines
24 KiB
C#
619 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using Prism.Commands;
|
|
using Prism.Mvvm;
|
|
using XP.Common.GeneralForm.Views;
|
|
using XP.Common.Logging.Interfaces;
|
|
using XP.Common.PdfViewer.Interfaces;
|
|
using XP.ReportEngine.Configs;
|
|
using XP.ReportEngine.Interfaces;
|
|
using XP.ReportEngine.Models;
|
|
using XP.ReportEngine.Services;
|
|
|
|
namespace XP.ReportEngine.ViewModels
|
|
{
|
|
/// <summary>
|
|
/// 报告生成演示窗口 ViewModel | Report generation demo window ViewModel
|
|
/// 演示如何使用 IReportService 生成 PDF 报告
|
|
/// Demonstrates how to use IReportService to generate PDF reports
|
|
/// </summary>
|
|
public class ReportDemoViewModel : BindableBase
|
|
{
|
|
private readonly IReportService _reportService;
|
|
private readonly IPdfViewerService _pdfViewerService;
|
|
private readonly IPdfPrintService _pdfPrintService;
|
|
private readonly ILoggerService _logger;
|
|
private readonly ReportIdGenerator _reportIdGenerator;
|
|
private readonly ReportConfig _reportConfig;
|
|
|
|
private string _productName = "PCB-TEST-001";
|
|
private string _operatorName = "戚明轩 mingxuan.qi@hexagon.com";
|
|
private string _description = "BGA 焊球气泡率检测";
|
|
private string _cncProgram = "Prog001";
|
|
private string _productCode = "PCBA-X100";
|
|
private string _workpieceSN = "SN20250001";
|
|
private string _deviceId = "XP-CT-001";
|
|
private string _machineId = "MC01";
|
|
private string _statusMessage = "就绪";
|
|
private string _lastOutputPath;
|
|
private bool _isGenerating;
|
|
|
|
#region 属性 | Properties
|
|
|
|
/// <summary>
|
|
/// 产品名称 | Product name
|
|
/// </summary>
|
|
public string ProductName
|
|
{
|
|
get => _productName;
|
|
set => SetProperty(ref _productName, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 操作员 | Operator
|
|
/// </summary>
|
|
public string OperatorName
|
|
{
|
|
get => _operatorName;
|
|
set => SetProperty(ref _operatorName, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 描述 | Description
|
|
/// </summary>
|
|
public string Description
|
|
{
|
|
get => _description;
|
|
set => SetProperty(ref _description, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// CNC 程序名称 | CNC program name
|
|
/// </summary>
|
|
public string CncProgram
|
|
{
|
|
get => _cncProgram;
|
|
set => SetProperty(ref _cncProgram, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 产品类型码 | Product type code
|
|
/// </summary>
|
|
public string ProductCode
|
|
{
|
|
get => _productCode;
|
|
set => SetProperty(ref _productCode, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 工件 SN 码 | Workpiece serial number
|
|
/// </summary>
|
|
public string WorkpieceSN
|
|
{
|
|
get => _workpieceSN;
|
|
set => SetProperty(ref _workpieceSN, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检测设备编号 | Inspection device ID
|
|
/// </summary>
|
|
public string DeviceId
|
|
{
|
|
get => _deviceId;
|
|
set => SetProperty(ref _deviceId, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生产机台号 | Production machine ID
|
|
/// </summary>
|
|
public string MachineId
|
|
{
|
|
get => _machineId;
|
|
set => SetProperty(ref _machineId, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 状态信息 | Status message
|
|
/// </summary>
|
|
public string StatusMessage
|
|
{
|
|
get => _statusMessage;
|
|
set => SetProperty(ref _statusMessage, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否正在生成 | Whether generating
|
|
/// </summary>
|
|
public bool IsGenerating
|
|
{
|
|
get => _isGenerating;
|
|
set
|
|
{
|
|
if (SetProperty(ref _isGenerating, value))
|
|
{
|
|
GenerateReportCommand.RaiseCanExecuteChanged();
|
|
OpenViewerCommand.RaiseCanExecuteChanged();
|
|
PrintReportCommand.RaiseCanExecuteChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 命令 | Commands
|
|
|
|
/// <summary>
|
|
/// 生成报告命令 | Generate report command
|
|
/// </summary>
|
|
public DelegateCommand GenerateReportCommand { get; }
|
|
|
|
/// <summary>
|
|
/// 打开 PDF 阅读器命令 | Open PDF viewer command
|
|
/// </summary>
|
|
public DelegateCommand OpenViewerCommand { get; }
|
|
|
|
/// <summary>
|
|
/// 打印报告命令 | Print report command
|
|
/// </summary>
|
|
public DelegateCommand PrintReportCommand { get; }
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 构造函数 | Constructor
|
|
/// </summary>
|
|
public ReportDemoViewModel(
|
|
IReportService reportService,
|
|
IPdfViewerService pdfViewerService,
|
|
IPdfPrintService pdfPrintService,
|
|
ILoggerService logger,
|
|
ReportIdGenerator reportIdGenerator,
|
|
ReportConfig reportConfig)
|
|
{
|
|
_reportService = reportService ?? throw new ArgumentNullException(nameof(reportService));
|
|
_pdfViewerService = pdfViewerService ?? throw new ArgumentNullException(nameof(pdfViewerService));
|
|
_pdfPrintService = pdfPrintService ?? throw new ArgumentNullException(nameof(pdfPrintService));
|
|
_logger = logger?.ForModule<ReportDemoViewModel>() ?? throw new ArgumentNullException(nameof(logger));
|
|
_reportIdGenerator = reportIdGenerator ?? throw new ArgumentNullException(nameof(reportIdGenerator));
|
|
_reportConfig = reportConfig ?? throw new ArgumentNullException(nameof(reportConfig));
|
|
|
|
GenerateReportCommand = new DelegateCommand(async () => await GenerateReportAsync(), () => !IsGenerating);
|
|
OpenViewerCommand = new DelegateCommand(OpenViewer, () => !IsGenerating && !string.IsNullOrEmpty(_lastOutputPath));
|
|
PrintReportCommand = new DelegateCommand(PrintReport, () => !IsGenerating && !string.IsNullOrEmpty(_lastOutputPath));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成报告(带进度条)| Generate report (with progress window)
|
|
/// </summary>
|
|
private async Task GenerateReportAsync()
|
|
{
|
|
IsGenerating = true;
|
|
StatusMessage = "正在生成报告...";
|
|
|
|
try
|
|
{
|
|
// 构建文件名占位符参数 | Build file name placeholder parameters
|
|
var fileNameParams = new Dictionary<string, string>
|
|
{
|
|
["ReportId"] = _reportIdGenerator.GenerateNext(),
|
|
["ProductName"] = ProductName,
|
|
["CncProgram"] = CncProgram,
|
|
["ProductCode"] = ProductCode,
|
|
["WorkpieceSN"] = WorkpieceSN,
|
|
["DeviceId"] = DeviceId,
|
|
["MachineId"] = MachineId,
|
|
["Result"] = "Pass"
|
|
};
|
|
|
|
// 确定输出路径:提示用户是否使用默认位置 | Determine output path: ask user whether to use default location
|
|
var defaultOutputPath = _reportConfig.ResolveOutputFilePath(fileNameParams);
|
|
var defaultFileName = System.IO.Path.GetFileName(defaultOutputPath);
|
|
|
|
var result = MessageBox.Show(
|
|
$"是否将报告输出到默认位置?\r\n{defaultOutputPath}",
|
|
"输出位置确认",
|
|
MessageBoxButton.YesNoCancel,
|
|
MessageBoxImage.Question);
|
|
|
|
if (result == MessageBoxResult.Cancel)
|
|
{
|
|
StatusMessage = "已取消生成";
|
|
IsGenerating = false;
|
|
return;
|
|
}
|
|
|
|
string outputPath;
|
|
if (result == MessageBoxResult.No)
|
|
{
|
|
// 用户选择自定义位置 | User chooses custom location
|
|
var saveDialog = new Microsoft.Win32.SaveFileDialog
|
|
{
|
|
Title = "选择报告保存位置",
|
|
Filter = "PDF 文件 (*.pdf)|*.pdf",
|
|
FileName = defaultFileName,
|
|
DefaultExt = ".pdf",
|
|
InitialDirectory = System.IO.Path.GetDirectoryName(defaultOutputPath)
|
|
};
|
|
|
|
if (saveDialog.ShowDialog() != true)
|
|
{
|
|
StatusMessage = "已取消生成";
|
|
IsGenerating = false;
|
|
return;
|
|
}
|
|
|
|
outputPath = saveDialog.FileName;
|
|
}
|
|
else
|
|
{
|
|
// 使用默认路径 | Use default path
|
|
outputPath = defaultOutputPath;
|
|
}
|
|
|
|
// 创建进度条窗口 | Create progress window
|
|
var progressWindow = new ProgressWindow(
|
|
title: "报告生成中",
|
|
message: "正在准备数据...",
|
|
isCancelable: false,
|
|
logger: _logger);
|
|
|
|
progressWindow.Owner = Application.Current.MainWindow;
|
|
progressWindow.Show();
|
|
|
|
try
|
|
{
|
|
// 步骤 1:准备模拟数据 | Step 1: Prepare mock data
|
|
progressWindow.UpdateProgress("正在准备检测数据...", 10);
|
|
await Task.Delay(300); // 模拟耗时 | Simulate delay
|
|
|
|
var processorOutputs = CreateMockProcessorOutputs();
|
|
|
|
// 步骤 2:构建报告请求 | Step 2: Build report request
|
|
progressWindow.UpdateProgress("正在组装报告数据...", 30);
|
|
await Task.Delay(200);
|
|
|
|
var request = new ReportRequest
|
|
{
|
|
ProcessorOutputs = processorOutputs,
|
|
Metadata = new ReportMetadata
|
|
{
|
|
ReportId = fileNameParams["ReportId"],
|
|
InspectionDate = DateTime.Now,
|
|
SampleName = ProductName,
|
|
OperatorName = OperatorName,
|
|
Description = Description
|
|
},
|
|
OutputFilePath = outputPath,
|
|
FileNameParameters = fileNameParams
|
|
};
|
|
|
|
// 注入工件整体图片 | Inject workpiece overview image
|
|
var workpieceImagePath = System.IO.Path.Combine(MockImageDirectory, "OverView.png");
|
|
if (File.Exists(workpieceImagePath))
|
|
{
|
|
request.AdditionalImages["workpieceImage"] = new ImageData
|
|
{
|
|
SourceType = ImageSourceType.FilePath,
|
|
FilePath = workpieceImagePath
|
|
};
|
|
}
|
|
|
|
// 步骤 3:调用报告服务生成(在后台线程执行,避免阻塞 UI)
|
|
// Step 3: Call report service (on background thread to avoid blocking UI)
|
|
progressWindow.UpdateProgress("正在生成 PDF...", 60);
|
|
await Task.Delay(200);
|
|
|
|
var genResult = await Task.Run(() => _reportService.GenerateAsync(request));
|
|
|
|
// 步骤 4:处理结果 | Step 4: Handle result
|
|
progressWindow.UpdateProgress("正在完成...", 95);
|
|
await Task.Delay(200);
|
|
|
|
if (genResult.IsSuccess)
|
|
{
|
|
_lastOutputPath = genResult.OutputFilePath;
|
|
StatusMessage = $"报告生成成功:{genResult.OutputFilePath}";
|
|
_logger.Info("报告生成成功:{Path} | Report generated successfully: {Path}", genResult.OutputFilePath);
|
|
|
|
progressWindow.UpdateProgress("报告生成完成!", 100);
|
|
await Task.Delay(500);
|
|
|
|
// 根据配置自动打开 PDF 阅读器 | Auto-open PDF viewer based on config
|
|
if (_reportConfig.AutoOpenAfterGenerate)
|
|
{
|
|
try
|
|
{
|
|
_pdfViewerService.OpenViewer(genResult.OutputFilePath);
|
|
}
|
|
catch (Exception viewerEx)
|
|
{
|
|
_logger.Warn("自动打开 PDF 失败 | Auto-open PDF failed: {Message}", viewerEx.Message);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StatusMessage = $"报告生成失败:{genResult.ErrorMessage}";
|
|
_logger.Error(null, "报告生成失败:{Message} | Report generation failed: {Message}", genResult.ErrorMessage);
|
|
|
|
MessageBox.Show(
|
|
$"报告生成失败:\n{genResult.ErrorMessage}",
|
|
"错误",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Error);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
progressWindow.Close();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"报告生成异常:{ex.Message}";
|
|
_logger.Error(ex, "报告生成异常 | Report generation exception: {Message}", ex.Message);
|
|
|
|
MessageBox.Show(
|
|
$"报告生成过程中发生异常:\n{ex.Message}",
|
|
"错误",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Error);
|
|
}
|
|
finally
|
|
{
|
|
IsGenerating = false;
|
|
OpenViewerCommand.RaiseCanExecuteChanged();
|
|
PrintReportCommand.RaiseCanExecuteChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 打开 PDF 阅读器 | Open PDF viewer
|
|
/// </summary>
|
|
private void OpenViewer()
|
|
{
|
|
if (string.IsNullOrEmpty(_lastOutputPath) || !File.Exists(_lastOutputPath))
|
|
{
|
|
MessageBox.Show("PDF 文件不存在,请先生成报告。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// 使用 XP.Common PDF 阅读器打开 | Open with XP.Common PDF viewer
|
|
_pdfViewerService.OpenViewer(_lastOutputPath);
|
|
_logger.Info("使用内置 PDF 阅读器打开:{Path} | Opened with built-in PDF viewer: {Path}", _lastOutputPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, "打开 PDF 失败 | Failed to open PDF: {Message}", ex.Message);
|
|
MessageBox.Show($"打开 PDF 失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 打印报告 | Print report
|
|
/// </summary>
|
|
private void PrintReport()
|
|
{
|
|
if (string.IsNullOrEmpty(_lastOutputPath) || !File.Exists(_lastOutputPath))
|
|
{
|
|
MessageBox.Show("PDF 文件不存在,请先生成报告。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var confirmed = _pdfPrintService.PrintWithDialog(_lastOutputPath);
|
|
if (confirmed)
|
|
{
|
|
_logger.Info("报告已发送到打印机:{Path} | Report sent to printer: {Path}", _lastOutputPath);
|
|
StatusMessage = "报告已发送到打印机";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, "打印报告失败 | Failed to print report: {Message}", ex.Message);
|
|
MessageBox.Show($"打印失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
#region 模拟数据 | Mock Data
|
|
|
|
/// <summary>
|
|
/// 模拟图像目录路径 | Mock image directory path
|
|
/// </summary>
|
|
private const string MockImageDirectory = @"D:\XplorePlane\DetectorImages";
|
|
|
|
/// <summary>
|
|
/// 创建模拟处理器输出数据(演示用,覆盖所有检测类型)
|
|
/// Create mock processor outputs (for demo, covers all inspection types)
|
|
/// </summary>
|
|
private List<ProcessorOutput> CreateMockProcessorOutputs()
|
|
{
|
|
return new List<ProcessorOutput>
|
|
{
|
|
CreateLineMeasurementOutput(),
|
|
CreateBgaVoidRateOutput(),
|
|
CreateVoidMeasurementOutput(),
|
|
CreateFillRateOutput()
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建线测量处理器模拟数据 | Create line measurement processor mock data
|
|
/// </summary>
|
|
private ProcessorOutput CreateLineMeasurementOutput()
|
|
{
|
|
return new ProcessorOutput
|
|
{
|
|
ProcessorType = "LineMeasurementProcessor",
|
|
OutputData = new Dictionary<string, object>
|
|
{
|
|
["MeasurementType"] = "TwoPointDistance",
|
|
["Point1"] = "X=125.32, Y=80.15",
|
|
["Point2"] = "X=340.78, Y=80.15",
|
|
["PixelDistance"] = 215.46,
|
|
["ActualDistance"] = 3.256,
|
|
["Unit"] = "mm",
|
|
["Angle"] = 0.0
|
|
},
|
|
AnnotatedImage = LoadMockImage("BGA.png")
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建 BGA 气泡率处理器模拟数据 | Create BGA void rate processor mock data
|
|
/// </summary>
|
|
private ProcessorOutput CreateBgaVoidRateOutput()
|
|
{
|
|
// 生成 64 组 BGA 球模拟数据 | Generate 64 BGA ball mock data
|
|
var bgaBalls = new List<Dictionary<string, object>>();
|
|
var random = new Random(42); // 固定种子确保可重复 | Fixed seed for reproducibility
|
|
var voidLimit = 0.05;
|
|
|
|
for (int i = 1; i <= 64; i++)
|
|
{
|
|
// 大部分合格,少数不合格 | Most pass, a few fail
|
|
double voidRate;
|
|
if (i == 12 || i == 27 || i == 41 || i == 58)
|
|
{
|
|
// 这几个球不合格 | These balls fail
|
|
voidRate = Math.Round(0.05 + random.NextDouble() * 0.03, 4);
|
|
}
|
|
else
|
|
{
|
|
voidRate = Math.Round(random.NextDouble() * 0.045, 4);
|
|
}
|
|
|
|
var area = Math.Round(190.0 + random.NextDouble() * 15.0, 1);
|
|
var classification = voidRate > voidLimit ? "Fail" : "Pass";
|
|
|
|
bgaBalls.Add(new Dictionary<string, object>
|
|
{
|
|
["Index"] = i,
|
|
["VoidRate"] = voidRate,
|
|
["Area"] = area,
|
|
["Classification"] = classification
|
|
});
|
|
}
|
|
|
|
return new ProcessorOutput
|
|
{
|
|
ProcessorType = "BgaVoidRateProcessor",
|
|
OutputData = new Dictionary<string, object>
|
|
{
|
|
["BgaCount"] = 64,
|
|
["VoidRate"] = 0.028,
|
|
["FillRate"] = 0.972,
|
|
["TotalBgaArea"] = 12500.5,
|
|
["TotalVoidArea"] = 350.2,
|
|
["Classification"] = "Pass",
|
|
["VoidLimit"] = 0.05,
|
|
["BgaBalls"] = bgaBalls
|
|
},
|
|
AnnotatedImage = LoadMockImage("BGA.png")
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建空隙测量处理器模拟数据 | Create void measurement processor mock data
|
|
/// </summary>
|
|
private ProcessorOutput CreateVoidMeasurementOutput()
|
|
{
|
|
return new ProcessorOutput
|
|
{
|
|
ProcessorType = "VoidMeasurementProcessor",
|
|
OutputData = new Dictionary<string, object>
|
|
{
|
|
["RoiArea"] = 5000.0,
|
|
["TotalVoidArea"] = 125.8,
|
|
["VoidRate"] = 0.025,
|
|
["VoidLimit"] = 0.05,
|
|
["VoidCount"] = 5,
|
|
["MaxVoidArea"] = 65.2,
|
|
["Classification"] = "Pass",
|
|
["Voids"] = new List<Dictionary<string, object>>
|
|
{
|
|
new() { ["Index"] = 1, ["Area"] = 65.2, ["AreaPercent"] = 1.30, ["CenterX"] = 120.5, ["CenterY"] = 85.3 },
|
|
new() { ["Index"] = 2, ["Area"] = 38.4, ["AreaPercent"] = 0.77, ["CenterX"] = 200.1, ["CenterY"] = 150.8 },
|
|
new() { ["Index"] = 3, ["Area"] = 22.2, ["AreaPercent"] = 0.44, ["CenterX"] = 80.0, ["CenterY"] = 220.5 },
|
|
new() { ["Index"] = 4, ["Area"] = 15.6, ["AreaPercent"] = 0.31, ["CenterX"] = 310.2, ["CenterY"] = 95.7 },
|
|
new() { ["Index"] = 5, ["Area"] = 8.9, ["AreaPercent"] = 0.18, ["CenterX"] = 155.8, ["CenterY"] = 280.1 }
|
|
}
|
|
},
|
|
AnnotatedImage = LoadMockImage("Void.png")
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建通孔填锡率处理器模拟数据 | Create via fill rate processor mock data
|
|
/// </summary>
|
|
private ProcessorOutput CreateFillRateOutput()
|
|
{
|
|
return new ProcessorOutput
|
|
{
|
|
ProcessorType = "FillRateProcessor",
|
|
OutputData = new Dictionary<string, object>
|
|
{
|
|
["FillRate"] = 0.85,
|
|
["VoidRate"] = 0.15,
|
|
["FullDistance"] = 1.60,
|
|
["FillDistance"] = 1.36,
|
|
["THTLimit"] = 0.75,
|
|
["Classification"] = "Pass",
|
|
["E1"] = new Dictionary<string, object>
|
|
{
|
|
["CenterX"] = 256.0, ["CenterY"] = 256.0,
|
|
["SemiAxisA"] = 120.5, ["SemiAxisB"] = 118.2, ["Angle"] = 2.3
|
|
},
|
|
["E2"] = new Dictionary<string, object>
|
|
{
|
|
["CenterX"] = 256.0, ["CenterY"] = 256.0,
|
|
["SemiAxisA"] = 95.8, ["SemiAxisB"] = 93.1, ["Angle"] = 2.3
|
|
},
|
|
["E3"] = new Dictionary<string, object>
|
|
{
|
|
["CenterX"] = 256.0, ["CenterY"] = 256.0,
|
|
["SemiAxisA"] = 70.2, ["SemiAxisB"] = 68.5, ["Angle"] = 1.8
|
|
},
|
|
["E4"] = new Dictionary<string, object>
|
|
{
|
|
["CenterX"] = 256.0, ["CenterY"] = 256.0,
|
|
["SemiAxisA"] = 45.0, ["SemiAxisB"] = 43.7, ["Angle"] = 1.5
|
|
}
|
|
},
|
|
AnnotatedImage = LoadMockImage("Void.png")
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载模拟图像文件 | Load mock image file
|
|
/// 从指定目录加载图像,文件不存在时返回 null
|
|
/// Loads image from specified directory, returns null if file not found
|
|
/// </summary>
|
|
/// <param name="fileName">图像文件名 | Image file name</param>
|
|
/// <returns>图像数据对象或 null | ImageData object or null</returns>
|
|
private ImageData LoadMockImage(string fileName)
|
|
{
|
|
var filePath = System.IO.Path.Combine(MockImageDirectory, fileName);
|
|
if (!File.Exists(filePath))
|
|
{
|
|
_logger.Warn("模拟图像文件不存在:{Path} | Mock image file not found: {Path}", filePath);
|
|
return null;
|
|
}
|
|
|
|
return new ImageData
|
|
{
|
|
SourceType = ImageSourceType.FilePath,
|
|
FilePath = filePath
|
|
};
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|