添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
using MainShell.Log;
|
||||
using MwFramework.AlarmManager;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Alarm
|
||||
{
|
||||
public class AlarmOperate : IAlarmSend, IAlarmResponse<string>
|
||||
{
|
||||
private const string AlarmSourceName = "AlarmOperate";
|
||||
|
||||
private readonly IAlarmManager _alarmManager;
|
||||
|
||||
public AlarmOperate(IAlarmManager alarmManager)
|
||||
{
|
||||
_alarmManager = alarmManager ?? throw new ArgumentNullException(nameof(alarmManager));
|
||||
_alarmManager.CloseBuzzer += () =>
|
||||
{
|
||||
LogManager.LogAlarmEvent(AlarmSourceName, "CloseBuzzer");
|
||||
};
|
||||
_alarmManager.RestBuzzer += () =>
|
||||
{
|
||||
|
||||
};
|
||||
_alarmManager.ClearPLCAlarm += () =>
|
||||
{
|
||||
List<long> unresolvedAlarmIds = _alarmManager.UnresolvedAlarms == null
|
||||
? new List<long>()
|
||||
: _alarmManager.UnresolvedAlarms.Distinct().ToList();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
foreach (long alarmId in unresolvedAlarmIds)
|
||||
{
|
||||
_alarmManager.HandleAlarmSolved(alarmId);
|
||||
}
|
||||
|
||||
LogManager.LogAlarmEvent(
|
||||
AlarmSourceName,
|
||||
string.Format("ClearPLCAlarm resolved {0} alarms", unresolvedAlarmIds.Count));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogAlarmError(AlarmSourceName, "ClearPLCAlarm", ex);
|
||||
throw;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public string Code { private get; set; }
|
||||
|
||||
public void Alert(int alarmID)
|
||||
{
|
||||
Task alertTask = AlertAsync(alarmID);
|
||||
|
||||
if (Application.Current != null &&
|
||||
Application.Current.Dispatcher != null &&
|
||||
Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
alertTask.ContinueWith(task =>
|
||||
{
|
||||
AggregateException ignored = task.Exception;
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
return;
|
||||
}
|
||||
|
||||
alertTask.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public void Alert(int alarmID, string source, string action, string detail = null)
|
||||
{
|
||||
Task alertTask = AlertAsync(alarmID, source, action, detail);
|
||||
|
||||
if (Application.Current != null &&
|
||||
Application.Current.Dispatcher != null &&
|
||||
Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
alertTask.ContinueWith(task =>
|
||||
{
|
||||
AggregateException ignored = task.Exception;
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
return;
|
||||
}
|
||||
|
||||
alertTask.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public async Task AlertAsync(int alarmID)
|
||||
{
|
||||
await AlertInternalAsync(alarmID, AlarmSourceName, "AlertAsync requested").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task AlertAsync(int alarmID, string source, string action, string detail = null)
|
||||
{
|
||||
string alarmSource = string.IsNullOrWhiteSpace(source) ? AlarmSourceName : source;
|
||||
string triggerAction = BuildTriggerAction(action, detail);
|
||||
|
||||
await AlertInternalAsync(alarmID, alarmSource, triggerAction).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task AlertInternalAsync(int alarmID, string source, string action)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.LogAlarmEvent(source, action, alarmID);
|
||||
await _alarmManager.HandleAlarmAsync(alarmID, this, this).ConfigureAwait(false);
|
||||
LogManager.LogAlarmEvent(source, "HandleAlarmAsync completed", alarmID);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogAlarmError(source, "HandleAlarmAsync", ex, alarmID);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildTriggerAction(string action, string detail)
|
||||
{
|
||||
string normalizedAction = string.IsNullOrWhiteSpace(action) ? "AlertAsync requested" : action;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(detail))
|
||||
{
|
||||
return normalizedAction;
|
||||
}
|
||||
|
||||
return string.Format("{0}. Detail={1}", normalizedAction, detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using MainShell.Alarm.ViewModel;
|
||||
using MwFramework.AlarmManager;
|
||||
using Stylet;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Alarm
|
||||
{
|
||||
[AlarmID(begin:10000, end:20011)]
|
||||
public class UserAlarmProduce : AbstractAlarmAsyncProcedure
|
||||
{
|
||||
private readonly IAlarmManager _alarmManager;
|
||||
private readonly IWindowManager _windowManager;
|
||||
|
||||
public UserAlarmProduce(IAlarmManager alarmManager, IWindowManager windowManager)
|
||||
{
|
||||
_alarmManager = alarmManager;
|
||||
_windowManager = windowManager;
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(IAlarmSend inContext = null, IAlarmResponse outContext = null)
|
||||
{
|
||||
var dialogViewModel = new AlarmDialogViewModel
|
||||
{
|
||||
AlarmInfo = AlarmInfo
|
||||
};
|
||||
var resetRequested = false;
|
||||
await Execute.OnUIThreadAsync(() =>
|
||||
{
|
||||
resetRequested = _windowManager.ShowDialog(dialogViewModel) == true;
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
if (resetRequested)
|
||||
{
|
||||
_alarmManager.ClearPLCAlarm?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<Window x:Class="MainShell.Alarm.View.AlarmDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:MainShell.Alarm.View"
|
||||
mc:Ignorable="d"
|
||||
SizeToContent="Height"
|
||||
ResizeMode="CanResizeWithGrip"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Title="报警提示 (Alarm)" Width="650" MinWidth="500" MaxHeight="800">
|
||||
<Window.Resources>
|
||||
<Style TargetType="GroupBox" BasedOn="{StaticResource LeftGroupStyle}"/>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 顶部横幅 -->
|
||||
<RowDefinition Height="*"/>
|
||||
<!-- 内容区域 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 按钮区域 -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部横幅区域 -->
|
||||
<Border Grid.Row="0" Background="#FFF5E5" BorderBrush="#FFCC80" BorderThickness="0,0,0,1" Padding="15,10">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="⚠" Foreground="#E65100" FontSize="22" FontWeight="Bold" Margin="0,0,10,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="系统发生报警,请及时处理" Foreground="#D84315" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Margin="15,10,15,15">
|
||||
<StackPanel>
|
||||
<!-- 报警ID和类型 -->
|
||||
<GroupBox Header="基本信息" Margin="0,0,0,10">
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="10"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="报警 ID:" Style="{StaticResource LabelStyle}" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmID}" Style="{StaticResource ValueStyle}" FontWeight="Bold" Grid.Row="0" Grid.Column="1" TextWrapping="Wrap"/>
|
||||
|
||||
<TextBlock Text="报警类型:" Style="{StaticResource LabelStyle}" Grid.Row="2" Grid.Column="0" VerticalAlignment="Top"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmType}" Style="{StaticResource ValueStyle}" Foreground="#D84315" FontWeight="SemiBold" Grid.Row="2" Grid.Column="1" TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 报警消息 -->
|
||||
<GroupBox Header="报警消息" Margin="0,0,0,10">
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="10"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="中文消息:" Style="{StaticResource LabelStyle}" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmMessage}" Style="{StaticResource ValueStyle}" Grid.Row="0" Grid.Column="1" TextWrapping="Wrap" LineHeight="20"/>
|
||||
|
||||
<TextBlock Text="英文消息:" Style="{StaticResource LabelStyle}" Grid.Row="2" Grid.Column="0" VerticalAlignment="Top"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmMessageEN}" Style="{StaticResource ValueStyle}" Grid.Row="2" Grid.Column="1" TextWrapping="Wrap" Foreground="#555555" LineHeight="20"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 报警原因 -->
|
||||
<GroupBox Header="报警原因" Margin="0,0,0,10">
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="原因描述:" Style="{StaticResource LabelStyle}" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmReason}" Style="{StaticResource ValueStyle}" Grid.Row="0" Grid.Column="1" TextWrapping="Wrap" LineHeight="20"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 解决方案 -->
|
||||
<GroupBox Header="解决方案" Margin="0,0,0,10">
|
||||
<Border Background="#F9FBE7" BorderBrush="#CDDC39" BorderThickness="1" CornerRadius="4" Padding="10">
|
||||
<TextBlock Text="{Binding AlarmInfo.AlarmSolution}" Style="{StaticResource ValueStyle}" TextWrapping="Wrap" Foreground="#33691E" LineHeight="20"/>
|
||||
</Border>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 触发时间 -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,5,0">
|
||||
<TextBlock Text="触发时间:" Style="{StaticResource LabelStyle}" Foreground="#888888" Margin="0,0,5,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding AlarmInfo.TriggerTime, StringFormat='{}{0:yyyy-MM-dd HH:mm:ss}'}" Style="{StaticResource ValueStyle}" Foreground="#888888" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- 底部按钮区域 -->
|
||||
<Border Grid.Row="2" BorderBrush="#E0E0E0" BorderThickness="0,1,0,0" Padding="10,8" Background="#F8F8F8">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="复位报警" Style="{StaticResource CloseButtonStyle}" Width="100" Height="32" Margin="0,0,10,0" Command="{Binding ResetCommand}" Cursor="Hand"/>
|
||||
<Button Content="关闭" Style="{StaticResource CloseButtonStyle}" Width="100" Height="32" Command="{Binding CloseCommand}" Cursor="Hand"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.Alarm.View
|
||||
{
|
||||
/// <summary>
|
||||
/// AlarmDialog.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class AlarmDialogView : Window
|
||||
{
|
||||
public AlarmDialogView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using MainShell.Models;
|
||||
using MaxwellFramework.Core.Common.Command;
|
||||
using MwFramework.AlarmManager;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MainShell.Alarm.ViewModel
|
||||
{
|
||||
public class AlarmDialogViewModel : BaseScreen
|
||||
{
|
||||
public ICommand ResetCommand { get; }
|
||||
public ICommand CloseCommand { get; }
|
||||
|
||||
public AlarmDialogViewModel()
|
||||
{
|
||||
DisplayName = "报警详情";
|
||||
ResetCommand = new DelegateCommand(obj => Reset());
|
||||
CloseCommand = new DelegateCommand(obj => Close());
|
||||
}
|
||||
|
||||
private AlarmInfo _alarmInfo;
|
||||
public AlarmInfo AlarmInfo
|
||||
{
|
||||
get => _alarmInfo;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _alarmInfo, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void Close()
|
||||
{
|
||||
RequestClose(false);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
RequestClose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.config
Normal file
37
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.config
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
|
||||
<section name="templates" type="MwFramework.Controls.PatternTemplate.ConfigModule.TemplateConfigurationSection,MwFramework.Controls.PatternTemplate" />
|
||||
</configSections>
|
||||
<templates parserType="MwFramework.HuaruiMatch.TypeParser" caliperType="MwFramework.HuaruiMatch.CaliperTest" assemblyFile="MwFramework.HuaruiMatch.dll">
|
||||
<template templateName="Shape" templateType="MwFramework.HuaruiMatch.ShapeMatch" assemblyFile="MwFramework.HuaruiMatch.dll"></template>
|
||||
<template templateName="Ncc" templateType="MwFramework.HuaruiMatch.TemplateMatch" assemblyFile="MwFramework.HuaruiMatch.dll"></template>
|
||||
</templates>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
|
||||
|
||||
<appSettings>
|
||||
|
||||
<add key="Demo" value="true" />
|
||||
<!--语言-->
|
||||
<add key="Lang" value="CN" />
|
||||
<add key="SaveLogsWay" value="DataBase"/>
|
||||
<!--Txt 存储路径-->
|
||||
<add key="LogsPath" value="D:\\Logs" />
|
||||
<add key="MachineId" value="" />
|
||||
</appSettings>
|
||||
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
21
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.xaml
Normal file
21
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.xaml
Normal file
@@ -0,0 +1,21 @@
|
||||
<Application x:Class="MainShell.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:MainShell" xmlns:mw="http://www.maxwell-gp.com/"
|
||||
>
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaxwellControl;component/Themes/SkinTouchable.xaml" />
|
||||
<mw:ApplicationLoader>
|
||||
<mw:ApplicationLoader.Bootstrapper>
|
||||
<local:StartBootstrapper/>
|
||||
</mw:ApplicationLoader.Bootstrapper>
|
||||
</mw:ApplicationLoader>
|
||||
|
||||
<ResourceDictionary Source="/Resources/Styles/Styles.xaml"/>
|
||||
<ResourceDictionary Source="/Language/MXJM_CN.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
17
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.xaml.cs
Normal file
17
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/App.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell
|
||||
{
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
171
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/CLAUDE.md
Normal file
171
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/CLAUDE.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# CLAUDE.md
|
||||
|
||||
## 前置指令
|
||||
|
||||
1. **XAML 文件可以直接更改** — 使用 Edit 工具直接修改 `.xaml` 文件
|
||||
2. **CS 文件有 TSM 加密** — `.cs` 文件在本地是加密的,无法直接读取或编辑。需要通过 `git show HEAD:path` 获取内容。但注意:有时最新的 CS 文件还未提交到 git,此时可以让用户直接提供最新的 CS 文件内容
|
||||
3. **所有回复使用中文** — 所有与用户的交流、注释说明等均使用中文
|
||||
|
||||
## PageCalib 目录结构
|
||||
|
||||
PageCalib 是标定页面模块,采用 MVVM 架构,包含 8 个标定子模块。主入口通过 `PageCalibView.xaml` + `PageCalibViewModel.cs` 管理导航。
|
||||
|
||||
### 目录组织
|
||||
|
||||
```
|
||||
PageCalib/
|
||||
├── View/ # 主视图
|
||||
│ ├── PageCalibView.xaml # 主页面,使用 SideMenu 导航
|
||||
│ └── PageCalibView.xaml.cs
|
||||
├── ViewModel/ # 主视图模型
|
||||
│ └── PageCalibViewModel.cs # 管理 8 个标定子模块导航
|
||||
├── HeightMeasure/ # 高度标定模块
|
||||
│ ├── Model/ # HeightBaseSetting, IHeightMeasure, DiastimeterHeightMeasure
|
||||
│ ├── Service/ # HeightMeasureMotionService
|
||||
│ ├── View/ # HeightView.xaml
|
||||
│ └── ViewModel/ # HeightViewModel
|
||||
├── OriginCalib/ # 原点标定模块
|
||||
│ ├── Model/ # OriginCalibSetting
|
||||
│ ├── Service/ # ICalibrationPostProcessor, OriginCalibrationMotionService, CalibrationPostProcessors
|
||||
│ ├── View/ # OriginCalibView.xaml
|
||||
│ └── ViewModel/ # OriginCalibViewModel, OriginCalibModuleViewModel, AvoidanceAxisViewModel, CalibrationAxisViewModel
|
||||
└── AlgorithmCalib/ # 算法标定模块(包含多个子模块)
|
||||
├── Common/ # 公共接口和结果类
|
||||
│ ├── IAlgorithmCalibModule.cs
|
||||
│ ├── AlgorithmCalibResult.cs
|
||||
│ └── CalibrationProgressEventArgs.cs
|
||||
├── Model/ # 参数模型
|
||||
│ ├── AlgorithmCalibModuleNames.cs
|
||||
│ ├── FusionCalibParItem.cs
|
||||
│ ├── RotateCalibParItem.cs
|
||||
│ └── FusionCalib/ # FusionCalibSetting, FusionCalibModuleItem
|
||||
├── Task/ # 标定任务
|
||||
│ ├── RotateFormCalibTask.cs
|
||||
│ └── FusionCalibTask.cs
|
||||
├── View/ # 各子模块视图
|
||||
│ ├── PixRatioCalib/ # 像素比标定
|
||||
│ ├── DistortionCorrectionCalib/ # 畸变校正标定
|
||||
│ ├── RotateCenterCalib/ # 旋转中心标定
|
||||
│ ├── RotateMatixFormCalib/ # 旋转表标定
|
||||
│ ├── MotionCalib/ # 运动系标定
|
||||
│ └── FusionCalib/ # 融合标定(Die/Pad)
|
||||
├── ViewModel/ # 各子模块视图模型
|
||||
│ ├── PixRatioCalib/
|
||||
│ ├── DistortionCorrectionCalib/
|
||||
│ ├── RotateCenterCalib/
|
||||
│ ├── RotateMatixFormCalib/
|
||||
│ ├── MotionCalib/
|
||||
│ └── FusionCalib/
|
||||
└── Service/ # 各子模块服务
|
||||
├── RotateFormCalib/ # RotateMatixFormCalibMotionService, FileService, PostProcessor
|
||||
├── MotionCalib/ # MotionCalibFileService
|
||||
└── FusionCalib/ # FusionCalibMotionService, PostProcessor, FusionAlignProcessor
|
||||
```
|
||||
|
||||
### 标定子模块列表
|
||||
|
||||
| 模块名称 | 中文名 | 主 ViewModel | 说明 |
|
||||
|---------|--------|-------------|------|
|
||||
| HeightMeasure | 高度标定 | HeightViewModel | 测高标定,包含产品和方片高度测量 |
|
||||
| OriginCalib | 原点标定 | OriginCalibViewModel | 原点位置标定 |
|
||||
| PixRatioCalib | 像素比标定 | PixRatioCalibContentsViewModel | 相机像素比例标定 |
|
||||
| DistortionCorrectionCalib | 畸变校准标定 | DistortionCorrectionCalibContentsViewModel | 相机畸变校正 |
|
||||
| MotionCalib | 运动系标定 | MotionCalibContentsViewModel | 运动系统标定 |
|
||||
| RotateCenterCalib | 旋转中心标定 | RotateCenterCalibContentsViewModel | 旋转中心位置标定 |
|
||||
| RotateFormCalib | 旋转表标定 | RotateMatixFormCalibViewModel | 旋转矩阵表标定 |
|
||||
| FusionCalib | 融合标定 | FusionCalibViewModel | Die/Pad 融合标定 |
|
||||
|
||||
### 通用 UI 模式
|
||||
|
||||
算法标定子模块(PixRatio、DistortionCorrection、RotateCenter、MotionCalib、FusionCalib)采用统一的 ContentsView 布局:
|
||||
- 顶部:当前标定名称 + 进度文本
|
||||
- 中间:ContentControl 绑定 ShowScreenVM 显示具体内容
|
||||
- 底部:上一个/下一个导航按钮
|
||||
|
||||
旋转表标定(RotateMatixFormCalib)采用卡片式布局:
|
||||
- 左侧:相机预览
|
||||
- 右侧:模块卡片(避让位置、标定参数、验证参数、进度条、操作按钮)
|
||||
|
||||
## 融合标定需求与实现
|
||||
|
||||
### 轴映射关系
|
||||
|
||||
| 项目 | WS轴(Wafer轴) | PHS轴(Pad轴) |
|
||||
|------|-----------------|----------------|
|
||||
| 旧项目 | X2, Y2 | X1, Y1 |
|
||||
| 新项目 | X2, Y1 | X1, Y2 |
|
||||
|
||||
### 融合标定流程
|
||||
|
||||
#### 1. Die融合标定(ws圆形标定融合)
|
||||
在X1全行程不同位置,标定建立X2,Y1的die融合表,用于对位晶粒。
|
||||
|
||||
**标定方法:**
|
||||
- 在die运动系下(固定X1),移动X2,Y1扫描获取N×N点阵,作为初始位置
|
||||
- 选取X2负限位位置附近设置起始位置,将X1,X2平移相同距离移动到起始位置
|
||||
- 设定标定范围、标定间隔,扫描一系列N×N点阵,保存为die融合位置表
|
||||
|
||||
**验证方法:**
|
||||
- 在die运动系下飞拍任意坐标
|
||||
- 再选取任意X1位置,使用融合位置表计算出任意坐标移动到该X1位置下的X2,Y1坐标
|
||||
- 同时获取到在该X1位置下实际逼近的X2,Y1坐标
|
||||
- 输出即为标定误差,可选择若干位置覆盖测试全行程误差
|
||||
|
||||
#### 2. Pad融合标定(stage拼接融合)
|
||||
在Y1全行程不同位置,建立X1,Y2的pad融合表,用于对位pad。
|
||||
|
||||
**标定方法:**
|
||||
- 在pad运动系下(固定Y1),移动X1,Y2扫描获取N×N点阵,作为初始位置
|
||||
- 选取Y2负限位位置附近设置起始位置,将Y1,Y2平移相同距离移动到起始位置
|
||||
- 设立标定范围、标定间隔,扫描一系列N×N点阵,保存为pad融合位置表
|
||||
|
||||
**验证方法:**
|
||||
- 在pad运动系下飞拍任意坐标
|
||||
- 再选取任意Y1位置,使用融合位置表计算出任意坐标移动到该Y1位置下的X1,Y2坐标
|
||||
- 同时获取到在该Y1位置下实际逼近的X1,Y2坐标
|
||||
- 输出即为标定误差,可选择若干位置覆盖测试全行程误差
|
||||
|
||||
#### 3. 整体对位验证(对位流程)
|
||||
整体对位流程为:
|
||||
1. 飞拍获取die的下相机X2,Y2坐标,X1坐标固定(上相机die运动系X2,Y1),转换为X1,Y1坐标
|
||||
2. Pad定位mark获取X1,Y2坐标,Y1坐标固定(上相机pad运动系X1,Y2),即转化为X1,Y1坐标
|
||||
3. 通过查找die融合表将die X方向对齐pad(此时Y1会产生少许偏移)
|
||||
4. 再根据此时Y1值,将pad Y方向对齐die(X1会产生少许偏移)
|
||||
5. 此时再移动X2跟上X1的移动量(此处直接移动或查表再移动)
|
||||
|
||||
### 新项目融合标定文件结构
|
||||
|
||||
```
|
||||
AlgorithmCalib/
|
||||
├── View/FusionCalib/
|
||||
│ ├── DieFusionCalibView.xaml # Die融合标定视图(标定+验证Tab)
|
||||
│ ├── PadFusionCalibView.xaml # Pad融合标定视图(标定+验证Tab)
|
||||
│ └── FusionAlignVerifyView.xaml # 整体对位验证视图(4步骤流程)
|
||||
├── ViewModel/FusionCalib/
|
||||
│ ├── FusionCalibViewModel.cs # Die/Pad融合标定共用ViewModel
|
||||
│ ├── FusionAlignVerifyViewModel.cs # 整体对位验证ViewModel
|
||||
│ └── FusionMultipleCalibViewModel.cs # 多模块融合标定ViewModel
|
||||
├── Service/FusionCalib/
|
||||
│ ├── FusionCalibMotionService.cs # 融合标定运动服务
|
||||
│ ├── FusionCalibPostProcessor.cs # 融合标定后处理器
|
||||
│ └── FusionAlignProcessor.cs # 对位处理器
|
||||
└── Model/FusionCalib/
|
||||
├── FusionCalibSetting.cs # 融合标定设置
|
||||
└── FusionCalibModuleItem.cs # 融合标定模块参数
|
||||
```
|
||||
|
||||
### 旧项目参考文件
|
||||
|
||||
旧项目融合标定参考文件位于 `AlgorithmCalib/Old_fusionCalib/` 目录:
|
||||
- `oldProjectDetail.xaml` - 旧项目融合标定流程说明
|
||||
- `newProjectVisionDemand.xaml` - 新项目需求说明
|
||||
- `CameraFusionCali02AViewModel.xaml` - 旧项目ViewModel实现(CS内容)
|
||||
- `CameraFusionCalibrationMotion02A.xaml` - 旧项目Motion实现(CS内容)
|
||||
|
||||
### 关键API调用
|
||||
|
||||
旧项目使用的JM1Vision API:
|
||||
- `JM1Manager.Instance.cal_wafer_fusion()` - 计算wafer融合表
|
||||
- `JM1Manager.Instance.get_ws_pos()` - 根据融合表查询WS位置
|
||||
- `JM1Manager.Instance.pos_verify()` - 验证标定精度
|
||||
- `JM1Manager.Instance.Save()` - 保存标定数据
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MainShell.Common.Behaviors
|
||||
{
|
||||
public static class WindowDragMoveBehavior
|
||||
{
|
||||
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
|
||||
"IsEnabled",
|
||||
typeof(bool),
|
||||
typeof(WindowDragMoveBehavior),
|
||||
new PropertyMetadata(false, OnIsEnabledChanged));
|
||||
|
||||
public static bool GetIsEnabled(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(IsEnabledProperty);
|
||||
}
|
||||
|
||||
public static void SetIsEnabled(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(IsEnabledProperty, value);
|
||||
}
|
||||
|
||||
private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var element = d as UIElement;
|
||||
if (element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
element.MouseLeftButtonDown += OnMouseLeftButtonDown;
|
||||
return;
|
||||
}
|
||||
|
||||
element.MouseLeftButtonDown -= OnMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var element = sender as DependencyObject;
|
||||
var window = element != null ? Window.GetWindow(element) : null;
|
||||
if (window == null || e.ButtonState != MouseButtonState.Pressed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
window.DragMove();
|
||||
e.Handled = true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using MainShell.Log;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class CommonUti
|
||||
{
|
||||
public static void RunOnUi(Action action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Application.Current == null || Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
// 同步在当前线程执行
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// 在 UI 线程同步执行
|
||||
Application.Current.Dispatcher.Invoke(action);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MaxwellControl.Controls.MessageBox.Show($"方法执行异常:{ex.ToString()}", icon: MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static Brush BrushFromString(string s)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
return Brushes.Transparent;
|
||||
|
||||
try
|
||||
{
|
||||
var brush = (Brush)new BrushConverter().ConvertFromString(s);
|
||||
return brush ?? Brushes.Transparent;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果解析失败,返回默认颜色(可根据需要改为 Brushes.Black 或抛异常)
|
||||
return Brushes.Transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using MainShell.Resources.CustomControl;
|
||||
|
||||
namespace MainShell.Common.ControlAttribute
|
||||
{
|
||||
public static class ControlBehavior
|
||||
{
|
||||
public static bool GetIsEnable(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(IsEnableProperty);
|
||||
}
|
||||
|
||||
public static void SetIsEnable(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(IsEnableProperty, value);
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for IsEnable. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty IsEnableProperty =
|
||||
DependencyProperty.RegisterAttached("IsEnable", typeof(bool), typeof(ControlBehavior), new PropertyMetadata(true, OnProppertyChanged));
|
||||
|
||||
public static bool GetIsNumericOnly(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(IsNumericOnlyProperty);
|
||||
}
|
||||
|
||||
public static void SetIsNumericOnly(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(IsNumericOnlyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsNumericOnlyProperty =
|
||||
DependencyProperty.RegisterAttached("IsNumericOnly", typeof(bool), typeof(ControlBehavior), new PropertyMetadata(false, OnIsNumericOnlyChanged));
|
||||
|
||||
public static bool GetRouteDieMapMouseWheel(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(RouteDieMapMouseWheelProperty);
|
||||
}
|
||||
|
||||
public static void SetRouteDieMapMouseWheel(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(RouteDieMapMouseWheelProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RouteDieMapMouseWheelProperty =
|
||||
DependencyProperty.RegisterAttached("RouteDieMapMouseWheel", typeof(bool), typeof(ControlBehavior), new PropertyMetadata(false, OnRouteDieMapMouseWheelChanged));
|
||||
|
||||
|
||||
private static void OnProppertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is TabControl tabControl)
|
||||
{
|
||||
if (e.NewValue is bool isenable)
|
||||
{
|
||||
if (isenable)
|
||||
foreach (var item in tabControl.Items)
|
||||
{
|
||||
if (tabControl.ItemContainerGenerator.ContainerFromItem(item) is TabItem tabItem)
|
||||
{
|
||||
tabItem.IsEnabled = isenable;
|
||||
}
|
||||
}
|
||||
else
|
||||
foreach (var item in tabControl.Items)
|
||||
{
|
||||
if (tabControl.ItemContainerGenerator.ContainerFromItem(item) is TabItem tabItem)
|
||||
{
|
||||
if (tabItem.IsSelected)
|
||||
{
|
||||
tabItem.IsEnabled = true;
|
||||
}
|
||||
else
|
||||
tabItem.IsEnabled = isenable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnIsNumericOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (!(d is TextBox textBox))
|
||||
return;
|
||||
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
InputMethod.SetIsInputMethodEnabled(textBox, false);
|
||||
textBox.PreviewTextInput += TextBox_PreviewTextInput;
|
||||
DataObject.AddPastingHandler(textBox, OnTextBoxPaste);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputMethod.SetIsInputMethodEnabled(textBox, true);
|
||||
textBox.PreviewTextInput -= TextBox_PreviewTextInput;
|
||||
DataObject.RemovePastingHandler(textBox, OnTextBoxPaste);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnRouteDieMapMouseWheelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
ScrollViewer scrollViewer = d as ScrollViewer;
|
||||
if (scrollViewer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isEnabled = e.NewValue is bool && (bool)e.NewValue;
|
||||
MouseWheelEventHandler mouseWheelEventHandler = new MouseWheelEventHandler(ScrollViewer_PreviewMouseWheel);
|
||||
if (isEnabled)
|
||||
{
|
||||
scrollViewer.RemoveHandler(UIElement.PreviewMouseWheelEvent, mouseWheelEventHandler);
|
||||
scrollViewer.AddHandler(UIElement.PreviewMouseWheelEvent, mouseWheelEventHandler, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollViewer.RemoveHandler(UIElement.PreviewMouseWheelEvent, mouseWheelEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
ScrollViewer scrollViewer = sender as ScrollViewer;
|
||||
if (scrollViewer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DieMapControl dieMapControl = FindDieMapControl(scrollViewer, e);
|
||||
if (dieMapControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
MouseWheelEventArgs mouseWheelEventArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
|
||||
mouseWheelEventArgs.RoutedEvent = UIElement.MouseWheelEvent;
|
||||
mouseWheelEventArgs.Source = dieMapControl;
|
||||
dieMapControl.RaiseEvent(mouseWheelEventArgs);
|
||||
}
|
||||
|
||||
private static DieMapControl FindDieMapControl(ScrollViewer scrollViewer, MouseWheelEventArgs e)
|
||||
{
|
||||
DependencyObject dependencyObject = e.OriginalSource as DependencyObject;
|
||||
DieMapControl dieMapControl = FindAncestor<DieMapControl>(dependencyObject);
|
||||
if (dieMapControl != null)
|
||||
{
|
||||
return dieMapControl;
|
||||
}
|
||||
|
||||
dependencyObject = Mouse.DirectlyOver as DependencyObject;
|
||||
dieMapControl = FindAncestor<DieMapControl>(dependencyObject);
|
||||
if (dieMapControl != null)
|
||||
{
|
||||
return dieMapControl;
|
||||
}
|
||||
|
||||
IInputElement inputElement = scrollViewer.InputHitTest(e.GetPosition(scrollViewer));
|
||||
dependencyObject = inputElement as DependencyObject;
|
||||
return FindAncestor<DieMapControl>(dependencyObject);
|
||||
}
|
||||
|
||||
private static T FindAncestor<T>(DependencyObject dependencyObject) where T : DependencyObject
|
||||
{
|
||||
while (dependencyObject != null)
|
||||
{
|
||||
T target = dependencyObject as T;
|
||||
if (target != null)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
|
||||
if (parent == null && dependencyObject is FrameworkContentElement)
|
||||
{
|
||||
parent = ((FrameworkContentElement)dependencyObject).Parent;
|
||||
}
|
||||
|
||||
dependencyObject = parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
if (sender is TextBox textBox)
|
||||
{
|
||||
e.Handled = !IsValidNumericText(GetPreviewText(textBox, e.Text));
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnTextBoxPaste(object sender, DataObjectPastingEventArgs e)
|
||||
{
|
||||
if (!(sender is TextBox textBox))
|
||||
return;
|
||||
|
||||
if (!e.DataObject.GetDataPresent(typeof(string)))
|
||||
{
|
||||
e.CancelCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
var pasteText = e.DataObject.GetData(typeof(string)) as string ?? string.Empty;
|
||||
if (!IsValidNumericText(GetPreviewText(textBox, pasteText)))
|
||||
{
|
||||
e.CancelCommand();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPreviewText(TextBox textBox, string newText)
|
||||
{
|
||||
var currentText = textBox.Text ?? string.Empty;
|
||||
if (textBox.SelectionLength > 0)
|
||||
{
|
||||
currentText = currentText.Remove(textBox.SelectionStart, textBox.SelectionLength);
|
||||
}
|
||||
|
||||
return currentText.Insert(textBox.CaretIndex, newText);
|
||||
}
|
||||
|
||||
private static bool IsValidNumericText(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text) || text == "-" || text == "." || text == "-.")
|
||||
return true;
|
||||
|
||||
return double.TryParse(text, out _);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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.Controls;
|
||||
using System.Windows.Input;
|
||||
using MessageBox = MaxwellControl.Controls.MessageBox;
|
||||
|
||||
namespace MainShell.Common.ControlAttribute
|
||||
{
|
||||
public class NumericValidationRule : ValidationRule
|
||||
{
|
||||
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||
{
|
||||
string strValue = value as string;
|
||||
if (string.IsNullOrEmpty(strValue))
|
||||
{
|
||||
// 空值是允许的,如果需要必填,则返回 new ValidationResult(false, "不能为空");
|
||||
return new ValidationResult(false, "不能为空");
|
||||
}
|
||||
|
||||
// 尝试将字符串转换为double
|
||||
if (double.TryParse(strValue, out _))
|
||||
{
|
||||
return ValidationResult.ValidResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ValidationResult(false, "请输入有效的数字。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using MaxwellFramework.Core.Common;
|
||||
using MwFramework.Controls.ControlCanvas.Model;
|
||||
using MwFramework.ManagerService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common.Display.Models
|
||||
{
|
||||
public class CameraAxisDevices : ViewModelBase
|
||||
{
|
||||
List<HardwareDevice> _hardwareDeviceList = new List<HardwareDevice>();
|
||||
HardwareDevice _selectedHardwareDevice = new HardwareDevice();
|
||||
private ObservableCollection<object> _shapes = new ObservableCollection<object>();
|
||||
private int _selectedIndex = 0;
|
||||
private bool _cameraSwitchEnable = true;
|
||||
|
||||
public List<HardwareDevice> HardwareDeviceList
|
||||
{
|
||||
get { return _hardwareDeviceList; }
|
||||
set
|
||||
{
|
||||
if (_hardwareDeviceList == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_hardwareDeviceList = value;
|
||||
|
||||
if (_hardwareDeviceList != null && _hardwareDeviceList.Count > 0)
|
||||
{
|
||||
_selectedIndex = 0;
|
||||
SelectedHardwareDevice = _hardwareDeviceList[_selectedIndex];
|
||||
RaisePropertyChanged(nameof(SelectedIndex));
|
||||
}
|
||||
|
||||
RaisePropertyChanged(nameof(HardwareDeviceList));
|
||||
}
|
||||
}
|
||||
public HardwareDevice SelectedHardwareDevice
|
||||
{
|
||||
get { return _selectedHardwareDevice; }
|
||||
set
|
||||
{
|
||||
if (_selectedHardwareDevice != null && _selectedHardwareDevice.Camera != null && value != null && value.Camera != null)
|
||||
{
|
||||
|
||||
}
|
||||
_selectedHardwareDevice = value; RaisePropertyChanged(nameof(SelectedHardwareDevice));
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<object> Shapes
|
||||
{
|
||||
get { return _shapes; }
|
||||
set
|
||||
{
|
||||
if (_shapes != value) { _shapes = value; RaisePropertyChanged(nameof(Shapes)); }
|
||||
}
|
||||
}
|
||||
private ObservableCollection<PrimShape> _regions = new ObservableCollection<PrimShape>();
|
||||
public ObservableCollection<PrimShape> Regions
|
||||
{
|
||||
get { return _regions; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _regions, value);
|
||||
}
|
||||
}
|
||||
public int SelectedIndex
|
||||
{
|
||||
get { return _selectedIndex; }
|
||||
set
|
||||
{
|
||||
_selectedIndex = value;
|
||||
if (HardwareDeviceList != null && HardwareDeviceList.Count > 0 && _selectedIndex >= 0)
|
||||
{
|
||||
if (_selectedIndex < HardwareDeviceList.Count)
|
||||
{
|
||||
SelectedHardwareDevice = HardwareDeviceList[_selectedIndex];
|
||||
}
|
||||
|
||||
}
|
||||
RaisePropertyChanged(nameof(SelectedIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public bool CameraSwitchEnable
|
||||
{
|
||||
get { return _cameraSwitchEnable; }
|
||||
set { _cameraSwitchEnable = value; RaisePropertyChanged(nameof(CameraSwitchEnable)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="MainShell.Common.Display.View.CameraAxisView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.Common.Display.View"
|
||||
xmlns:control="http://www.maxwell.com/controls"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<CheckBox Panel.ZIndex="2" IsChecked="{Binding IsOpen, UpdateSourceTrigger=PropertyChanged}" Cursor="Hand" Margin="2,2" Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||
<TextBlock Text="移动"/>
|
||||
</CheckBox>
|
||||
<control:CameraAxisControlA Name="cameraAxisControl"
|
||||
IsShowDoubleLine="False"
|
||||
IsAxisControlLDBVisible2="Visible"
|
||||
Cameras="{Binding CameraAxisDevices.HardwareDeviceList}"
|
||||
TabSelectedIndex ="{Binding CameraAxisDevices.SelectedIndex}"
|
||||
Items="{Binding CameraAxisDevices.Shapes,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
|
||||
Regions="{Binding CameraAxisDevices.Regions}" ShapeThickness="1" IsShowSolidLine="True" DrawInConcurrency="False"
|
||||
>
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="RecordPix">
|
||||
<i:InvokeCommandAction Command="{Binding OnLeftMouseDownCommand}" CommandParameter="{Binding ElementName=cameraAxisControl}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</control:CameraAxisControlA>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.Common.Display.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraAxisView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraAxisView : UserControl
|
||||
{
|
||||
public CameraAxisView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<UserControl x:Class="MainShell.Common.Display.View.CameraView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.Common.Display.View"
|
||||
xmlns:mw="http://www.maxwell.com/controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Border BorderThickness="1" BorderBrush ="#B0B9C4">
|
||||
<mw:DesignPanel x:Name="cameraDesignPanel"
|
||||
Source="{Binding DisplayImage}"
|
||||
Items="{Binding Shapes}"
|
||||
IsVirtualPix="Visible"
|
||||
IsShowSolidLine="True"
|
||||
IsCrossingLineVisible="False"
|
||||
IsNonRectCrossingLineVisible="False"
|
||||
IsImagePix="Collapsed" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.Common.Display.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraView : UserControl
|
||||
{
|
||||
public CameraView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.Models;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.Controls.ControlCanvas.Model;
|
||||
using MwFramework.Controls.UIControl;
|
||||
using MwFramework.Device;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using StyletIoC;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MainShell.Common.Display.ViewModel
|
||||
{
|
||||
public class CameraAxisViewModel : Screen
|
||||
{
|
||||
private const double DefaultFovX = 14.1 * 10;
|
||||
private const double DefaultFovY = 10.3 * 10;
|
||||
private const string SafeAxisMotionNotInjectedMessage = "SafeAxisMotion is not injected.";
|
||||
|
||||
private readonly object _moveLock = new object();
|
||||
|
||||
private CameraAxisDevices _cameraAxisDevices = new CameraAxisDevices();
|
||||
private double _xPixelPos;
|
||||
private double _yPixelPos;
|
||||
private double _cameraXIndex;
|
||||
private double _cameraYIndex;
|
||||
private GetConvertValue _convertFunXDelegate;
|
||||
private GetConvertValue _convertFunYDelegate;
|
||||
private ObservableCollection<PrimShape> _regions = new ObservableCollection<PrimShape>();
|
||||
private bool _isCameraEnable = true;
|
||||
private Visibility _controlVisibility = Visibility.Visible;
|
||||
private bool _isOpen;
|
||||
|
||||
[Inject]
|
||||
public SafeAxisMotion SafeAxisMotion { get; set; }
|
||||
|
||||
public CameraAxisViewModel()
|
||||
{
|
||||
ConvertFunXDelegate = new GetConvertValue(ConvertFunX);
|
||||
ConvertFunYDelegate = new GetConvertValue(ConvertFunY);
|
||||
OnLeftMouseDownCommand = new DelegateCommand<object>(OnLeftMouseDown);
|
||||
}
|
||||
|
||||
public CameraAxisDevices CameraAxisDevices
|
||||
{
|
||||
get { return _cameraAxisDevices; }
|
||||
set { SetAndNotify(ref _cameraAxisDevices, value); }
|
||||
}
|
||||
|
||||
public double XPixelPos
|
||||
{
|
||||
get { return _xPixelPos; }
|
||||
set { SetAndNotify(ref _xPixelPos, value); }
|
||||
}
|
||||
|
||||
public double YPixelPos
|
||||
{
|
||||
get { return _yPixelPos; }
|
||||
set { SetAndNotify(ref _yPixelPos, value); }
|
||||
}
|
||||
|
||||
public double CameraXIndex
|
||||
{
|
||||
get { return _cameraXIndex; }
|
||||
set { SetAndNotify(ref _cameraXIndex, value); }
|
||||
}
|
||||
|
||||
public double CameraYIndex
|
||||
{
|
||||
get { return _cameraYIndex; }
|
||||
set { SetAndNotify(ref _cameraYIndex, value); }
|
||||
}
|
||||
|
||||
public GetConvertValue ConvertFunXDelegate
|
||||
{
|
||||
get { return _convertFunXDelegate; }
|
||||
set { SetAndNotify(ref _convertFunXDelegate, value); }
|
||||
}
|
||||
|
||||
public GetConvertValue ConvertFunYDelegate
|
||||
{
|
||||
get { return _convertFunYDelegate; }
|
||||
set { SetAndNotify(ref _convertFunYDelegate, value); }
|
||||
}
|
||||
|
||||
public ObservableCollection<PrimShape> Regions
|
||||
{
|
||||
get { return _regions; }
|
||||
set { SetAndNotify(ref _regions, value); }
|
||||
}
|
||||
|
||||
public bool IsCameraEnable
|
||||
{
|
||||
get { return _isCameraEnable; }
|
||||
set { SetAndNotify(ref _isCameraEnable, value); }
|
||||
}
|
||||
|
||||
public Visibility ControlVisibility
|
||||
{
|
||||
get { return _controlVisibility; }
|
||||
set { SetAndNotify(ref _controlVisibility, value); }
|
||||
}
|
||||
|
||||
public ICommand OnLeftMouseDownCommand { get; private set; }
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get { return _isOpen; }
|
||||
set { SetAndNotify(ref _isOpen, value); }
|
||||
}
|
||||
|
||||
public void OnLeftMouseDown(object sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
HardwareDevice selectedDevice;
|
||||
if (!TryGetSelectedDevice(out selectedDevice))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CameraAxisControlA controlA = sender as CameraAxisControlA;
|
||||
if (controlA == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Point pixelPos = new Point(controlA.YPixPos, controlA.XPixPos);
|
||||
Task.Run(() => MoveToPixelPoint(selectedDevice, pixelPos, false));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogSysError(ex);
|
||||
ShowOperationFailed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void MovePosAction()
|
||||
{
|
||||
try
|
||||
{
|
||||
HardwareDevice selectedDevice;
|
||||
if (!TryGetSelectedDevice(out selectedDevice))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Point pixelPos = new Point(YPixelPos, XPixelPos);
|
||||
Task.Run(() => MoveToPixelPoint(selectedDevice, pixelPos, true));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogSysError(ex);
|
||||
ShowOperationFailed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public double ConvertFunX(double interval)
|
||||
{
|
||||
try
|
||||
{
|
||||
HardwareDevice selectedDevice;
|
||||
if (!TryGetSelectedDevice(out selectedDevice))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
string name = selectedDevice.Camera.Id;
|
||||
double dx;
|
||||
double dy;
|
||||
VisionProcess.Instance.GetCameraResolution(name, out dx, out dy);
|
||||
double pixelX = interval / Math.Abs(dx);
|
||||
return pixelX;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogSysError(ex);
|
||||
ShowOperationFailed(ex.Message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public double ConvertFunY(double interval)
|
||||
{
|
||||
try
|
||||
{
|
||||
HardwareDevice selectedDevice;
|
||||
if (!TryGetSelectedDevice(out selectedDevice))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
string name = selectedDevice.Camera.Id;
|
||||
double dx;
|
||||
double dy;
|
||||
VisionProcess.Instance.GetCameraResolution(name, out dx, out dy);
|
||||
double pixelY = interval / Math.Abs(dy);
|
||||
return pixelY;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogSysError(ex);
|
||||
ShowOperationFailed(ex.Message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetSelectedDevice(out HardwareDevice selectedDevice)
|
||||
{
|
||||
selectedDevice = CameraAxisDevices != null ? CameraAxisDevices.SelectedHardwareDevice : null;
|
||||
if (!IsOpen || selectedDevice == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedDevice.Camera == null || selectedDevice.Camera.Camera == null)
|
||||
{
|
||||
ShowDeviceNotInitialized();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!selectedDevice.Camera.Camera.IsGrabbing)
|
||||
{
|
||||
LocalizedMessageBox.Show(MessageKey.VisionCameraNotGrabbing, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedDevice.AxisX == null || selectedDevice.AxisY == null)
|
||||
{
|
||||
ShowDeviceNotInitialized();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void MoveToPixelPoint(HardwareDevice selectedDevice, Point pixelPos, bool requireConfirmation)
|
||||
{
|
||||
lock (_moveLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
IAxis axisX = selectedDevice.AxisX;
|
||||
IAxis axisY = selectedDevice.AxisY;
|
||||
Point rulerPos = new Point(axisX.State.ActualPos, axisY.State.ActualPos);
|
||||
Point newRulerPoint = Algorithm.Instance.MoveToPixelPoint(selectedDevice.Camera.Id, rulerPos, pixelPos);
|
||||
|
||||
if (requireConfirmation)
|
||||
{
|
||||
double dx = newRulerPoint.X - rulerPos.X;
|
||||
double dy = newRulerPoint.Y - rulerPos.Y;
|
||||
if (!ValidateMoveRange(dx, dy))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ConfirmMove(newRulerPoint))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (SafeAxisMotion == null)
|
||||
{
|
||||
InvalidOperationException exception = new InvalidOperationException(SafeAxisMotionNotInjectedMessage);
|
||||
LogManager.LogSysError(exception);
|
||||
ShowOperationFailed(SafeAxisMotionNotInjectedMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
SafeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(axisX, newRulerPoint.X),
|
||||
MotionMoveRequest.ForAxis(axisY, newRulerPoint.Y));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.LogSysError(ex);
|
||||
ShowOperationFailed(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ValidateMoveRange(double dx, double dy)
|
||||
{
|
||||
if (Math.Abs(dx) > DefaultFovX || Math.Abs(dy) > DefaultFovY)
|
||||
{
|
||||
LocalizedMessageBox.Show(MessageKey.ParamOutOfRange, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ConfirmMove(Point newRulerPoint)
|
||||
{
|
||||
string message = string.Format("新点的坐标({0},{1}),是否移动?", newRulerPoint.X, newRulerPoint.Y);
|
||||
return MwMessageBox.Show(message, LanguageResourceHelper.GetString(MessageKey.TitleConfirm), MessageBoxButton.OKCancel, MessageBoxImage.Question, MessageBoxResult.Cancel) == MessageBoxResult.OK;
|
||||
}
|
||||
|
||||
private static void ShowDeviceNotInitialized()
|
||||
{
|
||||
LocalizedMessageBox.Show(MessageKey.DeviceNotInitialized, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
|
||||
private static void ShowOperationFailed(string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
LocalizedMessageBox.Show(MessageKey.CommonOperationFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
MwMessageBox.Show(message, LanguageResourceHelper.GetString(MessageKey.TitleError), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
using MainShell.EventArgsFolder;
|
||||
using MainShell.Log;
|
||||
using MainShell.Vision;
|
||||
using MwFramework.Device.Model;
|
||||
using MwFramework.Controls.ControlCanvas.DrawingControl;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using AppCameraType = MainShell.Common.CameraType;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell.Common.Display.ViewModel
|
||||
{
|
||||
public class CameraViewModel : Screen, IHandle<DisplayImageEventArgs>, IHandle<DisplayFindTemplateResultEventArgs>
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
public AppCameraType CameraType { get; }
|
||||
|
||||
private WriteableBitmap currentImage;
|
||||
private WriteableBitmap _displayImage;
|
||||
public WriteableBitmap DisplayImage
|
||||
{
|
||||
get { return _displayImage; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _displayImage, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ObservableCollection<object> _shapes = new ObservableCollection<object>();
|
||||
public ObservableCollection<object> Shapes
|
||||
{
|
||||
get { return _shapes; }
|
||||
set
|
||||
{
|
||||
if (_shapes != value) { _shapes = value; OnPropertyChanged(nameof(Shapes)); }
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据 CameraData 更新并返回 WriteableBitmap。
|
||||
/// 优化要点:
|
||||
/// - 重用已有 WriteableBitmap(当尺寸与像素格式相同时)以减少分配。
|
||||
/// - 校验参数与缓冲区长度。
|
||||
/// - 捕获并记录异常,失败时返回 null(不抛出)。
|
||||
/// </summary>
|
||||
public WriteableBitmap UpdateBitmap(CameraData cameraData)
|
||||
{
|
||||
if (cameraData == null)
|
||||
{
|
||||
"图片数据为空".LogSysError();
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int width = (int)cameraData.Width;
|
||||
int height = (int)cameraData.Height;
|
||||
int bitCnt = cameraData.Bit;
|
||||
byte[] buffer = cameraData.BufferData;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
$"CameraViewModel.UpdateBitmap: invalid size {width}x{height}".LogSysError();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 选择像素格式
|
||||
System.Windows.Media.PixelFormat pixelFormat = bitCnt == 1
|
||||
? System.Windows.Media.PixelFormats.Gray8
|
||||
: (bitCnt == 3 ? System.Windows.Media.PixelFormats.Bgr24 : System.Windows.Media.PixelFormats.Bgra32);
|
||||
|
||||
// 计算每行字节数(stride)
|
||||
int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
|
||||
int stride = width * bytesPerPixel;
|
||||
long requiredLength = (long)stride * height;
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
"CameraViewModel.UpdateBitmap: buffer is null".LogSysError();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (buffer.Length < requiredLength)
|
||||
{
|
||||
($"CameraViewModel.UpdateBitmap: buffer length {buffer.Length} is less than required {requiredLength}").LogSysError();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果现有 bitmap 可复用(尺寸和格式一致),就重用以减少 GC/分配
|
||||
if (currentImage == null ||
|
||||
currentImage.PixelWidth != width ||
|
||||
currentImage.PixelHeight != height ||
|
||||
!currentImage.Format.Equals(pixelFormat))
|
||||
{
|
||||
// 新建 WriteableBitmap
|
||||
currentImage = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
|
||||
}
|
||||
|
||||
// 将字节拷贝到 BackBuffer(UI 线程中调用)
|
||||
currentImage.Lock();
|
||||
try
|
||||
{
|
||||
// BackBuffer 为 IntPtr,使用 Marshal.Copy 从 byte[] 拷贝
|
||||
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, currentImage.BackBuffer, (int)requiredLength);
|
||||
currentImage.AddDirtyRect(new Int32Rect(0, 0, width, height));
|
||||
}
|
||||
finally
|
||||
{
|
||||
currentImage.Unlock();
|
||||
}
|
||||
|
||||
return currentImage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
($"CameraViewModel.UpdateBitmap exception: {ex}").LogSysError();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public CameraViewModel(IEventAggregator eventAggregator, AppCameraType cameraType)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
CameraType = cameraType;
|
||||
_eventAggregator?.Subscribe(this);
|
||||
}
|
||||
|
||||
public void Handle(DisplayImageEventArgs message)
|
||||
{
|
||||
if (message == null || message.CameraType != CameraType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommonUti.RunOnUi(() =>
|
||||
{
|
||||
WriteableBitmap bmp = UpdateBitmap(message.CameraData);
|
||||
// 只有在成功生成 bitmap 时才更新 DisplayImage,避免把 null 赋值导致 UI 清空
|
||||
if (bmp != null)
|
||||
{
|
||||
DisplayImage = bmp;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Handle(DisplayFindTemplateResultEventArgs message)
|
||||
{
|
||||
if (message == null || message.CameraType != CameraType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CommonUti.RunOnUi(() =>
|
||||
{
|
||||
ApplyTemplateResultShapes(message);
|
||||
});
|
||||
}
|
||||
|
||||
private void ApplyTemplateResultShapes(DisplayFindTemplateResultEventArgs message)
|
||||
{
|
||||
if (message.ClearShapesBeforeDisplay)
|
||||
{
|
||||
Shapes.Clear();
|
||||
}
|
||||
|
||||
if (message.Result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppendCenterShapes(message.Result);
|
||||
AppendContourShape(message.Result.Contour);
|
||||
AppendCircleShapes(message.Result.Circles);
|
||||
AppendLineShapes(message.Result.Lines);
|
||||
AppendRectangleShapes(message.Result.Rectangles);
|
||||
}
|
||||
|
||||
private void AppendCenterShapes(FindTemplateResult result)
|
||||
{
|
||||
if (result == null || !AreFinite(result.CenterX, result.CenterY, result.Score))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShapeDrawing pointShape = new ShapeDrawing();
|
||||
pointShape.X = result.CenterX;
|
||||
pointShape.Y = result.CenterY;
|
||||
Shapes.Add(pointShape);
|
||||
|
||||
TextShapeDrawing textShape = new TextShapeDrawing();
|
||||
textShape.X = result.CenterX;
|
||||
textShape.Y = result.CenterY;
|
||||
textShape.Text = $"Score:{result.Score:F3}";
|
||||
Shapes.Add(textShape);
|
||||
}
|
||||
|
||||
private void AppendContourShape(FindTemplateContourResult contour)
|
||||
{
|
||||
if (contour == null || !AreFinite(contour.StartX, contour.StartY, contour.EndX, contour.EndY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RectShapeDrawing contourShape = new RectShapeDrawing();
|
||||
contourShape.X = contour.StartX;
|
||||
contourShape.Y = contour.StartY;
|
||||
contourShape.X1 = contour.EndX;
|
||||
contourShape.Y1 = contour.EndY;
|
||||
Shapes.Add(contourShape);
|
||||
}
|
||||
|
||||
private void AppendCircleShapes(IList<FindTemplateCircleResult> circles)
|
||||
{
|
||||
if (circles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (FindTemplateCircleResult circle in circles)
|
||||
{
|
||||
if (circle == null || !AreFinite(circle.CenterX, circle.CenterY, circle.Radius))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CircleShapeDrawing circleShape = new CircleShapeDrawing();
|
||||
circleShape.X = circle.CenterX;
|
||||
circleShape.Y = circle.CenterY;
|
||||
circleShape.CenterPoint = new Point(circle.CenterX, circle.CenterY);
|
||||
circleShape.RadiusX = circle.Radius;
|
||||
circleShape.RadiusY = circle.Radius;
|
||||
circleShape.LineWidth = 1;
|
||||
circleShape.FillColor = Brushes.Blue;
|
||||
Shapes.Add(circleShape);
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLineShapes(IList<FindTemplateLineResult> lines)
|
||||
{
|
||||
if (lines == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (FindTemplateLineResult line in lines)
|
||||
{
|
||||
if (line == null || !AreFinite(line.StartX, line.StartY, line.EndX, line.EndY))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LineShapeDrawing lineShape = new LineShapeDrawing();
|
||||
lineShape.X = line.StartX;
|
||||
lineShape.Y = line.StartY;
|
||||
lineShape.X1 = line.EndX;
|
||||
lineShape.Y1 = line.EndY;
|
||||
Shapes.Add(lineShape);
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendRectangleShapes(IList<FindTemplateRectangleResult> rectangles)
|
||||
{
|
||||
if (rectangles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (FindTemplateRectangleResult rectangle in rectangles)
|
||||
{
|
||||
if (rectangle == null || !AreFinite(rectangle.StartX, rectangle.StartY, rectangle.Width, rectangle.Height, rectangle.Angle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double halfWidth = rectangle.Width / 2d;
|
||||
double halfHeight = rectangle.Height / 2d;
|
||||
double cosAngle = Math.Cos(rectangle.Angle);
|
||||
double sinAngle = Math.Sin(rectangle.Angle);
|
||||
double centerX = rectangle.StartX + (halfWidth * cosAngle) - (halfHeight * sinAngle);
|
||||
double centerY = rectangle.StartY + (halfWidth * sinAngle) + (halfHeight * cosAngle);
|
||||
|
||||
RectShape2Drawing rectangleShape = new RectShape2Drawing();
|
||||
rectangleShape.X = centerX;
|
||||
rectangleShape.Y = centerY;
|
||||
rectangleShape.CenterX = centerX;
|
||||
rectangleShape.CenterY = centerY;
|
||||
rectangleShape.HalfWidth = halfWidth;
|
||||
rectangleShape.HalfHeigth = halfHeight;
|
||||
rectangleShape.Angle = rectangle.Angle;
|
||||
Shapes.Add(rectangleShape);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AreFinite(params double[] values)
|
||||
{
|
||||
if (values == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (double value in values)
|
||||
{
|
||||
if (double.IsNaN(value) || double.IsInfinity(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 一个简单的包装类,在对象被 Dispose 时执行指定的 Action。
|
||||
/// </summary>
|
||||
public class DisposableAction : IDisposable
|
||||
{
|
||||
private readonly Action _action;
|
||||
private bool _isDisposed;
|
||||
|
||||
public DisposableAction(Action action)
|
||||
{
|
||||
_action = action ?? throw new ArgumentNullException(nameof(action));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_action();
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Common/Enums.cs
Normal file
181
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Common/Enums.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public enum MachineMode { Manual, Auto, Maintenance }
|
||||
|
||||
public enum SpeedType
|
||||
{
|
||||
[Description("低速")]
|
||||
Low,
|
||||
[Description("中速")]
|
||||
Medium,
|
||||
[Description("高速")]
|
||||
High
|
||||
}
|
||||
|
||||
public enum DieTransferRowTraversalStrategy
|
||||
{
|
||||
[Description("全部正向")]
|
||||
AllPositive = 0,
|
||||
|
||||
[Description("全部反向")]
|
||||
AllNegative = 1,
|
||||
|
||||
[Description("蛇形")]
|
||||
Serpentine = 2
|
||||
}
|
||||
public enum BondingPathMode
|
||||
{
|
||||
S形打件 = 1,
|
||||
Z形正向打件,
|
||||
Z形反向打件,
|
||||
}
|
||||
|
||||
public enum BondingStagePathMode
|
||||
{
|
||||
S型区域打件 = 1,
|
||||
Stage正向区域打件,
|
||||
Stage负向区域打件,
|
||||
}
|
||||
|
||||
public enum BondingWSPathMode
|
||||
{
|
||||
S型打件 = 1,
|
||||
WS正向区域打件,
|
||||
WS负向区域打件,
|
||||
}
|
||||
|
||||
public enum RunningMode
|
||||
{
|
||||
生产检测 = 1,
|
||||
老化测试,
|
||||
|
||||
}
|
||||
|
||||
public enum CameraType
|
||||
{
|
||||
TopPositionCamera,
|
||||
TopWsCamera,
|
||||
TopWideCamera,
|
||||
TopWideWsCamera,
|
||||
MapCamera
|
||||
}
|
||||
|
||||
public enum TransPathType
|
||||
{
|
||||
[Description("就近")]
|
||||
Nearest,
|
||||
[Description("顺序")]
|
||||
Sequence,
|
||||
}
|
||||
|
||||
public enum TransPathDirection
|
||||
{
|
||||
[Description("正向")]
|
||||
Positive,
|
||||
[Description("反向")]
|
||||
Negative,
|
||||
}
|
||||
|
||||
public enum DieState
|
||||
{
|
||||
[Description("可使用")]
|
||||
Available,
|
||||
[Description("已使用")]
|
||||
Used,
|
||||
[Description("错误")]
|
||||
Error,
|
||||
[Description("不存在")]
|
||||
NotExist,
|
||||
[Description("当前")]
|
||||
Current,
|
||||
[Description("目标")]
|
||||
Target
|
||||
}
|
||||
|
||||
public enum ProcessExecutionStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
Running,
|
||||
Paused,
|
||||
Canceled,
|
||||
Faulted,
|
||||
Completed
|
||||
}
|
||||
|
||||
public enum FlowDisplayStage
|
||||
{
|
||||
Load = 0,
|
||||
Align = 1,
|
||||
Bond = 2,
|
||||
Inspect = 3,
|
||||
Unload = 4
|
||||
}
|
||||
|
||||
public enum WaferScanMode
|
||||
{
|
||||
[Description("按需扫描")]
|
||||
ScanOnDemand,
|
||||
|
||||
[Description("全扫")]
|
||||
FullScan,
|
||||
}
|
||||
|
||||
public enum BondingSection
|
||||
{
|
||||
/// <summary>
|
||||
/// A区
|
||||
/// </summary>
|
||||
A,
|
||||
/// <summary>
|
||||
/// B区
|
||||
/// </summary>
|
||||
B
|
||||
}
|
||||
|
||||
public enum ComSupMotionType
|
||||
{
|
||||
/// <summary>
|
||||
/// 干涉写入
|
||||
/// </summary>
|
||||
Interfere = 102,
|
||||
/// <summary>
|
||||
/// 回零写入
|
||||
/// </summary>
|
||||
Home = 103,
|
||||
/// <summary>
|
||||
/// 快打执行
|
||||
/// </summary>
|
||||
FastBonding = 200,
|
||||
/// <summary>
|
||||
/// 慢打执行
|
||||
/// </summary>
|
||||
SlowBonding = 201,
|
||||
/// <summary>
|
||||
/// 报警清楚
|
||||
/// </summary>
|
||||
AlarmClear = 104,
|
||||
/// <summary>
|
||||
/// 切PID指定
|
||||
/// </summary>
|
||||
ChangePid = 301,
|
||||
/// <summary>
|
||||
/// 触发报警
|
||||
/// </summary>
|
||||
OccurAlarm = 105,
|
||||
/// <summary>
|
||||
/// 同步PID参数
|
||||
/// </summary>
|
||||
SyncPIDParam = 106,
|
||||
/// <summary>
|
||||
/// 手动设置刺针次数
|
||||
/// </summary>
|
||||
NeedleWorkCount = 302,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common.Extension
|
||||
{
|
||||
public static class DeviceExtension
|
||||
{
|
||||
private static readonly int _taskNum = 3;
|
||||
public static void GetLastSamples(this IDiastimeter diastimeter, out double distance)
|
||||
{
|
||||
var doubles = new List<double>();
|
||||
for (int i = 0; i < _taskNum; i++)
|
||||
{
|
||||
diastimeter.GetLastSample(out double val);
|
||||
if (val != double.NaN)
|
||||
doubles.Add(val);
|
||||
}
|
||||
distance = doubles.Average();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class FocusedEditorCommitHelper
|
||||
{
|
||||
public static void CommitFocusedEditorChanges()
|
||||
{
|
||||
var focusedElement = Keyboard.FocusedElement as DependencyObject;
|
||||
if (focusedElement == null)
|
||||
return;
|
||||
|
||||
CommitBinding(focusedElement);
|
||||
|
||||
var dataGrid = FindAncestor<DataGrid>(focusedElement);
|
||||
if (dataGrid != null)
|
||||
{
|
||||
dataGrid.CommitEdit(DataGridEditingUnit.Cell, true);
|
||||
dataGrid.CommitEdit(DataGridEditingUnit.Row, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CommitBinding(DependencyObject dependencyObject)
|
||||
{
|
||||
if (dependencyObject is TextBox textBox)
|
||||
{
|
||||
textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dependencyObject is ComboBox comboBox)
|
||||
{
|
||||
comboBox.GetBindingExpression(Selector.SelectedItemProperty)?.UpdateSource();
|
||||
comboBox.GetBindingExpression(ComboBox.TextProperty)?.UpdateSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dependencyObject is ToggleButton toggleButton)
|
||||
{
|
||||
toggleButton.GetBindingExpression(ToggleButton.IsCheckedProperty)?.UpdateSource();
|
||||
}
|
||||
}
|
||||
|
||||
private static T FindAncestor<T>(DependencyObject dependencyObject) where T : DependencyObject
|
||||
{
|
||||
var current = dependencyObject;
|
||||
while (current != null)
|
||||
{
|
||||
if (current is T target)
|
||||
return target;
|
||||
|
||||
current = GetParent(current);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static DependencyObject GetParent(DependencyObject dependencyObject)
|
||||
{
|
||||
if (dependencyObject is FrameworkElement frameworkElement)
|
||||
{
|
||||
return frameworkElement.Parent ?? VisualTreeHelper.GetParent(frameworkElement);
|
||||
}
|
||||
|
||||
if (dependencyObject is FrameworkContentElement frameworkContentElement)
|
||||
{
|
||||
return frameworkContentElement.Parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
using MainShell.Resources.CustomControl;
|
||||
using MaxwellFramework.Core.Events;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public class HeaderDeviceStatusController : PropertyChangedBase, IHandle<MainViewSelectedPageChangeEvent>
|
||||
{
|
||||
private enum HeaderDeviceStatusTone
|
||||
{
|
||||
Auto,
|
||||
Manual,
|
||||
Maintenance,
|
||||
Recipe,
|
||||
Settings,
|
||||
Calibration,
|
||||
Unknown
|
||||
}
|
||||
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private bool _hasLoadingStarted;
|
||||
private bool _isVisible;
|
||||
private string _labelText = string.Empty;
|
||||
private string _statusText = string.Empty;
|
||||
private Brush _badgeBackgroundBrush;
|
||||
private Brush _badgeBorderBrush;
|
||||
private Brush _labelForegroundBrush;
|
||||
private Brush _statusForegroundBrush;
|
||||
private Brush _indicatorBrush;
|
||||
|
||||
public HeaderDeviceStatusController(IEventAggregator eventAggregator)
|
||||
{
|
||||
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
||||
|
||||
_eventAggregator.Subscribe(this);
|
||||
LoadingService.Instance.PropertyChanged += OnLoadingServicePropertyChanged;
|
||||
UpdateStatusText("Home");
|
||||
IsVisible = false;
|
||||
}
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isVisible;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _isVisible, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string LabelText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _labelText;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _labelText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string StatusText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _statusText;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _statusText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush BadgeBackgroundBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _badgeBackgroundBrush;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _badgeBackgroundBrush, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush BadgeBorderBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _badgeBorderBrush;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _badgeBorderBrush, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush LabelForegroundBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _labelForegroundBrush;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _labelForegroundBrush, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush StatusForegroundBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _statusForegroundBrush;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _statusForegroundBrush, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush IndicatorBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _indicatorBrush;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _indicatorBrush, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(MainViewSelectedPageChangeEvent message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStatusText(message.SelectePageName);
|
||||
if (!LoadingService.Instance.IsBusy)
|
||||
{
|
||||
IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoadingServicePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!string.Equals(e.PropertyName, nameof(LoadingService.IsBusy), StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (LoadingService.Instance.IsBusy)
|
||||
{
|
||||
_hasLoadingStarted = true;
|
||||
IsVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hasLoadingStarted)
|
||||
{
|
||||
IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatusText(string pageName)
|
||||
{
|
||||
string resourceKey;
|
||||
HeaderDeviceStatusTone tone;
|
||||
|
||||
ResolveStatusDefinition(pageName, out resourceKey, out tone);
|
||||
|
||||
LabelText = GetResourceText("HeaderDeviceStatusLabel", "<22><>ǰ״̬:");
|
||||
StatusText = GetResourceText(resourceKey, GetFallbackStatusText(tone));
|
||||
ApplyTone(tone);
|
||||
}
|
||||
|
||||
private static void ResolveStatusDefinition(string pageName, out string resourceKey, out HeaderDeviceStatusTone tone)
|
||||
{
|
||||
if (string.Equals(pageName, "Home", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeAuto";
|
||||
tone = HeaderDeviceStatusTone.Auto;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(pageName, "ManualOperate", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeManual";
|
||||
tone = HeaderDeviceStatusTone.Manual;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(pageName, "MenuDeviceMaint", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeMaintenance";
|
||||
tone = HeaderDeviceStatusTone.Maintenance;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(pageName, "Recipe", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeRecipe";
|
||||
tone = HeaderDeviceStatusTone.Recipe;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(pageName, "PageSettings", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeSettings";
|
||||
tone = HeaderDeviceStatusTone.Settings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(pageName, "PageCalib", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceKey = "HeaderDeviceModeCalibration";
|
||||
tone = HeaderDeviceStatusTone.Calibration;
|
||||
return;
|
||||
}
|
||||
|
||||
resourceKey = "HeaderDeviceModeUnknown";
|
||||
tone = HeaderDeviceStatusTone.Unknown;
|
||||
}
|
||||
|
||||
private static string GetFallbackStatusText(HeaderDeviceStatusTone tone)
|
||||
{
|
||||
switch (tone)
|
||||
{
|
||||
case HeaderDeviceStatusTone.Auto:
|
||||
return "<22>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD> (AUTO)";
|
||||
|
||||
case HeaderDeviceStatusTone.Manual:
|
||||
return "<22>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD> (MANUAL)";
|
||||
|
||||
case HeaderDeviceStatusTone.Maintenance:
|
||||
return "<22>豸ά<E8B1B8><CEAC> (MAINT)";
|
||||
|
||||
case HeaderDeviceStatusTone.Recipe:
|
||||
return "<22>䷽<EFBFBD>༭ (RECIPE)";
|
||||
|
||||
case HeaderDeviceStatusTone.Settings:
|
||||
return "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (SETUP)";
|
||||
|
||||
case HeaderDeviceStatusTone.Calibration:
|
||||
return "<22>궨У (CALIB)";
|
||||
|
||||
default:
|
||||
return "״̬<D7B4><CCAC><EFBFBD><EFBFBD> (PENDING)";
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTone(HeaderDeviceStatusTone tone)
|
||||
{
|
||||
BadgeBackgroundBrush = CreateBackgroundBrush(tone);
|
||||
BadgeBorderBrush = CreateBorderBrush(tone);
|
||||
LabelForegroundBrush = CreateSolidBrush(198, 221, 255);
|
||||
StatusForegroundBrush = Brushes.White;
|
||||
IndicatorBrush = CreateIndicatorBrush(tone);
|
||||
}
|
||||
|
||||
private static Brush CreateBackgroundBrush(HeaderDeviceStatusTone tone)
|
||||
{
|
||||
switch (tone)
|
||||
{
|
||||
case HeaderDeviceStatusTone.Auto:
|
||||
return CreateGradientBrush(Color.FromRgb(42, 111, 84), Color.FromRgb(24, 79, 60));
|
||||
|
||||
case HeaderDeviceStatusTone.Manual:
|
||||
return CreateGradientBrush(Color.FromRgb(148, 103, 37), Color.FromRgb(104, 72, 24));
|
||||
|
||||
case HeaderDeviceStatusTone.Maintenance:
|
||||
return CreateGradientBrush(Color.FromRgb(46, 104, 164), Color.FromRgb(31, 74, 125));
|
||||
|
||||
case HeaderDeviceStatusTone.Recipe:
|
||||
return CreateGradientBrush(Color.FromRgb(95, 76, 153), Color.FromRgb(68, 54, 111));
|
||||
|
||||
case HeaderDeviceStatusTone.Settings:
|
||||
return CreateGradientBrush(Color.FromRgb(88, 103, 124), Color.FromRgb(62, 74, 92));
|
||||
|
||||
case HeaderDeviceStatusTone.Calibration:
|
||||
return CreateGradientBrush(Color.FromRgb(34, 124, 141), Color.FromRgb(23, 90, 102));
|
||||
|
||||
default:
|
||||
return CreateGradientBrush(Color.FromRgb(50, 102, 177), Color.FromRgb(35, 78, 140));
|
||||
}
|
||||
}
|
||||
|
||||
private static Brush CreateBorderBrush(HeaderDeviceStatusTone tone)
|
||||
{
|
||||
switch (tone)
|
||||
{
|
||||
case HeaderDeviceStatusTone.Auto:
|
||||
return CreateSolidBrush(94, 169, 128);
|
||||
|
||||
case HeaderDeviceStatusTone.Manual:
|
||||
return CreateSolidBrush(201, 151, 76);
|
||||
|
||||
case HeaderDeviceStatusTone.Maintenance:
|
||||
return CreateSolidBrush(94, 148, 206);
|
||||
|
||||
case HeaderDeviceStatusTone.Recipe:
|
||||
return CreateSolidBrush(130, 112, 192);
|
||||
|
||||
case HeaderDeviceStatusTone.Settings:
|
||||
return CreateSolidBrush(126, 143, 166);
|
||||
|
||||
case HeaderDeviceStatusTone.Calibration:
|
||||
return CreateSolidBrush(79, 170, 187);
|
||||
|
||||
default:
|
||||
return CreateSolidBrush(96, 145, 214);
|
||||
}
|
||||
}
|
||||
|
||||
private static Brush CreateIndicatorBrush(HeaderDeviceStatusTone tone)
|
||||
{
|
||||
switch (tone)
|
||||
{
|
||||
case HeaderDeviceStatusTone.Auto:
|
||||
return CreateSolidBrush(63, 227, 123);
|
||||
|
||||
case HeaderDeviceStatusTone.Manual:
|
||||
return CreateSolidBrush(255, 183, 66);
|
||||
|
||||
case HeaderDeviceStatusTone.Maintenance:
|
||||
return CreateSolidBrush(72, 196, 255);
|
||||
|
||||
case HeaderDeviceStatusTone.Recipe:
|
||||
return CreateSolidBrush(173, 121, 255);
|
||||
|
||||
case HeaderDeviceStatusTone.Settings:
|
||||
return CreateSolidBrush(158, 172, 196);
|
||||
|
||||
case HeaderDeviceStatusTone.Calibration:
|
||||
return CreateSolidBrush(70, 231, 219);
|
||||
|
||||
default:
|
||||
return CreateSolidBrush(255, 93, 93);
|
||||
}
|
||||
}
|
||||
|
||||
private static Brush CreateSolidBrush(byte red, byte green, byte blue)
|
||||
{
|
||||
return new SolidColorBrush(Color.FromRgb(red, green, blue));
|
||||
}
|
||||
|
||||
private static Brush CreateGradientBrush(Color startColor, Color endColor)
|
||||
{
|
||||
return new LinearGradientBrush(startColor, endColor, 0.0);
|
||||
}
|
||||
|
||||
private static string GetResourceText(string resourceKey, string fallback)
|
||||
{
|
||||
Application application = Application.Current;
|
||||
if (application == null)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
object resource = application.TryFindResource(resourceKey);
|
||||
string text = resource as string;
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,607 @@
|
||||
using MainShell.Resources.CustomControl;
|
||||
using Newtonsoft.Json;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class HeaderDeviceStatusOverlayHost
|
||||
{
|
||||
private static readonly object OverlayRootTag = new object();
|
||||
private static readonly HeaderDeviceStatusOverlaySettings OverlaySettings = new HeaderDeviceStatusOverlaySettings();
|
||||
|
||||
public static void Attach(Window window, HeaderDeviceStatusController controller)
|
||||
{
|
||||
if (window == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
}
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(controller));
|
||||
}
|
||||
|
||||
window.Dispatcher.BeginInvoke(
|
||||
DispatcherPriority.Loaded,
|
||||
new Action(() => AttachCore(window, controller)));
|
||||
}
|
||||
|
||||
private static void AttachCore(Window window, HeaderDeviceStatusController controller)
|
||||
{
|
||||
Grid existingOverlayRoot = window.Content as Grid;
|
||||
if (existingOverlayRoot != null && ReferenceEquals(existingOverlayRoot.Tag, OverlayRootTag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UIElement currentContent = window.Content as UIElement;
|
||||
if (currentContent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Grid overlayRoot = new Grid();
|
||||
overlayRoot.Tag = OverlayRootTag;
|
||||
|
||||
window.Content = null;
|
||||
overlayRoot.Children.Add(currentContent);
|
||||
overlayRoot.Children.Add(CreateOverlayElement(controller));
|
||||
overlayRoot.Children.Add(CreateDebugPanelElement());
|
||||
window.Content = overlayRoot;
|
||||
}
|
||||
|
||||
private static FrameworkElement CreateOverlayElement(HeaderDeviceStatusController controller)
|
||||
{
|
||||
HeaderDeviceStatusView statusView = new HeaderDeviceStatusView();
|
||||
statusView.DataContext = controller;
|
||||
statusView.IsHitTestVisible = false;
|
||||
statusView.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
statusView.VerticalAlignment = VerticalAlignment.Top;
|
||||
|
||||
Binding marginBinding = new Binding(nameof(HeaderDeviceStatusOverlaySettings.Margin));
|
||||
marginBinding.Source = OverlaySettings;
|
||||
BindingOperations.SetBinding(statusView, FrameworkElement.MarginProperty, marginBinding);
|
||||
|
||||
Panel.SetZIndex(statusView, short.MaxValue);
|
||||
return statusView;
|
||||
}
|
||||
|
||||
private static FrameworkElement CreateDebugPanelElement()
|
||||
{
|
||||
Border panelBorder = new Border();
|
||||
panelBorder.Background = new SolidColorBrush(Color.FromArgb(235, 18, 26, 35));
|
||||
panelBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(72, 93, 118));
|
||||
panelBorder.BorderThickness = new Thickness(1.0);
|
||||
panelBorder.CornerRadius = new CornerRadius(6.0);
|
||||
panelBorder.Padding = new Thickness(10.0, 8.0, 10.0, 8.0);
|
||||
panelBorder.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
panelBorder.VerticalAlignment = VerticalAlignment.Top;
|
||||
|
||||
Binding panelMarginBinding = new Binding(nameof(HeaderDeviceStatusOverlaySettings.DebugPanelMargin));
|
||||
panelMarginBinding.Source = OverlaySettings;
|
||||
BindingOperations.SetBinding(panelBorder, FrameworkElement.MarginProperty, panelMarginBinding);
|
||||
|
||||
Binding panelVisibilityBinding = new Binding(nameof(HeaderDeviceStatusOverlaySettings.IsDebugPanelVisible));
|
||||
panelVisibilityBinding.Source = OverlaySettings;
|
||||
panelVisibilityBinding.Converter = new BooleanToVisibilityConverter();
|
||||
BindingOperations.SetBinding(panelBorder, UIElement.VisibilityProperty, panelVisibilityBinding);
|
||||
|
||||
StackPanel rootPanel = new StackPanel();
|
||||
rootPanel.Orientation = Orientation.Vertical;
|
||||
|
||||
DockPanel headerPanel = new DockPanel();
|
||||
|
||||
TextBlock titleText = new TextBlock();
|
||||
titleText.Text = "Overlay Debug";
|
||||
titleText.Foreground = Brushes.White;
|
||||
titleText.FontSize = 13.0;
|
||||
titleText.FontWeight = FontWeights.SemiBold;
|
||||
titleText.Margin = new Thickness(0.0, 0.0, 8.0, 6.0);
|
||||
DockPanel.SetDock(titleText, Dock.Left);
|
||||
headerPanel.Children.Add(titleText);
|
||||
|
||||
Button closeButton = CreateDebugButton("<22><><EFBFBD><EFBFBD>", 44.0);
|
||||
closeButton.Margin = new Thickness(6.0, 0.0, 0.0, 6.0);
|
||||
closeButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.HideDebugPanel();
|
||||
};
|
||||
DockPanel.SetDock(closeButton, Dock.Right);
|
||||
headerPanel.Children.Add(closeButton);
|
||||
|
||||
rootPanel.Children.Add(headerPanel);
|
||||
|
||||
TextBlock summaryText = new TextBlock();
|
||||
summaryText.Foreground = new SolidColorBrush(Color.FromRgb(210, 221, 236));
|
||||
summaryText.FontSize = 12.0;
|
||||
summaryText.Margin = new Thickness(0.0, 0.0, 0.0, 8.0);
|
||||
Binding summaryBinding = new Binding(nameof(HeaderDeviceStatusOverlaySettings.PositionSummary));
|
||||
summaryBinding.Source = OverlaySettings;
|
||||
BindingOperations.SetBinding(summaryText, TextBlock.TextProperty, summaryBinding);
|
||||
rootPanel.Children.Add(summaryText);
|
||||
|
||||
rootPanel.Children.Add(CreateDebugInputRow("Left", nameof(HeaderDeviceStatusOverlaySettings.LeftMarginText)));
|
||||
rootPanel.Children.Add(CreateDebugInputRow("Top", nameof(HeaderDeviceStatusOverlaySettings.TopMarginText)));
|
||||
rootPanel.Children.Add(CreateDebugInputRow("Step", nameof(HeaderDeviceStatusOverlaySettings.StepText)));
|
||||
|
||||
UniformGrid actionGrid = new UniformGrid();
|
||||
actionGrid.Columns = 4;
|
||||
actionGrid.Rows = 1;
|
||||
actionGrid.Margin = new Thickness(0.0, 0.0, 0.0, 8.0);
|
||||
|
||||
Button leftButton = CreateDebugButton("<22><>", 40.0);
|
||||
leftButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.AdjustMargin(-OverlaySettings.Step, 0.0);
|
||||
};
|
||||
actionGrid.Children.Add(leftButton);
|
||||
|
||||
Button rightButton = CreateDebugButton("<22><>", 40.0);
|
||||
rightButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.AdjustMargin(OverlaySettings.Step, 0.0);
|
||||
};
|
||||
actionGrid.Children.Add(rightButton);
|
||||
|
||||
Button upButton = CreateDebugButton("<22><>", 40.0);
|
||||
upButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.AdjustMargin(0.0, -OverlaySettings.Step);
|
||||
};
|
||||
actionGrid.Children.Add(upButton);
|
||||
|
||||
Button downButton = CreateDebugButton("<22><>", 40.0);
|
||||
downButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.AdjustMargin(0.0, OverlaySettings.Step);
|
||||
};
|
||||
actionGrid.Children.Add(downButton);
|
||||
|
||||
rootPanel.Children.Add(actionGrid);
|
||||
|
||||
Button applyButton = CreateDebugButton("Ӧ<><D3A6>", 0.0);
|
||||
applyButton.Width = 178.0;
|
||||
applyButton.Margin = new Thickness(0.0, 0.0, 0.0, 0.0);
|
||||
applyButton.Click += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.ApplyTextValues();
|
||||
};
|
||||
rootPanel.Children.Add(applyButton);
|
||||
|
||||
panelBorder.Child = rootPanel;
|
||||
Panel.SetZIndex(panelBorder, short.MaxValue);
|
||||
return panelBorder;
|
||||
}
|
||||
|
||||
private static FrameworkElement CreateDebugInputRow(string labelText, string bindingPath)
|
||||
{
|
||||
Grid rowGrid = new Grid();
|
||||
rowGrid.Margin = new Thickness(0.0, 0.0, 0.0, 6.0);
|
||||
rowGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(44.0) });
|
||||
rowGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(92.0) });
|
||||
rowGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(56.0) });
|
||||
|
||||
TextBlock label = new TextBlock();
|
||||
label.Text = labelText;
|
||||
label.Foreground = new SolidColorBrush(Color.FromRgb(210, 221, 236));
|
||||
label.FontSize = 12.0;
|
||||
label.VerticalAlignment = VerticalAlignment.Center;
|
||||
Grid.SetColumn(label, 0);
|
||||
rowGrid.Children.Add(label);
|
||||
|
||||
TextBox inputBox = CreateDebugTextBox(bindingPath);
|
||||
Grid.SetColumn(inputBox, 1);
|
||||
rowGrid.Children.Add(inputBox);
|
||||
|
||||
TextBlock hint = new TextBlock();
|
||||
hint.Text = "<22>س<EFBFBD>";
|
||||
hint.Foreground = new SolidColorBrush(Color.FromRgb(150, 167, 188));
|
||||
hint.FontSize = 11.0;
|
||||
hint.VerticalAlignment = VerticalAlignment.Center;
|
||||
hint.HorizontalAlignment = HorizontalAlignment.Right;
|
||||
Grid.SetColumn(hint, 2);
|
||||
rowGrid.Children.Add(hint);
|
||||
|
||||
return rowGrid;
|
||||
}
|
||||
|
||||
private static TextBox CreateDebugTextBox(string bindingPath)
|
||||
{
|
||||
TextBox inputBox = new TextBox();
|
||||
inputBox.Height = 26.0;
|
||||
inputBox.Margin = new Thickness(0.0);
|
||||
inputBox.Padding = new Thickness(6.0, 2.0, 6.0, 2.0);
|
||||
inputBox.Background = new SolidColorBrush(Color.FromRgb(33, 46, 60));
|
||||
inputBox.BorderBrush = new SolidColorBrush(Color.FromRgb(96, 122, 149));
|
||||
inputBox.Foreground = Brushes.White;
|
||||
inputBox.FontSize = 12.0;
|
||||
inputBox.VerticalContentAlignment = VerticalAlignment.Center;
|
||||
|
||||
Binding textBinding = new Binding(bindingPath);
|
||||
textBinding.Source = OverlaySettings;
|
||||
textBinding.Mode = BindingMode.TwoWay;
|
||||
textBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
|
||||
BindingOperations.SetBinding(inputBox, TextBox.TextProperty, textBinding);
|
||||
|
||||
inputBox.LostFocus += delegate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OverlaySettings.ApplyTextValues();
|
||||
};
|
||||
inputBox.KeyDown += delegate(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key != Key.Enter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OverlaySettings.ApplyTextValues();
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
return inputBox;
|
||||
}
|
||||
|
||||
private static Button CreateDebugButton(string content, double width)
|
||||
{
|
||||
Button button = new Button();
|
||||
button.Content = content;
|
||||
if (width > 0.0)
|
||||
{
|
||||
button.Width = width;
|
||||
}
|
||||
button.Height = 28.0;
|
||||
button.Margin = new Thickness(0.0, 0.0, 6.0, 0.0);
|
||||
button.Padding = new Thickness(4.0, 0.0, 4.0, 0.0);
|
||||
button.Background = new SolidColorBrush(Color.FromRgb(43, 62, 81));
|
||||
button.BorderBrush = new SolidColorBrush(Color.FromRgb(96, 122, 149));
|
||||
button.Foreground = Brushes.White;
|
||||
button.FontSize = 12.0;
|
||||
return button;
|
||||
}
|
||||
|
||||
private sealed class HeaderDeviceStatusOverlaySettings : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private const double DefaultTopMargin = 8.0;
|
||||
private const double DefaultLeftMargin = 8.0;
|
||||
private const double DefaultDebugPanelTopOffset = 50.0;
|
||||
private const double DefaultAdjustStep = 1.0;
|
||||
private const string ConfigurationDirectoryName = "Configuration";
|
||||
private const string ConfigurationFileName = "HeaderDeviceStatusOverlay.json";
|
||||
|
||||
private readonly string _configurationDirectoryPath;
|
||||
private readonly string _configurationFilePath;
|
||||
private readonly FileSystemWatcher _fileWatcher;
|
||||
private double _topMargin = DefaultTopMargin;
|
||||
private double _leftMargin = DefaultLeftMargin;
|
||||
private bool _isDebugPanelVisible;
|
||||
private double _step = DefaultAdjustStep;
|
||||
private string _leftMarginText = DefaultLeftMargin.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
private string _topMarginText = DefaultTopMargin.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
private string _stepText = DefaultAdjustStep.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
|
||||
public HeaderDeviceStatusOverlaySettings()
|
||||
{
|
||||
_configurationDirectoryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigurationDirectoryName);
|
||||
_configurationFilePath = Path.Combine(_configurationDirectoryPath, ConfigurationFileName);
|
||||
|
||||
EnsureConfigurationFile();
|
||||
LoadFromFile();
|
||||
|
||||
_fileWatcher = new FileSystemWatcher(_configurationDirectoryPath, ConfigurationFileName);
|
||||
_fileWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.CreationTime;
|
||||
_fileWatcher.Changed += OnConfigurationFileChanged;
|
||||
_fileWatcher.Created += OnConfigurationFileChanged;
|
||||
_fileWatcher.Renamed += OnConfigurationFileRenamed;
|
||||
_fileWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
public Thickness Margin
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Thickness(_leftMargin, _topMargin, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public Thickness DebugPanelMargin
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Thickness(_leftMargin, _topMargin + DefaultDebugPanelTopOffset, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDebugPanelVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isDebugPanelVisible;
|
||||
}
|
||||
}
|
||||
|
||||
public double Step
|
||||
{
|
||||
get
|
||||
{
|
||||
return _step;
|
||||
}
|
||||
}
|
||||
|
||||
public string LeftMarginText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _leftMarginText;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _leftMarginText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string TopMarginText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _topMarginText;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _topMarginText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string StepText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _stepText;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _stepText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string PositionSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("Left={0:0.##}, Top={1:0.##}, Step={2:0.##}", _leftMargin, _topMargin, _step);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_fileWatcher.Changed -= OnConfigurationFileChanged;
|
||||
_fileWatcher.Created -= OnConfigurationFileChanged;
|
||||
_fileWatcher.Renamed -= OnConfigurationFileRenamed;
|
||||
_fileWatcher.Dispose();
|
||||
}
|
||||
|
||||
public void AdjustMargin(double leftOffset, double topOffset)
|
||||
{
|
||||
double leftMargin = _leftMargin + leftOffset;
|
||||
double topMargin = _topMargin + topOffset;
|
||||
|
||||
UpdateSettings(leftMargin, topMargin, _isDebugPanelVisible, _step);
|
||||
PersistCurrentConfiguration();
|
||||
}
|
||||
|
||||
public void HideDebugPanel()
|
||||
{
|
||||
UpdateSettings(_leftMargin, _topMargin, false, _step);
|
||||
PersistCurrentConfiguration();
|
||||
}
|
||||
|
||||
public void ApplyTextValues()
|
||||
{
|
||||
double leftMargin;
|
||||
double topMargin;
|
||||
double step;
|
||||
|
||||
bool canParseLeft = TryParseInput(LeftMarginText, _leftMargin, out leftMargin);
|
||||
bool canParseTop = TryParseInput(TopMarginText, _topMargin, out topMargin);
|
||||
bool canParseStep = TryParseInput(StepText, _step, out step);
|
||||
|
||||
if (!canParseStep)
|
||||
{
|
||||
step = _step;
|
||||
}
|
||||
|
||||
step = NormalizeStep(step);
|
||||
|
||||
UpdateSettings(leftMargin, topMargin, _isDebugPanelVisible, step);
|
||||
PersistCurrentConfiguration();
|
||||
}
|
||||
|
||||
private void OnConfigurationFileChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
ReloadOnUiThread();
|
||||
}
|
||||
|
||||
private void OnConfigurationFileRenamed(object sender, RenamedEventArgs e)
|
||||
{
|
||||
ReloadOnUiThread();
|
||||
}
|
||||
|
||||
private void ReloadOnUiThread()
|
||||
{
|
||||
Application currentApplication = Application.Current;
|
||||
if (currentApplication == null)
|
||||
{
|
||||
LoadFromFile();
|
||||
return;
|
||||
}
|
||||
|
||||
currentApplication.Dispatcher.BeginInvoke(
|
||||
DispatcherPriority.Background,
|
||||
new Action(LoadFromFile));
|
||||
}
|
||||
|
||||
private void EnsureConfigurationFile()
|
||||
{
|
||||
if (!Directory.Exists(_configurationDirectoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(_configurationDirectoryPath);
|
||||
}
|
||||
|
||||
if (File.Exists(_configurationFilePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HeaderDeviceStatusOverlayPositionConfiguration configuration = new HeaderDeviceStatusOverlayPositionConfiguration();
|
||||
configuration.TopMargin = DefaultTopMargin;
|
||||
configuration.LeftMargin = DefaultLeftMargin;
|
||||
configuration.ShowDebugPanel = false;
|
||||
configuration.AdjustStep = DefaultAdjustStep;
|
||||
SaveConfiguration(configuration);
|
||||
}
|
||||
|
||||
private void LoadFromFile()
|
||||
{
|
||||
HeaderDeviceStatusOverlayPositionConfiguration configuration = TryReadConfiguration();
|
||||
if (configuration == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double topMargin = NormalizeMargin(configuration.TopMargin, DefaultTopMargin);
|
||||
double leftMargin = NormalizeMargin(configuration.LeftMargin, DefaultLeftMargin);
|
||||
double adjustStep = NormalizeStep(configuration.AdjustStep);
|
||||
UpdateSettings(leftMargin, topMargin, configuration.ShowDebugPanel, adjustStep);
|
||||
}
|
||||
|
||||
private HeaderDeviceStatusOverlayPositionConfiguration TryReadConfiguration()
|
||||
{
|
||||
for (int attempt = 0; attempt < 3; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
string content = File.ReadAllText(_configurationFilePath);
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new HeaderDeviceStatusOverlayPositionConfiguration();
|
||||
}
|
||||
|
||||
HeaderDeviceStatusOverlayPositionConfiguration configuration = JsonConvert.DeserializeObject<HeaderDeviceStatusOverlayPositionConfiguration>(content);
|
||||
return configuration ?? new HeaderDeviceStatusOverlayPositionConfiguration();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SaveConfiguration(HeaderDeviceStatusOverlayPositionConfiguration configuration)
|
||||
{
|
||||
string content = JsonConvert.SerializeObject(configuration, Formatting.Indented);
|
||||
File.WriteAllText(_configurationFilePath, content);
|
||||
}
|
||||
|
||||
private void PersistCurrentConfiguration()
|
||||
{
|
||||
HeaderDeviceStatusOverlayPositionConfiguration configuration = new HeaderDeviceStatusOverlayPositionConfiguration();
|
||||
configuration.TopMargin = _topMargin;
|
||||
configuration.LeftMargin = _leftMargin;
|
||||
configuration.ShowDebugPanel = _isDebugPanelVisible;
|
||||
configuration.AdjustStep = _step;
|
||||
SaveConfiguration(configuration);
|
||||
}
|
||||
|
||||
private static double NormalizeMargin(double value, double fallbackValue)
|
||||
{
|
||||
if (double.IsNaN(value) || double.IsInfinity(value))
|
||||
{
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static double NormalizeStep(double value)
|
||||
{
|
||||
if (double.IsNaN(value) || double.IsInfinity(value) || value <= 0.0)
|
||||
{
|
||||
return DefaultAdjustStep;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private void UpdateSettings(double leftMargin, double topMargin, bool isDebugPanelVisible, double step)
|
||||
{
|
||||
bool hasChanged = !leftMargin.Equals(_leftMargin)
|
||||
|| !topMargin.Equals(_topMargin)
|
||||
|| !isDebugPanelVisible.Equals(_isDebugPanelVisible)
|
||||
|| !step.Equals(_step);
|
||||
if (!hasChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_leftMargin = leftMargin;
|
||||
_topMargin = topMargin;
|
||||
_isDebugPanelVisible = isDebugPanelVisible;
|
||||
_step = step;
|
||||
LeftMarginText = FormatValue(_leftMargin);
|
||||
TopMarginText = FormatValue(_topMargin);
|
||||
StepText = FormatValue(_step);
|
||||
NotifyOfPropertyChange(nameof(Margin));
|
||||
NotifyOfPropertyChange(nameof(DebugPanelMargin));
|
||||
NotifyOfPropertyChange(nameof(IsDebugPanelVisible));
|
||||
NotifyOfPropertyChange(nameof(Step));
|
||||
NotifyOfPropertyChange(nameof(PositionSummary));
|
||||
}
|
||||
|
||||
private static bool TryParseInput(string text, double fallbackValue, out double value)
|
||||
{
|
||||
string trimmedText = string.IsNullOrWhiteSpace(text) ? string.Empty : text.Trim();
|
||||
if (string.IsNullOrEmpty(trimmedText))
|
||||
{
|
||||
value = fallbackValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
return double.TryParse(trimmedText, NumberStyles.Float, CultureInfo.InvariantCulture, out value)
|
||||
|| double.TryParse(trimmedText, NumberStyles.Float, CultureInfo.CurrentCulture, out value);
|
||||
}
|
||||
|
||||
private static string FormatValue(double value)
|
||||
{
|
||||
return value.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class HeaderDeviceStatusOverlayPositionConfiguration
|
||||
{
|
||||
public double TopMargin { get; set; }
|
||||
|
||||
public double LeftMargin { get; set; }
|
||||
|
||||
public bool ShowDebugPanel { get; set; }
|
||||
|
||||
public double AdjustStep { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Localization resource helper.
|
||||
/// </summary>
|
||||
public static class LanguageResourceHelper
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<MessageKey, string> ResourceKeyMap =
|
||||
new Dictionary<MessageKey, string>
|
||||
{
|
||||
{ MessageKey.TitleInfo, "Msg_Title_Info" },
|
||||
{ MessageKey.TitleWarning, "Msg_Title_Warning" },
|
||||
{ MessageKey.TitleError, "Msg_Title_Error" },
|
||||
{ MessageKey.TitleConfirm, "Msg_Title_Confirm" },
|
||||
|
||||
{ MessageKey.VisionCameraNotFound, "Msg_Vision_CameraNotFound" },
|
||||
{ MessageKey.VisionCameraNotOpen, "Msg_Vision_CameraNotOpen" },
|
||||
{ MessageKey.VisionCameraNotGrabbing, "Msg_Vision_CameraNotGrabbing" },
|
||||
{ MessageKey.VisionCaptureTimeout, "Msg_Vision_CaptureTimeout" },
|
||||
{ MessageKey.VisionNoFrameReturned, "Msg_Vision_NoFrameReturned" },
|
||||
{ MessageKey.VisionSoftTriggerFailed, "Msg_Vision_SoftTriggerFailed" },
|
||||
{ MessageKey.VisionDriverError, "Msg_Vision_DriverError" },
|
||||
{ MessageKey.VisionImageIsNull, "Msg_Vision_ImageIsNull" },
|
||||
{ MessageKey.VisionRequestInvalid, "Msg_Vision_RequestInvalid" },
|
||||
{ MessageKey.VisionTimeoutInvalid, "Msg_Vision_TimeoutInvalid" },
|
||||
{ MessageKey.VisionOperationCancelled, "Msg_Vision_OperationCancelled" },
|
||||
{ MessageKey.VisionTemplatePathEmpty, "Msg_Vision_TemplatePathEmpty" },
|
||||
{ MessageKey.VisionTemplateRoiInvalid, "Msg_Vision_TemplateRoiInvalid" },
|
||||
{ MessageKey.VisionTemplateMinScoreInvalid, "Msg_Vision_TemplateMinScoreInvalid" },
|
||||
{ MessageKey.VisionTemplateAlgorithmNotImplemented, "Msg_Vision_TemplateAlgorithmNotImplemented" },
|
||||
{ MessageKey.VisionTemplateMatchFailed, "Msg_Vision_TemplateMatchFailed" },
|
||||
{ MessageKey.VisionCommonAlgorithmNotSupported, "Msg_Vision_CommonAlgorithmNotSupported" },
|
||||
{ MessageKey.VisionCommonAlgorithmExecutionFailed, "Msg_Vision_CommonAlgorithmExecutionFailed" },
|
||||
{ MessageKey.VisionChipMapSortInputInvalid, "Msg_Vision_ChipMapSortInputInvalid" },
|
||||
|
||||
{ MessageKey.CommonUnknownError, "Msg_Common_UnknownError" },
|
||||
{ MessageKey.CommonOperationSucceeded, "Msg_Common_OperationSucceeded" },
|
||||
{ MessageKey.CommonOperationFailed, "Msg_Common_OperationFailed" },
|
||||
{ MessageKey.CommonSaveSucceeded, "Msg_Common_SaveSucceeded" },
|
||||
{ MessageKey.CommonSaveFailed, "Msg_Common_SaveFailed" },
|
||||
{ MessageKey.AxisSoftLimitSaveConfirm, "Msg_AxisSoftLimit_SaveConfirm" },
|
||||
{ MessageKey.AxisSoftLimitSaveFailedWithReason, "Msg_AxisSoftLimit_SaveFailedWithReason" },
|
||||
{ MessageKey.AxisSoftLimitLoadFailedWithReason, "Msg_AxisSoftLimit_LoadFailedWithReason" },
|
||||
{ MessageKey.AxisSoftLimitRangeInvalid, "Msg_AxisSoftLimit_RangeInvalid" },
|
||||
{ MessageKey.AxisSoftLimitApplySucceeded, "Msg_AxisSoftLimit_ApplySucceeded" },
|
||||
{ MessageKey.AxisSoftLimitApplyFailedWithReason, "Msg_AxisSoftLimit_ApplyFailedWithReason" },
|
||||
{ MessageKey.AxisSoftLimitApplyAllSucceeded, "Msg_AxisSoftLimit_ApplyAllSucceeded" },
|
||||
{ MessageKey.AxisSoftLimitApplyAllFailedWithReason, "Msg_AxisSoftLimit_ApplyAllFailedWithReason" },
|
||||
{ MessageKey.AxisSoftLimitNoAxisData, "Msg_AxisSoftLimit_NoAxisData" },
|
||||
{ MessageKey.AxisSoftLimitSelectedAxisRequired, "Msg_AxisSoftLimit_SelectedAxisRequired" },
|
||||
{ MessageKey.CommonDeleteConfirm, "Msg_Common_DeleteConfirm" },
|
||||
{ MessageKey.CommonExitConfirm, "Msg_Common_ExitConfirm" },
|
||||
|
||||
{ MessageKey.DeviceNotInitialized, "Msg_Device_NotInitialized" },
|
||||
{ MessageKey.DeviceBusy, "Msg_Device_Busy" },
|
||||
{ MessageKey.DeviceDisconnected, "Msg_Device_Disconnected" },
|
||||
{ MessageKey.DeviceHomeRequired, "Msg_Device_HomeRequired" },
|
||||
|
||||
{ MessageKey.ParamInvalid, "Msg_Param_Invalid" },
|
||||
{ MessageKey.ParamEmpty, "Msg_Param_Empty" },
|
||||
{ MessageKey.ParamOutOfRange, "Msg_Param_OutOfRange" },
|
||||
|
||||
{ MessageKey.StartProcessConfirm, "Msg_Process_StartConfirm" },
|
||||
{ MessageKey.StartProcessFailed, "Msg_Process_StartFailed" },
|
||||
{ MessageKey.StopProcessConfirm, "Msg_Process_StopConfirm" },
|
||||
{ MessageKey.StopProcessFailed, "Msg_Process_StopFailed" },
|
||||
|
||||
{ MessageKey.ProcessFailed, "Msg_Process_Failed" },
|
||||
{ MessageKey.ProcessFailedWithReason, "Msg_Process_FailedWithReason" },
|
||||
{ MessageKey.ProcessStepFailedWithReason, "Msg_Process_StepFailedWithReason" },
|
||||
{ MessageKey.ProcessSubstratePositionFailedWithReason, "Msg_Process_SubstratePositionFailedWithReason" },
|
||||
{ MessageKey.ProcessSubstratePositionRecipeNotLoaded, "Msg_Process_SubstratePositionRecipeNotLoaded" },
|
||||
{ MessageKey.ProcessSubstratePositionMarkParameterMissing, "Msg_Process_SubstratePositionMarkParameterMissing" },
|
||||
{ MessageKey.ProcessSubstratePositionNoEnabledMarks, "Msg_Process_SubstratePositionNoEnabledMarks" },
|
||||
{ MessageKey.ProcessSubstratePositionAlignmentFailedWithReason, "Msg_Process_SubstratePositionAlignmentFailedWithReason" },
|
||||
{ MessageKey.ProcessDiePositionFailedWithReason, "Msg_Process_DiePositionFailedWithReason" },
|
||||
{ MessageKey.ProcessDiePositionRecipeNotLoaded, "Msg_Process_DiePositionRecipeNotLoaded" },
|
||||
{ MessageKey.ProcessDiePositionCoordinateGenerationMissing, "Msg_Process_DiePositionCoordinateGenerationMissing" },
|
||||
{ MessageKey.ProcessDiePositionWaferInfoMissing, "Msg_Process_DiePositionWaferInfoMissing" },
|
||||
{ MessageKey.ProcessSubstrateHeightMeasureFailedWithReason, "Msg_Process_SubstrateHeightMeasureFailedWithReason" },
|
||||
{ MessageKey.ProcessSubstrateHeightMeasureRecipeNotLoaded, "Msg_Process_SubstrateHeightMeasureRecipeNotLoaded" },
|
||||
{ MessageKey.ProcessSubstrateHeightMeasureSettingMissing, "Msg_Process_SubstrateHeightMeasureSettingMissing" },
|
||||
{ MessageKey.ProcessSubstrateHeightMeasureNoPoints, "Msg_Process_SubstrateHeightMeasureNoPoints" },
|
||||
{ MessageKey.ProcessSubstrateHeightMeasurePointPositionInvalid, "Msg_Process_SubstrateHeightMeasurePointPositionInvalid" },
|
||||
{ MessageKey.NeedleCalibrationLoadFailed, "Msg_NeedleCalibration_LoadFailed" },
|
||||
{ MessageKey.NeedleCalibrationTouchCountMustGreaterThanZero, "Msg_NeedleCalibration_TouchCountMustGreaterThanZero" },
|
||||
{ MessageKey.NeedleCalibrationCompleted, "Msg_NeedleCalibration_Completed" },
|
||||
{ MessageKey.NeedleCalibrationStopped, "Msg_NeedleCalibration_Stopped" },
|
||||
{ MessageKey.NeedleCalibrationCanceled, "Msg_NeedleCalibration_Canceled" },
|
||||
{ MessageKey.OriginCalibOpenVisionTemplateFailed, "Msg_OriginCalib_OpenVisionTemplateFailed" },
|
||||
{ MessageKey.OriginCalibAxisNotFound, "Msg_OriginCalib_AxisNotFound" },
|
||||
{ MessageKey.OriginCalibReadPositionFailed, "Msg_OriginCalib_ReadPositionFailed" },
|
||||
{ MessageKey.OriginCalibMoveFailed, "Msg_OriginCalib_MoveFailed" },
|
||||
{ MessageKey.OriginCalibDeleteAxisFailed, "Msg_OriginCalib_DeleteAxisFailed" },
|
||||
{ MessageKey.OriginCalibDeleteAxisDuringCalibration, "Msg_OriginCalib_DeleteAxisDuringCalibration" },
|
||||
{ MessageKey.OriginCalibCalibrationCanceled, "Msg_OriginCalib_CalibrationCanceled" },
|
||||
{ MessageKey.OriginCalibCalibrationFailed, "Msg_OriginCalib_CalibrationFailed" },
|
||||
{ MessageKey.OriginCalibConfigSaved, "Msg_OriginCalib_ConfigSaved" },
|
||||
{ MessageKey.OriginCalibConfigSaveFailed, "Msg_OriginCalib_ConfigSaveFailed" },
|
||||
{ MessageKey.OriginCalibNoCalibratedModules, "Msg_OriginCalib_NoCalibratedModules" },
|
||||
{ MessageKey.OriginCalibControllerWriteCompleted, "Msg_OriginCalib_ControllerWriteCompleted" },
|
||||
{ MessageKey.OriginCalibControllerWriteNotReady, "Msg_OriginCalib_ControllerWriteNotReady" },
|
||||
{ MessageKey.OriginCalibControllerWritePartialSuccess, "Msg_OriginCalib_ControllerWritePartialSuccess" },
|
||||
{ MessageKey.OriginCalibControllerWriteNotImplemented, "Msg_OriginCalib_ControllerWriteNotImplemented" },
|
||||
{ MessageKey.PidNoProfileSelected, "Msg_Pid_NoProfileSelected" },
|
||||
{ MessageKey.PidNoFilteringParameterSelected, "Msg_Pid_NoFilteringParameterSelected" },
|
||||
{ MessageKey.PidReadSucceeded, "Msg_Pid_ReadSucceeded" },
|
||||
{ MessageKey.PidReadFailed, "Msg_Pid_ReadFailed" },
|
||||
{ MessageKey.PidWriteSucceeded, "Msg_Pid_WriteSucceeded" },
|
||||
{ MessageKey.PidWriteFailed, "Msg_Pid_WriteFailed" },
|
||||
|
||||
{ MessageKey.DieRecheckSelectedPointRequired, "Msg_DieRecheck_SelectedPointRequired" },
|
||||
{ MessageKey.DieRecheckMoveDeviceUnavailable, "Msg_DieRecheck_MoveDeviceUnavailable" },
|
||||
{ MessageKey.DieRecheckStatusOk, "Msg_DieRecheck_StatusOk" },
|
||||
{ MessageKey.DieRecheckStatusMissingBond, "Msg_DieRecheck_StatusMissingBond" },
|
||||
{ MessageKey.DieRecheckStatusXExceeded, "Msg_DieRecheck_StatusXExceeded" },
|
||||
{ MessageKey.DieRecheckStatusYExceeded, "Msg_DieRecheck_StatusYExceeded" }
|
||||
};
|
||||
|
||||
public static string GetString(MessageKey messageKey)
|
||||
{
|
||||
return GetString(messageKey, messageKey.ToString());
|
||||
}
|
||||
|
||||
public static string GetString(MessageKey messageKey, string fallback)
|
||||
{
|
||||
if (messageKey == MessageKey.None)
|
||||
{
|
||||
return fallback ?? string.Empty;
|
||||
}
|
||||
|
||||
if (!ResourceKeyMap.TryGetValue(messageKey, out var resourceKey))
|
||||
{
|
||||
return fallback ?? messageKey.ToString();
|
||||
}
|
||||
|
||||
var application = Application.Current;
|
||||
if (application == null)
|
||||
{
|
||||
return fallback ?? resourceKey;
|
||||
}
|
||||
|
||||
var resource = application.TryFindResource(resourceKey);
|
||||
if (resource is string text && !string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
return fallback ?? resourceKey;
|
||||
}
|
||||
|
||||
public static string Format(MessageKey messageKey, params object[] args)
|
||||
{
|
||||
var format = GetString(messageKey);
|
||||
return args == null || args.Length == 0
|
||||
? format
|
||||
: string.Format(format, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Common/Loading.cs
Normal file
104
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Common/Loading.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using MainShell.Resources.CustomControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class Loading
|
||||
{
|
||||
|
||||
private static LoadingWaitView _view;
|
||||
|
||||
// 全局初始化:在主程序启动或插件加载时调用一次
|
||||
public static void Initialize(Window mainWindow)
|
||||
{
|
||||
if (_view != null) return; // 避免重复加载
|
||||
|
||||
_view = new LoadingWaitView();
|
||||
|
||||
// 获取窗口的根内容
|
||||
var rootContent = mainWindow.Content;
|
||||
|
||||
if (rootContent is Panel rootPanel)
|
||||
{
|
||||
// 如果根部本来就是 Panel (Grid/Canvas等),直接添加
|
||||
rootPanel.Children.Add(_view);
|
||||
}
|
||||
else if (rootContent is ContentControl contentControl)
|
||||
{
|
||||
// 如果根部是 ContentControl,我们需要把原本的内容包在一个新的 Grid 里
|
||||
var originalContent = contentControl.Content as UIElement;
|
||||
contentControl.Content = null;
|
||||
|
||||
var wrapperGrid = new Grid();
|
||||
wrapperGrid.Children.Add(originalContent); // 原有内容
|
||||
wrapperGrid.Children.Add(_view); // 我们的遮罩层
|
||||
|
||||
contentControl.Content = wrapperGrid;
|
||||
}
|
||||
|
||||
// 确保遮罩层铺满并置于顶层
|
||||
Grid.SetColumnSpan(_view, 99);
|
||||
Grid.SetRowSpan(_view, 99);
|
||||
Panel.SetZIndex(_view, 9999);
|
||||
}
|
||||
// 基础调用:Loading.Show("计算中...");
|
||||
public static void Show(string msg, bool isIndeterminate, bool canCancel = true) => LoadingService.Instance.Show(msg, canCancel, isIndeterminate);
|
||||
|
||||
public static void Hide() => LoadingService.Instance.Hide();
|
||||
|
||||
public static void Report(double val) => LoadingService.Instance.Report(val);
|
||||
|
||||
// 获取当前令牌:Loading.Token
|
||||
public static CancellationToken Token => LoadingService.Instance.Token;
|
||||
|
||||
// 高级用法:使用 using 块自动开启和关闭
|
||||
public static IDisposable Manager(string msg, bool canCancel = true)
|
||||
{
|
||||
Show(msg, canCancel);
|
||||
return new DisposableAction(() => Hide());
|
||||
}
|
||||
|
||||
public static async Task<bool> RunAsync(
|
||||
Func<CancellationToken, IProgress<double>, Task> work,
|
||||
string message,
|
||||
bool canCancel = true, bool isIndeterminate = false,
|
||||
Action<Exception> onError = null)
|
||||
{
|
||||
using (Manager(message, canCancel))
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadingService.Instance.Show(message, isIndeterminate, canCancel);
|
||||
var progress = new Progress<double>(val =>
|
||||
Application.Current.Dispatcher.Invoke(() => LoadingService.Instance.ProgressValue = val));
|
||||
|
||||
await Task.Run(() => work(LoadingService.Instance.Token, progress), LoadingService.Instance.Token);
|
||||
|
||||
return true; // 执行成功
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 用户点击了取消,通常不需要弹窗,直接返回 false
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获其他所有异常(硬件错误、逻辑错误等)
|
||||
if (onError != null)
|
||||
onError(ex);
|
||||
else
|
||||
MessageBox.Show($"操作失败: {ex.Message}", "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><D7B0>
|
||||
/// </summary>
|
||||
public static class LocalizedMessageBox
|
||||
{
|
||||
public static MessageBoxResult Show(MessageKey messageKey)
|
||||
{
|
||||
return Show(null, messageKey, MessageKey.TitleInfo, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(MessageKey messageKey, MessageKey captionKey)
|
||||
{
|
||||
return Show(null, messageKey, captionKey, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(MessageKey messageKey, MessageKey captionKey, MessageBoxButton button, MessageBoxImage icon)
|
||||
{
|
||||
return Show(null, messageKey, captionKey, button, icon, MessageBoxResult.None);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, MessageKey messageKey, MessageKey captionKey, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult = MessageBoxResult.None)
|
||||
{
|
||||
return MwMessageBox.InvokeOnUiThread(() => ShowCore(owner, messageKey, captionKey, button, icon, defaultResult));
|
||||
}
|
||||
|
||||
public static MessageBoxResult ShowFormat(MessageKey messageKey, MessageKey captionKey, MessageBoxButton button, MessageBoxImage icon, params object[] args)
|
||||
{
|
||||
return MwMessageBox.InvokeOnUiThread(() => ShowFormatCore(messageKey, captionKey, button, icon, args));
|
||||
}
|
||||
|
||||
private static MessageBoxResult ShowCore(Window owner, MessageKey messageKey, MessageKey captionKey, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
|
||||
{
|
||||
string message = LanguageResourceHelper.GetString(messageKey);
|
||||
string caption = captionKey == MessageKey.None
|
||||
? string.Empty
|
||||
: LanguageResourceHelper.GetString(captionKey);
|
||||
|
||||
return MwMessageBox.Show(owner, message, caption, button, icon, defaultResult);
|
||||
}
|
||||
|
||||
private static MessageBoxResult ShowFormatCore(MessageKey messageKey, MessageKey captionKey, MessageBoxButton button, MessageBoxImage icon, object[] args)
|
||||
{
|
||||
string message = LanguageResourceHelper.Format(messageKey, args);
|
||||
string caption = captionKey == MessageKey.None
|
||||
? string.Empty
|
||||
: LanguageResourceHelper.GetString(captionKey);
|
||||
|
||||
return MwMessageBox.Show(message, caption, button, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD> MessageKey <20><>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD>ܿ<EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class LocalizedProcessException : Exception
|
||||
{
|
||||
public MessageKey FailureMessageKey { get; }
|
||||
|
||||
public string[] FailureMessageArguments { get; }
|
||||
|
||||
public LocalizedProcessException(MessageKey failureMessageKey, params string[] failureMessageArguments)
|
||||
: base(LanguageResourceHelper.Format(failureMessageKey, ConvertArguments(failureMessageArguments)))
|
||||
{
|
||||
FailureMessageKey = failureMessageKey;
|
||||
FailureMessageArguments = failureMessageArguments ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
public static object[] ConvertArguments(string[] failureMessageArguments)
|
||||
{
|
||||
if (failureMessageArguments == null || failureMessageArguments.Length == 0)
|
||||
{
|
||||
return Array.Empty<object>();
|
||||
}
|
||||
|
||||
object[] convertedArguments = new object[failureMessageArguments.Length];
|
||||
for (int i = 0; i < failureMessageArguments.Length; i++)
|
||||
{
|
||||
convertedArguments[i] = failureMessageArguments[i];
|
||||
}
|
||||
|
||||
return convertedArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Message keys used by the localization system.
|
||||
/// </summary>
|
||||
public enum MessageKey
|
||||
{
|
||||
None = 0,
|
||||
|
||||
TitleInfo,
|
||||
TitleWarning,
|
||||
TitleError,
|
||||
TitleConfirm,
|
||||
|
||||
VisionCameraNotFound,
|
||||
VisionCameraNotOpen,
|
||||
VisionCameraNotGrabbing,
|
||||
VisionCaptureTimeout,
|
||||
VisionNoFrameReturned,
|
||||
VisionSoftTriggerFailed,
|
||||
VisionDriverError,
|
||||
VisionImageIsNull,
|
||||
VisionRequestInvalid,
|
||||
VisionTimeoutInvalid,
|
||||
VisionOperationCancelled,
|
||||
VisionTemplatePathEmpty,
|
||||
VisionTemplateRoiInvalid,
|
||||
VisionTemplateMinScoreInvalid,
|
||||
VisionTemplateAlgorithmNotImplemented,
|
||||
VisionTemplateMatchFailed,
|
||||
VisionCommonAlgorithmNotSupported,
|
||||
VisionCommonAlgorithmExecutionFailed,
|
||||
VisionChipMapSortInputInvalid,
|
||||
|
||||
CommonUnknownError,
|
||||
CommonOperationSucceeded,
|
||||
CommonOperationFailed,
|
||||
CommonSaveSucceeded,
|
||||
CommonSaveFailed,
|
||||
AxisSoftLimitSaveConfirm,
|
||||
AxisSoftLimitSaveFailedWithReason,
|
||||
AxisSoftLimitLoadFailedWithReason,
|
||||
AxisSoftLimitRangeInvalid,
|
||||
AxisSoftLimitApplySucceeded,
|
||||
AxisSoftLimitApplyFailedWithReason,
|
||||
AxisSoftLimitApplyAllSucceeded,
|
||||
AxisSoftLimitApplyAllFailedWithReason,
|
||||
AxisSoftLimitNoAxisData,
|
||||
AxisSoftLimitSelectedAxisRequired,
|
||||
CommonDeleteConfirm,
|
||||
CommonExitConfirm,
|
||||
|
||||
DeviceNotInitialized,
|
||||
DeviceBusy,
|
||||
DeviceDisconnected,
|
||||
DeviceHomeRequired,
|
||||
|
||||
ParamInvalid,
|
||||
ParamEmpty,
|
||||
ParamOutOfRange,
|
||||
|
||||
StartProcessConfirm,
|
||||
StartProcessFailed,
|
||||
StopProcessConfirm,
|
||||
StopProcessFailed,
|
||||
|
||||
ProcessFailed,
|
||||
ProcessFailedWithReason,
|
||||
ProcessStepFailedWithReason,
|
||||
ProcessSubstratePositionFailedWithReason,
|
||||
ProcessSubstratePositionRecipeNotLoaded,
|
||||
ProcessSubstratePositionMarkParameterMissing,
|
||||
ProcessSubstratePositionNoEnabledMarks,
|
||||
ProcessSubstratePositionAlignmentFailedWithReason,
|
||||
ProcessDiePositionFailedWithReason,
|
||||
ProcessDiePositionRecipeNotLoaded,
|
||||
ProcessDiePositionCoordinateGenerationMissing,
|
||||
ProcessDiePositionWaferInfoMissing,
|
||||
ProcessSubstrateHeightMeasureFailedWithReason,
|
||||
ProcessSubstrateHeightMeasureRecipeNotLoaded,
|
||||
ProcessSubstrateHeightMeasureSettingMissing,
|
||||
ProcessSubstrateHeightMeasureNoPoints,
|
||||
ProcessSubstrateHeightMeasurePointPositionInvalid,
|
||||
NeedleCalibrationLoadFailed,
|
||||
NeedleCalibrationTouchCountMustGreaterThanZero,
|
||||
NeedleCalibrationCompleted,
|
||||
NeedleCalibrationStopped,
|
||||
NeedleCalibrationCanceled,
|
||||
OriginCalibOpenVisionTemplateFailed,
|
||||
OriginCalibAxisNotFound,
|
||||
OriginCalibReadPositionFailed,
|
||||
OriginCalibMoveFailed,
|
||||
OriginCalibDeleteAxisFailed,
|
||||
OriginCalibDeleteAxisDuringCalibration,
|
||||
OriginCalibCalibrationCanceled,
|
||||
OriginCalibCalibrationFailed,
|
||||
OriginCalibConfigSaved,
|
||||
OriginCalibConfigSaveFailed,
|
||||
OriginCalibNoCalibratedModules,
|
||||
OriginCalibControllerWriteCompleted,
|
||||
OriginCalibControllerWriteNotReady,
|
||||
OriginCalibControllerWritePartialSuccess,
|
||||
OriginCalibControllerWriteNotImplemented,
|
||||
|
||||
PidNoProfileSelected,
|
||||
PidNoFilteringParameterSelected,
|
||||
PidReadSucceeded,
|
||||
PidReadFailed,
|
||||
PidWriteSucceeded,
|
||||
PidWriteFailed,
|
||||
|
||||
DieRecheckSelectedPointRequired,
|
||||
DieRecheckMoveDeviceUnavailable,
|
||||
DieRecheckStatusOk,
|
||||
DieRecheckStatusMissingBond,
|
||||
DieRecheckStatusXExceeded,
|
||||
DieRecheckStatusYExceeded
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,639 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using MainShell.Common.View;
|
||||
using MainShell.Common.ViewModel;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class MwMessageBoxGlyphs
|
||||
{
|
||||
public const string None = "\uE686";
|
||||
public const string Information = "\uE625";
|
||||
public const string Warning = "\uE7BD";
|
||||
public const string Error = "\uE76C";
|
||||
public const string Question = "\uE686";
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxButtonText
|
||||
{
|
||||
public string Ok { get; set; } = "ȷ<><C8B7>";
|
||||
public string Cancel { get; set; } = "ȡ<><C8A1>";
|
||||
public string Yes { get; set; } = "<22><>";
|
||||
public string No { get; set; } = "<22><>";
|
||||
public string Retry { get; set; } = "<22><><EFBFBD><EFBFBD>";
|
||||
public string Abort { get; set; } = "<22><>ֹ";
|
||||
public string Ignore { get; set; } = "<22><><EFBFBD><EFBFBD>";
|
||||
|
||||
public static MwMessageBoxButtonText CreateDefault()
|
||||
{
|
||||
return new MwMessageBoxButtonText();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxButtonDefinition
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public MessageBoxResult Result { get; set; }
|
||||
|
||||
public bool IsDefault { get; set; }
|
||||
|
||||
public bool IsCancel { get; set; }
|
||||
|
||||
public bool IsPrimary { get; set; }
|
||||
|
||||
public Style ButtonStyle { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxIconTheme
|
||||
{
|
||||
public string NoneGlyph { get; set; } = MwMessageBoxGlyphs.None;
|
||||
|
||||
public string InformationGlyph { get; set; } = MwMessageBoxGlyphs.Information;
|
||||
|
||||
public string WarningGlyph { get; set; } = MwMessageBoxGlyphs.Warning;
|
||||
|
||||
public string ErrorGlyph { get; set; } = MwMessageBoxGlyphs.Error;
|
||||
|
||||
public string QuestionGlyph { get; set; } = MwMessageBoxGlyphs.Question;
|
||||
|
||||
public static MwMessageBoxIconTheme CreateDefault()
|
||||
{
|
||||
return new MwMessageBoxIconTheme();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxColorPalette
|
||||
{
|
||||
public MwMessageBoxColorPalette()
|
||||
{
|
||||
}
|
||||
|
||||
public MwMessageBoxColorPalette(string accentColor, string iconBackgroundColor, string iconForegroundColor)
|
||||
{
|
||||
AccentColor = accentColor;
|
||||
IconBackgroundColor = iconBackgroundColor;
|
||||
IconForegroundColor = iconForegroundColor;
|
||||
}
|
||||
|
||||
public string AccentColor { get; set; }
|
||||
|
||||
public string IconBackgroundColor { get; set; }
|
||||
|
||||
public string IconForegroundColor { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxButtonColorTheme
|
||||
{
|
||||
public MwMessageBoxButtonColorTheme()
|
||||
{
|
||||
}
|
||||
|
||||
public MwMessageBoxButtonColorTheme(string backgroundColor, string hoverBackgroundColor, string pressedBackgroundColor, string borderColor, string foregroundColor)
|
||||
{
|
||||
BackgroundColor = backgroundColor;
|
||||
HoverBackgroundColor = hoverBackgroundColor;
|
||||
PressedBackgroundColor = pressedBackgroundColor;
|
||||
BorderColor = borderColor;
|
||||
ForegroundColor = foregroundColor;
|
||||
}
|
||||
|
||||
public string BackgroundColor { get; set; }
|
||||
|
||||
public string HoverBackgroundColor { get; set; }
|
||||
|
||||
public string PressedBackgroundColor { get; set; }
|
||||
|
||||
public string BorderColor { get; set; }
|
||||
|
||||
public string ForegroundColor { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxVisualTheme
|
||||
{
|
||||
public MwMessageBoxColorPalette NonePalette { get; set; } = new MwMessageBoxColorPalette("#9CA3AF", "#F3F4F6", "#6B7280");
|
||||
|
||||
public MwMessageBoxColorPalette InformationPalette { get; set; } = new MwMessageBoxColorPalette("#38BDF8", "#E0F2FE", "#0284C7");
|
||||
|
||||
public MwMessageBoxColorPalette WarningPalette { get; set; } = new MwMessageBoxColorPalette("#F59E0B", "#FEF3C7", "#D97706");
|
||||
|
||||
public MwMessageBoxColorPalette ErrorPalette { get; set; } = new MwMessageBoxColorPalette("#EF4444", "#FEE2E2", "#DC2626");
|
||||
|
||||
public MwMessageBoxColorPalette QuestionPalette { get; set; } = new MwMessageBoxColorPalette("#3B82F6", "#DBEAFE", "#2563EB");
|
||||
|
||||
public MwMessageBoxButtonColorTheme PrimaryButtonTheme { get; set; } = new MwMessageBoxButtonColorTheme("#0E6AE8", "#0B5AD0", "#094BAC", "#0E6AE8", "#FFFFFF");
|
||||
|
||||
public MwMessageBoxButtonColorTheme SecondaryButtonTheme { get; set; } = new MwMessageBoxButtonColorTheme("#F3F4F6", "#E5E7EB", "#D1D5DB", "#D1D5DB", "#374151");
|
||||
|
||||
public static MwMessageBoxVisualTheme CreateDefault()
|
||||
{
|
||||
return new MwMessageBoxVisualTheme();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MwMessageBoxState
|
||||
{
|
||||
public string Caption { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public string IconGlyph { get; set; }
|
||||
|
||||
public string IconPathData { get; set; }
|
||||
|
||||
public string TimeText { get; set; }
|
||||
|
||||
public Brush AccentBrush { get; set; }
|
||||
|
||||
public Brush IconBackgroundBrush { get; set; }
|
||||
|
||||
public Brush IconForegroundBrush { get; set; }
|
||||
|
||||
public IReadOnlyList<MwMessageBoxButtonDefinition> Buttons { get; set; }
|
||||
|
||||
public MessageBoxResult DefaultResult { get; set; }
|
||||
|
||||
public TextAlignment MessageTextAlignment { get; set; } = TextAlignment.Left;
|
||||
|
||||
public FlowDirection WindowFlowDirection { get; set; } = FlowDirection.LeftToRight;
|
||||
|
||||
public FlowDirection MessageFlowDirection { get; set; } = FlowDirection.LeftToRight;
|
||||
}
|
||||
|
||||
public static class MwMessageBox
|
||||
{
|
||||
public static MwMessageBoxButtonText DefaultButtonText { get; set; } = MwMessageBoxButtonText.CreateDefault();
|
||||
|
||||
public static MwMessageBoxIconTheme IconTheme { get; set; } = MwMessageBoxIconTheme.CreateDefault();
|
||||
|
||||
public static MwMessageBoxVisualTheme VisualTheme { get; set; } = MwMessageBoxVisualTheme.CreateDefault();
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText)
|
||||
{
|
||||
return Show(null, messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, button, icon, defaultResult, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, button, icon, defaultResult, options, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText)
|
||||
{
|
||||
return Show(owner, messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, button, icon, defaultResult, 0, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, button, icon, defaultResult, options, null);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MwMessageBoxButtonText buttonText)
|
||||
{
|
||||
return Show(null, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, buttonText);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MwMessageBoxButtonText buttonText)
|
||||
{
|
||||
return Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, buttonText);
|
||||
}
|
||||
|
||||
public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, MwMessageBoxButtonText buttonText)
|
||||
{
|
||||
return InvokeOnUiThread(() => ShowCore(owner, messageBoxText, caption, button, icon, defaultResult, options, buttonText));
|
||||
}
|
||||
|
||||
public static MessageBoxResult ShowCustom(string messageBoxText, string caption, MessageBoxImage icon, params MwMessageBoxButtonDefinition[] buttons)
|
||||
{
|
||||
return ShowCustom(null, messageBoxText, caption, icon, MessageBoxResult.None, 0, buttons);
|
||||
}
|
||||
|
||||
public static MessageBoxResult ShowCustom(Window owner, string messageBoxText, string caption, MessageBoxImage icon, params MwMessageBoxButtonDefinition[] buttons)
|
||||
{
|
||||
return ShowCustom(owner, messageBoxText, caption, icon, MessageBoxResult.None, 0, buttons);
|
||||
}
|
||||
|
||||
public static MessageBoxResult ShowCustom(Window owner, string messageBoxText, string caption, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, params MwMessageBoxButtonDefinition[] buttons)
|
||||
{
|
||||
return InvokeOnUiThread(() => ShowCustomCore(owner, messageBoxText, caption, icon, defaultResult, options, buttons));
|
||||
}
|
||||
|
||||
internal static T InvokeOnUiThread<T>(Func<T> callback)
|
||||
{
|
||||
if (callback == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(callback));
|
||||
}
|
||||
|
||||
Application application = Application.Current;
|
||||
if (application == null)
|
||||
{
|
||||
return callback();
|
||||
}
|
||||
|
||||
if (application.Dispatcher == null || application.Dispatcher.CheckAccess())
|
||||
{
|
||||
return callback();
|
||||
}
|
||||
|
||||
return application.Dispatcher.Invoke(callback);
|
||||
}
|
||||
|
||||
private static MessageBoxResult ShowCore(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, MwMessageBoxButtonText buttonText)
|
||||
{
|
||||
owner = owner ?? GetActiveWindow();
|
||||
|
||||
List<MwMessageBoxButtonDefinition> definitions = CreateButtonDefinitions(button, defaultResult, buttonText ?? DefaultButtonText).ToList();
|
||||
MwMessageBoxState state = CreateState(messageBoxText, caption, icon, definitions, defaultResult, options);
|
||||
MwMessageBoxWindowViewModel viewModel = new MwMessageBoxWindowViewModel(state);
|
||||
MwMessageBoxWindow dialog = new MwMessageBoxWindow(viewModel);
|
||||
if (owner != null)
|
||||
{
|
||||
dialog.Owner = owner;
|
||||
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
}
|
||||
|
||||
dialog.ShowDialog();
|
||||
return viewModel.Result;
|
||||
}
|
||||
|
||||
private static MessageBoxResult ShowCustomCore(Window owner, string messageBoxText, string caption, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, params MwMessageBoxButtonDefinition[] buttons)
|
||||
{
|
||||
owner = owner ?? GetActiveWindow();
|
||||
List<MwMessageBoxButtonDefinition> definitions = NormalizeButtonDefinitions(buttons, defaultResult).ToList();
|
||||
MwMessageBoxState state = CreateState(messageBoxText, caption, icon, definitions, defaultResult, options);
|
||||
MwMessageBoxWindowViewModel viewModel = new MwMessageBoxWindowViewModel(state);
|
||||
MwMessageBoxWindow dialog = new MwMessageBoxWindow(viewModel);
|
||||
if (owner != null)
|
||||
{
|
||||
dialog.Owner = owner;
|
||||
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
}
|
||||
|
||||
dialog.ShowDialog();
|
||||
return viewModel.Result;
|
||||
}
|
||||
|
||||
private static IEnumerable<MwMessageBoxButtonDefinition> CreateButtonDefinitions(MessageBoxButton button, MessageBoxResult defaultResult, MwMessageBoxButtonText buttonText)
|
||||
{
|
||||
var labels = buttonText ?? MwMessageBoxButtonText.CreateDefault();
|
||||
var definitions = new List<MwMessageBoxButtonDefinition>();
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case MessageBoxButton.OK:
|
||||
definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true));
|
||||
break;
|
||||
case MessageBoxButton.OKCancel:
|
||||
definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true));
|
||||
definitions.Add(CreateDefinition(labels.Cancel, MessageBoxResult.Cancel, false, true));
|
||||
break;
|
||||
case MessageBoxButton.YesNo:
|
||||
definitions.Add(CreateDefinition(labels.Yes, MessageBoxResult.Yes, true));
|
||||
definitions.Add(CreateDefinition(labels.No, MessageBoxResult.No));
|
||||
break;
|
||||
case MessageBoxButton.YesNoCancel:
|
||||
definitions.Add(CreateDefinition(labels.Yes, MessageBoxResult.Yes, true));
|
||||
definitions.Add(CreateDefinition(labels.No, MessageBoxResult.No));
|
||||
definitions.Add(CreateDefinition(labels.Cancel, MessageBoxResult.Cancel, false, true));
|
||||
break;
|
||||
default:
|
||||
definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true));
|
||||
break;
|
||||
}
|
||||
|
||||
return NormalizeButtonDefinitions(definitions, defaultResult);
|
||||
}
|
||||
|
||||
private static IEnumerable<MwMessageBoxButtonDefinition> NormalizeButtonDefinitions(IEnumerable<MwMessageBoxButtonDefinition> buttons, MessageBoxResult defaultResult)
|
||||
{
|
||||
var definitions = (buttons ?? Enumerable.Empty<MwMessageBoxButtonDefinition>())
|
||||
.Where(item => item != null)
|
||||
.Select(item => new MwMessageBoxButtonDefinition
|
||||
{
|
||||
Text = string.IsNullOrWhiteSpace(item.Text) ? item.Result.ToString() : item.Text,
|
||||
Result = item.Result,
|
||||
IsCancel = item.IsCancel,
|
||||
IsDefault = item.IsDefault,
|
||||
IsPrimary = item.IsPrimary,
|
||||
ButtonStyle = item.ButtonStyle
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (definitions.Count == 0)
|
||||
{
|
||||
definitions.Add(CreateDefinition(DefaultButtonText.Ok, MessageBoxResult.OK, true));
|
||||
}
|
||||
|
||||
var targetDefault = defaultResult == MessageBoxResult.None
|
||||
? definitions.FirstOrDefault(item => item.IsDefault)?.Result ?? definitions[0].Result
|
||||
: defaultResult;
|
||||
|
||||
foreach (var item in definitions)
|
||||
{
|
||||
item.IsDefault = item.Result == targetDefault;
|
||||
}
|
||||
|
||||
if (!definitions.Any(item => item.IsCancel))
|
||||
{
|
||||
var cancelButton = definitions.FirstOrDefault(item => item.Result == MessageBoxResult.Cancel);
|
||||
if (cancelButton != null)
|
||||
{
|
||||
cancelButton.IsCancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!definitions.Any(item => item.IsPrimary))
|
||||
{
|
||||
var primary = definitions.FirstOrDefault(item => item.IsDefault) ?? definitions[0];
|
||||
primary.IsPrimary = true;
|
||||
}
|
||||
|
||||
foreach (var item in definitions)
|
||||
{
|
||||
item.ButtonStyle = item.ButtonStyle ?? GetButtonStyle(item.IsPrimary);
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
private static MwMessageBoxButtonDefinition CreateDefinition(string text, MessageBoxResult result, bool isPrimary = false, bool isCancel = false)
|
||||
{
|
||||
return new MwMessageBoxButtonDefinition
|
||||
{
|
||||
Text = text,
|
||||
Result = result,
|
||||
IsPrimary = isPrimary,
|
||||
IsDefault = isPrimary,
|
||||
IsCancel = isCancel,
|
||||
ButtonStyle = GetButtonStyle(isPrimary)
|
||||
};
|
||||
}
|
||||
|
||||
internal static Style GetButtonStyle(bool isPrimary)
|
||||
{
|
||||
if (Application.Current != null)
|
||||
{
|
||||
var key = isPrimary ? "SaveButtonStyle" : "SettingsButtonStyle";
|
||||
var resourceStyle = Application.Current.TryFindResource(key) as Style;
|
||||
if (resourceStyle != null)
|
||||
{
|
||||
return resourceStyle;
|
||||
}
|
||||
}
|
||||
|
||||
var visualTheme = VisualTheme ?? MwMessageBoxVisualTheme.CreateDefault();
|
||||
var buttonTheme = isPrimary ? visualTheme.PrimaryButtonTheme : visualTheme.SecondaryButtonTheme;
|
||||
|
||||
var style = new Style(typeof(System.Windows.Controls.Button));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.BackgroundColor)));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.BorderBrushProperty, CreateBrush(buttonTheme.BorderColor)));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.BorderThicknessProperty, new Thickness(1)));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.ForegroundProperty, CreateBrush(buttonTheme.ForegroundColor)));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.FontSizeProperty, 14d));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.FontWeightProperty, FontWeights.SemiBold));
|
||||
style.Setters.Add(new Setter(System.Windows.Controls.Control.CursorProperty, System.Windows.Input.Cursors.Hand));
|
||||
|
||||
var hoverTrigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true };
|
||||
hoverTrigger.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.HoverBackgroundColor)));
|
||||
style.Triggers.Add(hoverTrigger);
|
||||
|
||||
var pressedTrigger = new Trigger { Property = System.Windows.Controls.Primitives.ButtonBase.IsPressedProperty, Value = true };
|
||||
pressedTrigger.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.PressedBackgroundColor)));
|
||||
style.Triggers.Add(pressedTrigger);
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
internal static MessageBoxResult ResolveFallbackResult(MwMessageBoxState state)
|
||||
{
|
||||
if (state == null)
|
||||
{
|
||||
return MessageBoxResult.None;
|
||||
}
|
||||
|
||||
if (state.DefaultResult != MessageBoxResult.None)
|
||||
{
|
||||
return state.DefaultResult;
|
||||
}
|
||||
|
||||
var cancelButton = state.Buttons != null ? state.Buttons.FirstOrDefault(item => item.IsCancel) : null;
|
||||
if (cancelButton != null)
|
||||
{
|
||||
return cancelButton.Result;
|
||||
}
|
||||
|
||||
var defaultButton = state.Buttons != null ? state.Buttons.FirstOrDefault(item => item.IsDefault) ?? state.Buttons.FirstOrDefault() : null;
|
||||
return defaultButton != null ? defaultButton.Result : MessageBoxResult.None;
|
||||
}
|
||||
|
||||
private static Window GetActiveWindow()
|
||||
{
|
||||
if (Application.Current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var active = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.IsActive);
|
||||
if (active != null)
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
if (Application.Current.MainWindow != null && Application.Current.MainWindow.IsVisible)
|
||||
{
|
||||
return Application.Current.MainWindow;
|
||||
}
|
||||
|
||||
return Application.Current.Windows.OfType<Window>()
|
||||
.Where(w => w.IsVisible)
|
||||
.OrderByDescending(w => w.IsLoaded)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private static MwMessageBoxState CreateState(string message, string caption, MessageBoxImage icon, IReadOnlyList<MwMessageBoxButtonDefinition> buttons, MessageBoxResult defaultResult, MessageBoxOptions options)
|
||||
{
|
||||
var palette = CreatePaletteBrushes(GetPalette(icon));
|
||||
return new MwMessageBoxState
|
||||
{
|
||||
Caption = ResolveCaption(caption, icon),
|
||||
Message = message,
|
||||
IconGlyph = GetIconText(icon, IconTheme),
|
||||
IconPathData = GetIconPathData(icon),
|
||||
TimeText = DateTime.Now.ToString("HH:mm:ss"),
|
||||
AccentBrush = palette.AccentBrush,
|
||||
IconBackgroundBrush = palette.IconBackgroundBrush,
|
||||
IconForegroundBrush = palette.IconForegroundBrush,
|
||||
Buttons = buttons,
|
||||
DefaultResult = defaultResult,
|
||||
MessageTextAlignment = (options & MessageBoxOptions.RightAlign) == MessageBoxOptions.RightAlign ? TextAlignment.Right : TextAlignment.Left,
|
||||
WindowFlowDirection = (options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading ? FlowDirection.RightToLeft : FlowDirection.LeftToRight,
|
||||
MessageFlowDirection = (options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading ? FlowDirection.RightToLeft : FlowDirection.LeftToRight
|
||||
};
|
||||
}
|
||||
|
||||
private static string ResolveCaption(string caption, MessageBoxImage icon)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(caption))
|
||||
{
|
||||
return caption;
|
||||
}
|
||||
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxImage.Warning:
|
||||
return "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ";
|
||||
case MessageBoxImage.Error:
|
||||
return "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ";
|
||||
case MessageBoxImage.Information:
|
||||
return "<22><>Ϣ<EFBFBD><CFA2>ʾ";
|
||||
case MessageBoxImage.Question:
|
||||
return "<22><><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7>";
|
||||
default:
|
||||
return "<22><>ʾ";
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetIconText(MessageBoxImage icon, MwMessageBoxIconTheme iconTheme)
|
||||
{
|
||||
var theme = iconTheme ?? MwMessageBoxIconTheme.CreateDefault();
|
||||
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxImage.None:
|
||||
return theme.NoneGlyph;
|
||||
case MessageBoxImage.Warning:
|
||||
return theme.WarningGlyph;
|
||||
case MessageBoxImage.Error:
|
||||
return theme.ErrorGlyph;
|
||||
case MessageBoxImage.Information:
|
||||
return theme.InformationGlyph;
|
||||
case MessageBoxImage.Question:
|
||||
return theme.QuestionGlyph;
|
||||
default:
|
||||
return theme.NoneGlyph;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetIconPathData(MessageBoxImage icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxImage.Warning:
|
||||
return "M11,4 H13 V14 H11 Z M11,16 H13 V18 H11 Z";
|
||||
case MessageBoxImage.Error:
|
||||
return "M7.76,6.34 L12,10.59 L16.24,6.34 L17.66,7.76 L13.41,12 L17.66,16.24 L16.24,17.66 L12,13.41 L7.76,17.66 L6.34,16.24 L10.59,12 L6.34,7.76 Z";
|
||||
case MessageBoxImage.Information:
|
||||
return "M11,5 H13 V7 H11 Z M11,9 H13 V19 H11 Z";
|
||||
case MessageBoxImage.Question:
|
||||
return "M10.2,8.8 C10.27,7.69 11.17,6.82 12.3,6.82 C13.46,6.82 14.36,7.66 14.36,8.75 C14.36,9.52 13.96,10.12 13.02,10.82 C11.74,11.78 11.1,12.65 11.1,14.35 L12.9,14.35 C12.9,13.26 13.27,12.74 14.1,12.09 C15.29,11.17 16,10.14 16,8.72 C16,6.69 14.37,5 12.3,5 C10.23,5 8.56,6.63 8.4,8.8 Z M11.05,16.2 H13.15 V18.3 H11.05 Z";
|
||||
default:
|
||||
return "M8,11 H16 V13 H8 Z";
|
||||
}
|
||||
}
|
||||
|
||||
private static MwMessageBoxColorPalette GetPalette(MessageBoxImage icon)
|
||||
{
|
||||
var visualTheme = VisualTheme ?? MwMessageBoxVisualTheme.CreateDefault();
|
||||
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxImage.Warning:
|
||||
return CreatePalette(visualTheme.WarningPalette, visualTheme.NonePalette);
|
||||
case MessageBoxImage.Error:
|
||||
return CreatePalette(visualTheme.ErrorPalette, visualTheme.NonePalette);
|
||||
case MessageBoxImage.Information:
|
||||
return CreatePalette(visualTheme.InformationPalette, visualTheme.NonePalette);
|
||||
case MessageBoxImage.Question:
|
||||
return CreatePalette(visualTheme.QuestionPalette, visualTheme.NonePalette);
|
||||
default:
|
||||
return CreatePalette(visualTheme.NonePalette, MwMessageBoxVisualTheme.CreateDefault().NonePalette);
|
||||
}
|
||||
}
|
||||
|
||||
private static MwMessageBoxPaletteBrushes CreatePaletteBrushes(MwMessageBoxColorPalette palette)
|
||||
{
|
||||
return new MwMessageBoxPaletteBrushes(palette);
|
||||
}
|
||||
|
||||
private static MwMessageBoxColorPalette CreatePalette(MwMessageBoxColorPalette palette, MwMessageBoxColorPalette fallbackPalette)
|
||||
{
|
||||
var resolvedFallback = fallbackPalette ?? MwMessageBoxVisualTheme.CreateDefault().NonePalette;
|
||||
var resolvedPalette = palette ?? resolvedFallback;
|
||||
return new MwMessageBoxColorPalette(
|
||||
resolvedPalette.AccentColor ?? resolvedFallback.AccentColor,
|
||||
resolvedPalette.IconBackgroundColor ?? resolvedFallback.IconBackgroundColor,
|
||||
resolvedPalette.IconForegroundColor ?? resolvedFallback.IconForegroundColor);
|
||||
}
|
||||
|
||||
private static SolidColorBrush CreateBrush(string color)
|
||||
{
|
||||
return (SolidColorBrush)new BrushConverter().ConvertFromString(color);
|
||||
}
|
||||
|
||||
private sealed class MwMessageBoxPaletteBrushes
|
||||
{
|
||||
public MwMessageBoxPaletteBrushes(MwMessageBoxColorPalette palette)
|
||||
{
|
||||
var resolvedPalette = palette ?? MwMessageBoxVisualTheme.CreateDefault().NonePalette;
|
||||
AccentBrush = CreateBrush(resolvedPalette.AccentColor ?? "#9CA3AF");
|
||||
IconBackgroundBrush = CreateBrush(resolvedPalette.IconBackgroundColor ?? "#F3F4F6");
|
||||
IconForegroundBrush = CreateBrush(resolvedPalette.IconForegroundColor ?? "#6B7280");
|
||||
}
|
||||
|
||||
public Brush AccentBrush { get; }
|
||||
|
||||
public Brush IconBackgroundBrush { get; }
|
||||
|
||||
public Brush IconForegroundBrush { get; }
|
||||
|
||||
private static SolidColorBrush CreateBrush(string color)
|
||||
{
|
||||
return (SolidColorBrush)new BrushConverter().ConvertFromString(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
<Window x:Class="MainShell.Common.View.MwMessageBoxWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:common="clr-namespace:MainShell.Common"
|
||||
xmlns:behaviors="clr-namespace:MainShell.Common.Behaviors"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="360"
|
||||
MinHeight="220"
|
||||
MaxWidth="720"
|
||||
SizeToContent="WidthAndHeight"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
AllowsTransparency="True"
|
||||
WindowStyle="None"
|
||||
Background="Transparent"
|
||||
ShowInTaskbar="False"
|
||||
Title="{Binding State.Caption}"
|
||||
FlowDirection="{Binding State.WindowFlowDirection}"
|
||||
UseLayoutRounding="True"
|
||||
SnapsToDevicePixels="True"
|
||||
common:WindowService.DialogResult="{Binding DialogResult}">
|
||||
<Window.Resources>
|
||||
<Style x:Key="MwMessageBoxButtonStyle" TargetType="Button">
|
||||
<Setter Property="Foreground" Value="#374151"/>
|
||||
<Setter Property="Background" Value="#FFFFFF"/>
|
||||
<Setter Property="BorderBrush" Value="#C9D5E5"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="3">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding DataContext.IsPrimary, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
|
||||
<Setter Property="Background" Value="#2E5FA7"/>
|
||||
<Setter Property="BorderBrush" Value="#2E5FA7"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding DataContext.IsPrimary, RelativeSource={RelativeSource TemplatedParent}}" Value="False"/>
|
||||
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="#F5F8FC"/>
|
||||
<Setter Property="BorderBrush" Value="#AFC3DD"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding DataContext.IsPrimary, RelativeSource={RelativeSource TemplatedParent}}" Value="False"/>
|
||||
<Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="#E8EEF6"/>
|
||||
<Setter Property="BorderBrush" Value="#9FB7D6"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding DataContext.IsPrimary, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="#254F8D"/>
|
||||
<Setter Property="BorderBrush" Value="#254F8D"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding DataContext.IsPrimary, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
<Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource TemplatedParent}}" Value="True"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="#1E4174"/>
|
||||
<Setter Property="BorderBrush" Value="#1E4174"/>
|
||||
</MultiDataTrigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="#9CA3AF"/>
|
||||
<Setter Property="Background" Value="#F3F4F6"/>
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MwMessageBoxCaptionStyle" TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="{Binding State.Caption}"/>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Text" Value="">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</Trigger>
|
||||
<Trigger Property="Text" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MwMessageBoxCloseButtonStyle" TargetType="Button">
|
||||
<Setter Property="Width" Value="44"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="Background" Value="#2E5FA7"/>
|
||||
<Setter Property="BorderBrush" Value="#2E5FA7"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C94A4A"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#A53B3B"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Closing">
|
||||
<i:InvokeCommandAction Command="{Binding WindowClosingCommand}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<Border Background="#FFFFFF"
|
||||
CornerRadius="2"
|
||||
BorderBrush="#C6D1DF"
|
||||
BorderThickness="1">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#1F3A5A"
|
||||
BlurRadius="18"
|
||||
ShadowDepth="2"
|
||||
Opacity="0.18"/>
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" Background="#2E5FA7">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0"
|
||||
behaviors:WindowDragMoveBehavior.IsEnabled="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Width="16"
|
||||
Height="16"
|
||||
Margin="10,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="#D8E6F7"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<TextBlock Text="i"
|
||||
Foreground="#FFFFFF"
|
||||
FontSize="11"
|
||||
FontWeight="Bold"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#FFFFFF"
|
||||
FontSize="13"
|
||||
FontWeight="Normal"
|
||||
TextTrimming="CharacterEllipsis">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="{Binding State.Caption}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding State.Caption}" Value="{x:Null}">
|
||||
<Setter Property="Text" Value="{DynamicResource Msg_Title_Info}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding State.Caption}" Value="">
|
||||
<Setter Property="Text" Value="{DynamicResource Msg_Title_Info}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<Button Grid.Column="1"
|
||||
x:Name="CloseButton"
|
||||
Style="{StaticResource MwMessageBoxCloseButtonStyle}"
|
||||
Click="OnCloseButtonClick"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Margin="28,28,28,22">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Width="62"
|
||||
Height="62"
|
||||
HorizontalAlignment="Center"
|
||||
Background="#FFFFFF"
|
||||
BorderBrush="{Binding State.AccentBrush}"
|
||||
BorderThickness="1.5"
|
||||
CornerRadius="31">
|
||||
<Viewbox Width="26"
|
||||
Height="26"
|
||||
Stretch="Uniform">
|
||||
<Path Data="{Binding State.IconPathData}"
|
||||
Fill="{Binding State.IconForegroundBrush}"
|
||||
Stretch="Uniform"/>
|
||||
</Viewbox>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Margin="0,18,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#1F2937"
|
||||
FontSize="17"
|
||||
FontWeight="SemiBold"
|
||||
TextAlignment="Center"
|
||||
Style="{StaticResource MwMessageBoxCaptionStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="2"
|
||||
Margin="0,14,0,0"
|
||||
MaxWidth="540"
|
||||
Text="{Binding State.Message}"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="#4B5563"
|
||||
FontSize="14"
|
||||
LineHeight="23"
|
||||
TextAlignment="Center"
|
||||
FlowDirection="{Binding State.MessageFlowDirection}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#E7EEF7"/>
|
||||
|
||||
<ItemsControl Grid.Row="1"
|
||||
Margin="0,18,0,20"
|
||||
ItemsSource="{Binding State.Buttons}"
|
||||
HorizontalAlignment="Center"
|
||||
MaxWidth="560">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Content="{Binding Text}"
|
||||
MinWidth="96"
|
||||
Height="38"
|
||||
Margin="8,0,8,0"
|
||||
Padding="22,0,22,0"
|
||||
IsDefault="{Binding IsDefault}"
|
||||
IsCancel="{Binding IsCancel}"
|
||||
Style="{Binding ButtonStyle, TargetNullValue={StaticResource MwMessageBoxButtonStyle}}"
|
||||
Command="{Binding DataContext.SelectButtonCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
using MainShell.Common.ViewModel;
|
||||
|
||||
namespace MainShell.Common.View
|
||||
{
|
||||
public partial class MwMessageBoxWindow : Window
|
||||
{
|
||||
public MwMessageBoxWindow(MwMessageBoxWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel ?? throw new System.ArgumentNullException(nameof(viewModel));
|
||||
CloseButton.Content = "\u00D7";
|
||||
}
|
||||
|
||||
private void OnCloseButtonClick(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using MaxwellFramework.Core.Common.Command;
|
||||
using Stylet;
|
||||
|
||||
namespace MainShell.Common.ViewModel
|
||||
{
|
||||
public class MwMessageBoxWindowViewModel : PropertyChangedBase
|
||||
{
|
||||
private bool? _dialogResult;
|
||||
private MessageBoxResult _result;
|
||||
|
||||
public MwMessageBoxWindowViewModel(MwMessageBoxState state)
|
||||
{
|
||||
State = state ?? throw new ArgumentNullException(nameof(state));
|
||||
SelectButtonCommand = new DelegateCommand(OnSelectButton);
|
||||
WindowClosingCommand = new DelegateCommand(OnWindowClosing);
|
||||
}
|
||||
|
||||
public MwMessageBoxState State { get; }
|
||||
|
||||
public bool? DialogResult
|
||||
{
|
||||
get => _dialogResult;
|
||||
set => SetAndNotify(ref _dialogResult, value);
|
||||
}
|
||||
|
||||
public MessageBoxResult Result
|
||||
{
|
||||
get => _result;
|
||||
private set => SetAndNotify(ref _result, value);
|
||||
}
|
||||
|
||||
public ICommand SelectButtonCommand { get; }
|
||||
|
||||
public ICommand WindowClosingCommand { get; }
|
||||
|
||||
private void OnSelectButton(object parameter)
|
||||
{
|
||||
var definition = parameter as MwMessageBoxButtonDefinition;
|
||||
if (definition == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Result = definition.Result;
|
||||
DialogResult = true;
|
||||
}
|
||||
|
||||
private void OnWindowClosing(object parameter)
|
||||
{
|
||||
if (Result != MessageBoxResult.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Result = MwMessageBox.ResolveFallbackResult(State);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
[MarkupExtensionReturnType(typeof(string))]
|
||||
public class PropDescExtension : MarkupExtension
|
||||
{
|
||||
public Type ForType { get; set; }
|
||||
public string Property { get; set; }
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (ForType == null || string.IsNullOrWhiteSpace(Property)) return Property;
|
||||
|
||||
var pd = TypeDescriptor.GetProperties(ForType)[Property];
|
||||
if (pd == null) return Property;
|
||||
|
||||
var desc = pd.Attributes.OfType<DescriptionAttribute>().FirstOrDefault();
|
||||
return string.IsNullOrWhiteSpace(desc?.Description) ? Property : desc.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public class RetryMechanism
|
||||
{
|
||||
// 自定义异常:操作失败
|
||||
public class RetryException : Exception
|
||||
{
|
||||
public RetryException(string message) : base(message) { }
|
||||
}
|
||||
|
||||
public class RetryResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public bool IsAborted { get; set; }
|
||||
|
||||
public int AttemptCount { get; set; }
|
||||
|
||||
public int MaxAttempts { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向后兼容旧接口:默认直接继续重试直到达到最大次数,失败时抛异常。
|
||||
/// 新代码建议优先使用 <see cref="RetryOrThrow(Func{bool}, Func{int, bool}, string, int)"/> 或返回结果对象的重载。
|
||||
/// </summary>
|
||||
public static void RetryIfNeeded(Func<bool> checkCondition, string message, int maxAttempts = 3)
|
||||
{
|
||||
RetryOrThrow(checkCondition, attempt => true, message, maxAttempts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行同步重试并返回结果对象。
|
||||
/// </summary>
|
||||
/// <param name="checkCondition">
|
||||
/// 每次尝试时执行的检查逻辑。
|
||||
/// 返回 <c>true</c> 表示成功,返回 <c>false</c> 表示本次失败并根据 <paramref name="shouldRetry"/> 决定是否继续。
|
||||
/// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。
|
||||
/// </param>
|
||||
/// <param name="shouldRetry">当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。</param>
|
||||
/// <param name="message">操作描述信息。</param>
|
||||
/// <param name="maxAttempts">最大尝试次数,必须大于 0。</param>
|
||||
public static RetryResult RetryIfNeeded(Func<bool> checkCondition, Func<int, bool> shouldRetry, string message, int maxAttempts = 3)
|
||||
{
|
||||
if (checkCondition == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(checkCondition));
|
||||
}
|
||||
|
||||
if (shouldRetry == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shouldRetry));
|
||||
}
|
||||
|
||||
if (maxAttempts <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0.");
|
||||
}
|
||||
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
||||
{
|
||||
bool conditionMet = checkCondition();
|
||||
if (conditionMet)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = true,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
if (attempt == maxAttempts)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
bool continueRetry = shouldRetry(attempt);
|
||||
if (!continueRetry)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
IsAborted = true,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
AttemptCount = maxAttempts,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
// 保留抛异常风格的兼容方法
|
||||
public static void RetryOrThrow(Func<bool> checkCondition, Func<int, bool> shouldRetry, string message, int maxAttempts = 3)
|
||||
{
|
||||
var result = RetryIfNeeded(checkCondition, shouldRetry, message, maxAttempts);
|
||||
EnsureSuccess(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向后兼容旧接口的异步版本:默认直接继续重试直到达到最大次数,失败时抛异常。
|
||||
/// 新代码建议优先使用 <see cref="RetryOrThrowAsync(Func{Task{bool}}, Func{int, Task{bool}}, string, int, CancellationToken)"/> 或返回结果对象的重载。
|
||||
/// </summary>
|
||||
public static async Task RetryIfNeededAsync(Func<Task<bool>> checkConditionAsync, string message, int maxAttempts = 3)
|
||||
{
|
||||
await RetryOrThrowAsync(checkConditionAsync, attempt => Task.FromResult(true), message, maxAttempts, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步重试并返回结果对象。
|
||||
/// </summary>
|
||||
/// <param name="checkConditionAsync">
|
||||
/// 每次尝试时执行的异步检查逻辑。
|
||||
/// 返回 <c>true</c> 表示成功,返回 <c>false</c> 表示本次失败并根据 <paramref name="shouldRetryAsync"/> 决定是否继续。
|
||||
/// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。
|
||||
/// </param>
|
||||
/// <param name="shouldRetryAsync">当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。</param>
|
||||
/// <param name="message">操作描述信息。</param>
|
||||
/// <param name="maxAttempts">最大尝试次数,必须大于 0。</param>
|
||||
/// <param name="cancellationToken">用于取消异步重试流程。</param>
|
||||
public static async Task<RetryResult> RetryIfNeededAsync(Func<Task<bool>> checkConditionAsync, Func<int, Task<bool>> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (checkConditionAsync == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(checkConditionAsync));
|
||||
}
|
||||
|
||||
if (shouldRetryAsync == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shouldRetryAsync));
|
||||
}
|
||||
|
||||
if (maxAttempts <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0.");
|
||||
}
|
||||
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
bool conditionMet = await checkConditionAsync().ConfigureAwait(false);
|
||||
if (conditionMet)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = true,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
if (attempt == maxAttempts)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
bool continueRetry = await shouldRetryAsync(attempt).ConfigureAwait(false);
|
||||
if (!continueRetry)
|
||||
{
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
IsAborted = true,
|
||||
AttemptCount = attempt,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new RetryResult
|
||||
{
|
||||
Succeeded = false,
|
||||
AttemptCount = maxAttempts,
|
||||
MaxAttempts = maxAttempts,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
// 保留抛异常风格的异步兼容方法
|
||||
public static async Task RetryOrThrowAsync(Func<Task<bool>> checkConditionAsync, Func<int, Task<bool>> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var result = await RetryIfNeededAsync(checkConditionAsync, shouldRetryAsync, message, maxAttempts, cancellationToken).ConfigureAwait(false);
|
||||
EnsureSuccess(result);
|
||||
}
|
||||
|
||||
private static void EnsureSuccess(RetryResult result)
|
||||
{
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.IsAborted)
|
||||
{
|
||||
throw new RetryException($"{result.Message} 已中止重试,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}");
|
||||
}
|
||||
|
||||
throw new RetryException($"{result.Message} 已达到最大重试次数,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
class TimeoutRetryMechanism
|
||||
{
|
||||
public class WaitForConditionResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public bool TimedOut { get; set; }
|
||||
|
||||
public bool IsAborted { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在指定超时时间内轮询等待条件成立。
|
||||
/// 当 <paramref name="timeout"/> 为 <c>null</c> 时,表示无限等待,直到条件成立或外部取消。
|
||||
/// </summary>
|
||||
/// <param name="condition">待检查的条件,返回 <c>true</c> 表示条件成立。</param>
|
||||
/// <param name="timeout">最大等待时间。传入 <c>null</c> 表示无限等待;传入具体值时必须大于 0。</param>
|
||||
/// <param name="pollingInterval">轮询间隔,必须大于 0。</param>
|
||||
/// <param name="cancellationToken">用于中止等待流程。</param>
|
||||
public static WaitForConditionResult WaitForConditionWithTimeout(Func<bool> condition, TimeSpan? timeout, TimeSpan pollingInterval, CancellationToken cancellationToken)
|
||||
{
|
||||
if (condition == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(condition));
|
||||
}
|
||||
|
||||
if (timeout.HasValue && timeout.Value <= TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(timeout), "timeout must be greater than zero when specified.");
|
||||
}
|
||||
|
||||
if (pollingInterval <= TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(pollingInterval), "pollingInterval must be greater than zero.");
|
||||
}
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (condition())
|
||||
{
|
||||
return new WaitForConditionResult
|
||||
{
|
||||
Succeeded = true
|
||||
};
|
||||
}
|
||||
|
||||
if (timeout.HasValue && stopwatch.Elapsed > timeout.Value)
|
||||
{
|
||||
return new WaitForConditionResult
|
||||
{
|
||||
Succeeded = false,
|
||||
TimedOut = true
|
||||
};
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return new WaitForConditionResult
|
||||
{
|
||||
Succeeded = false,
|
||||
IsAborted = true
|
||||
};
|
||||
}
|
||||
|
||||
Thread.Sleep(pollingInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<Window x:Class="MainShell.Common.View.CameraSettingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.Common.View"
|
||||
xmlns:custom="clr-namespace:MainShell.Resources.CustomControl" xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
Title="相机设置"
|
||||
Width="450" SizeToContent="Height"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="NoResize"
|
||||
WindowStyle="ToolWindow"
|
||||
d:DesignHeight="300" d:DesignWidth="350">
|
||||
<StackPanel Margin="5">
|
||||
<!-- 相机参数设置 -->
|
||||
<GroupBox Header="{DynamicResource CameraPar}" Margin="0,0,0,5" Style="{StaticResource GroupBoxSecondary}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 曝光时间 -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="曝光时间:" VerticalAlignment="Center" Style="{StaticResource LabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Row="0" Grid.Column="1"
|
||||
Value="{Binding CameraConfig.ExposureTime}"
|
||||
Minimum="10" Maximum="1000000"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
HorizontalContentAlignment="Right" Margin="5,2,0,2"/>
|
||||
|
||||
<!-- 增益 -->
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="增益:" VerticalAlignment="Center" Style="{StaticResource LabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Row="1" Grid.Column="1"
|
||||
Value="{Binding CameraConfig.Gain}"
|
||||
Minimum="1" Maximum="100"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
HorizontalContentAlignment="Right" Margin="5,2,0,2"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 光源参数设置 -->
|
||||
<!-- 使用 ItemsControl 动态生成 LightControl,需要 ViewModel 提供光源通道列表 -->
|
||||
<GroupBox Header="{DynamicResource LightSetting}" Style="{StaticResource GroupBoxSecondary}">
|
||||
<ItemsControl ItemsSource="{Binding LightChannels}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<custom:LightControl Header="{Binding Name}"
|
||||
Value="{Binding Value, Mode=TwoWay}"
|
||||
Min="0" Max="255" Margin="0,2"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</GroupBox>
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button Content="{DynamicResource GetParameter}" Style="{StaticResource TeachButtonStyle}" Margin="5" IsDefault="True" Command="{Binding ReadFromHardwareCommand}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.Common.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraSettingsControl.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraSettingsView : Window
|
||||
{
|
||||
public CameraSettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Models;
|
||||
using MwFramework.Controls.ControlCanvas;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MainShell.Common.ViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 单个光源通道的包装类
|
||||
/// </summary>
|
||||
public class LightChannelViewModel : PropertyChangedBase
|
||||
{
|
||||
private readonly object _sourceConfig;
|
||||
private readonly PropertyInfo _propertyInfo;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => (int)_propertyInfo.GetValue(_sourceConfig);
|
||||
set
|
||||
{
|
||||
if (value != Value)
|
||||
{
|
||||
_propertyInfo.SetValue(_sourceConfig, value);
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LightChannelViewModel(object sourceConfig, PropertyInfo propertyInfo, string displayName)
|
||||
{
|
||||
_sourceConfig = sourceConfig;
|
||||
_propertyInfo = propertyInfo;
|
||||
Name = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 相机及光源参数设置弹窗 ViewModel
|
||||
/// </summary>
|
||||
public class CameraSettingsViewModel : Screen
|
||||
{
|
||||
private readonly IWindowManager _windowManager;
|
||||
private readonly HardwareManager _hardwareManager;
|
||||
|
||||
// 核心标志位:是否正在从硬件同步数据
|
||||
private bool _isSyncingFromHardware;
|
||||
|
||||
private CameraType _currentCameraType;
|
||||
private object _currentLightConfig;
|
||||
|
||||
private CameraConfig _cameraConfig;
|
||||
public CameraConfig CameraConfig
|
||||
{
|
||||
get => _cameraConfig;
|
||||
set => SetAndNotify(ref _cameraConfig, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<LightChannelViewModel> _lightChannels;
|
||||
public ObservableCollection<LightChannelViewModel> LightChannels
|
||||
{
|
||||
get => _lightChannels;
|
||||
set => SetAndNotify(ref _lightChannels, value);
|
||||
}
|
||||
|
||||
public ICommand ReadFromHardwareCommand { get; }
|
||||
public ICommand SaveAndCloseCommand { get; }
|
||||
|
||||
public CameraSettingsViewModel(IWindowManager windowManager, HardwareManager hardwareManager)
|
||||
{
|
||||
_windowManager = windowManager;
|
||||
_hardwareManager = hardwareManager;
|
||||
|
||||
ReadFromHardwareCommand = new DelegateCommand(ReadFromHardware);
|
||||
SaveAndCloseCommand = new DelegateCommand(SaveAndClose);
|
||||
DisplayName = "相机光源参数设置";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化并绑定数据
|
||||
/// </summary>
|
||||
public void Initialize(CameraConfig cameraConfig, object lightConfig, CameraType cameraType)
|
||||
{
|
||||
// 1. 解绑旧对象的事件(如果有)
|
||||
if (CameraConfig != null) CameraConfig.PropertyChanged -= OnConfigPropertyChanged;
|
||||
if (_currentLightConfig is INotifyPropertyChanged oldLight) oldLight.PropertyChanged -= OnConfigPropertyChanged;
|
||||
|
||||
_currentCameraType = cameraType;
|
||||
CameraConfig = cameraConfig;
|
||||
_currentLightConfig = lightConfig;
|
||||
|
||||
// 2. 重新订阅事件
|
||||
if (CameraConfig != null) CameraConfig.PropertyChanged += OnConfigPropertyChanged;
|
||||
if (_currentLightConfig is INotifyPropertyChanged newLight) newLight.PropertyChanged += OnConfigPropertyChanged;
|
||||
|
||||
// 3. 生成光源通道列表
|
||||
LightChannels = new ObservableCollection<LightChannelViewModel>();
|
||||
if (lightConfig != null)
|
||||
{
|
||||
var properties = lightConfig.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
if (prop.PropertyType == typeof(int) && prop.CanRead && prop.CanWrite)
|
||||
{
|
||||
var descAttr = prop.GetCustomAttribute<DescriptionAttribute>();
|
||||
// 必须有 Description 才认为是光源通道
|
||||
if (descAttr != null)
|
||||
{
|
||||
var vm = new LightChannelViewModel(lightConfig, prop, descAttr.Description);
|
||||
LightChannels.Add(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一处理属性变更事件 => 设置硬件
|
||||
/// </summary>
|
||||
private void OnConfigPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
// 关键逻辑:如果是从硬件读取过程中,则忽略,不要反向设置回去
|
||||
if (_isSyncingFromHardware) return;
|
||||
|
||||
ApplySettingToHardware(sender, e.PropertyName);
|
||||
}
|
||||
|
||||
private void ApplySettingToHardware(object source, string propertyName)
|
||||
{
|
||||
// 1. 设置相机参数
|
||||
if (source == CameraConfig)
|
||||
{
|
||||
// TODO: 替换为实际的 set 相机参数代码
|
||||
/*
|
||||
var camDevice = _hardwareManager.GetCamera(_currentCameraType);
|
||||
if (propertyName == nameof(CameraConfig.ExposureTime))
|
||||
{
|
||||
camDevice.SetExposure(CameraConfig.ExposureTime);
|
||||
}
|
||||
else if (propertyName == nameof(CameraConfig.Gain))
|
||||
{
|
||||
camDevice.SetGain(CameraConfig.Gain);
|
||||
}
|
||||
*/
|
||||
System.Diagnostics.Debug.WriteLine($"[Hardware Set] Cam: {_currentCameraType}, Prop: {propertyName}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 设置光源参数 (根据类型直接判断)
|
||||
if (source is MapCamLightConfig mapConfig)
|
||||
{
|
||||
if (propertyName == nameof(MapCamLightConfig.RedLight))
|
||||
{
|
||||
// TODO: _hardwareManager.SetMapRedLight(mapConfig.RedLight);
|
||||
System.Diagnostics.Debug.WriteLine($"[Hardware Set] MapCam Red: {mapConfig.RedLight}");
|
||||
}
|
||||
else if (propertyName == nameof(MapCamLightConfig.BlueLight))
|
||||
{
|
||||
// TODO: _hardwareManager.SetMapBlueLight(mapConfig.BlueLight);
|
||||
System.Diagnostics.Debug.WriteLine($"[Hardware Set] MapCam Blue: {mapConfig.BlueLight}");
|
||||
}
|
||||
}
|
||||
else if (source is UpCamLightConfig upConfig)
|
||||
{
|
||||
if (propertyName == nameof(UpCamLightConfig.PointRedLight))
|
||||
{
|
||||
// TODO: _hardwareManager.SetUpPointRed(upConfig.PointRedLight);
|
||||
System.Diagnostics.Debug.WriteLine($"[Hardware Set] UpCam PointRed: {upConfig.PointRedLight}");
|
||||
}
|
||||
else if (propertyName == nameof(UpCamLightConfig.RingRedLight))
|
||||
{
|
||||
// TODO: ...
|
||||
}
|
||||
// ... 处理其他 UpCam 通道
|
||||
}
|
||||
else if (source is DownCamLightConfig downConfig)
|
||||
{
|
||||
if (propertyName == nameof(DownCamLightConfig.PointRedLight))
|
||||
{
|
||||
// TODO: ...
|
||||
}
|
||||
// ... 处理其他 DownCam 通道
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从硬件读取当前值 => 更新 UI (不触发设置)
|
||||
/// </summary>
|
||||
private void ReadFromHardware()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isSyncingFromHardware = true; // 开启静默模式
|
||||
|
||||
// 1. 读取相机实际参数
|
||||
/*
|
||||
var camDevice = _hardwareManager.GetCamera(_currentCameraType);
|
||||
if (camDevice != null) {
|
||||
CameraConfig.ExposureTime = (int)camDevice.CurrentExposure;
|
||||
CameraConfig.Gain = (int)camDevice.CurrentGain;
|
||||
}
|
||||
*/
|
||||
|
||||
// 2. 读取光源实际参数
|
||||
if (_currentLightConfig is MapCamLightConfig mapConfig)
|
||||
{
|
||||
// TODO: 读取实际硬件值
|
||||
mapConfig.RedLight = _hardwareManager.GetMapRedLightIntensity();
|
||||
mapConfig.BlueLight = _hardwareManager.GetMapBlueLightIntensity();
|
||||
}
|
||||
else if (_currentLightConfig is UpCamLightConfig upConfig)
|
||||
{
|
||||
upConfig.PointRedLight = _hardwareManager.GetUpPointRedLightIntensity();
|
||||
upConfig.PointBlueLight=_hardwareManager.GetUpPointBlueLightIntensity();
|
||||
upConfig.RingRedLight=_hardwareManager.GetUpRingRedLightIntensity();
|
||||
upConfig.RingBlueLight=_hardwareManager.GetUpRingBlueLightIntensity();
|
||||
upConfig.RedBackLight=_hardwareManager.GetUpRedBackLightIntensity();
|
||||
// ...
|
||||
}
|
||||
else if (_currentLightConfig is DownCamLightConfig downConfig)
|
||||
{
|
||||
// downConfig.PointRedLight = ...
|
||||
downConfig.PointRedLight = _hardwareManager.GetDownPointRedLightIntensity();
|
||||
downConfig.PointBlueLight = _hardwareManager.GetDownPointBlueLightIntensity();
|
||||
downConfig.RingRedLight = _hardwareManager.GetDownRingRedLightIntensity();
|
||||
downConfig.RingBlueLight = _hardwareManager.GetDownRingBlueLightIntensity();
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var channel in LightChannels)
|
||||
{
|
||||
// 强制刷新 UI
|
||||
channel.Refresh();
|
||||
}
|
||||
_isSyncingFromHardware = false; // 必须复位
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveAndClose()
|
||||
{
|
||||
RequestClose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<UserControl x:Class="MainShell.Common.VisionTemple.View.VisionTempleView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.Common.VisionTemple.View" xmlns:control="http://www.maxwell.com/controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
|
||||
<control:CameraVision DataContext="{Binding Service}" Name="cameraVision">
|
||||
<control:CameraVision.CameraHost>
|
||||
<control:CameraAxisControlA
|
||||
Items="{Binding CameraModel.CameraShowViewModel.Items}"
|
||||
Source="{Binding CameraModel.CameraShowViewModel.CurrentImage, Mode=OneWay}"
|
||||
TabSelectedIndex="{Binding SelectCameraIndex}"
|
||||
Cameras="{Binding Cameras}"
|
||||
Device="{Binding SelectItem}"
|
||||
ImportFile="{Binding CameraModel.ImportFile}"
|
||||
Regions="{Binding CameraModel.CameraShowViewModel.Regions}"
|
||||
IsClear="{Binding CameraModel.CameraShowViewModel.IsClear}"
|
||||
IsShowContext="True"
|
||||
ShapeThickness="1" IsShowSolidLine="True" DrawInConcurrency = "False"/>
|
||||
</control:CameraVision.CameraHost>
|
||||
</control:CameraVision>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.Common.VisionTemple.View
|
||||
{
|
||||
/// <summary>
|
||||
/// VisionTempleView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class VisionTempleView : UserControl
|
||||
{
|
||||
public VisionTempleView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Window x:Class="MainShell.Common.VisionTemple.View.VisionTempleWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:view="clr-namespace:MainShell.Common.VisionTemple.View"
|
||||
mc:Ignorable="d"
|
||||
Title="{Binding DisplayName}"
|
||||
Height="875"
|
||||
Width="1000"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Background="White">
|
||||
<Grid Background="White">
|
||||
<view:VisionTempleView DataContext="{Binding VisionTemple}" />
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Common.VisionTemple.View
|
||||
{
|
||||
/// <summary>
|
||||
/// VisionTempleWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class VisionTempleWindow : Window
|
||||
{
|
||||
public VisionTempleWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using MwFramework.Controls.PatternTemplate.ViewModel;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common.VisionTemple.ViewModel
|
||||
{
|
||||
public class VisionTempleViewModel : Screen
|
||||
{
|
||||
public string Name { get; set; } = "VisionTempleModel";
|
||||
|
||||
private MatchTemplateService _service;
|
||||
|
||||
public MatchTemplateService Service
|
||||
{
|
||||
get { return _service; }
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
OnPropertyChanged(nameof(Service));
|
||||
}
|
||||
}
|
||||
|
||||
public VisionTempleViewModel()
|
||||
{
|
||||
_service = new MatchTemplateService();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using MainShell.Common.VisionTemple.View;
|
||||
using MainShell.Hardware;
|
||||
using Stylet;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Common.VisionTemple.ViewModel
|
||||
{
|
||||
public class VisionTempleWindowViewModel : Screen
|
||||
{
|
||||
private readonly VisionTempleViewModel _visionTemple;
|
||||
private VisionTempleWindow _window;
|
||||
private bool _isShuttingDown;
|
||||
private readonly HardwareManager _hardwareManager;
|
||||
|
||||
public VisionTempleWindowViewModel(HardwareManager hardwareManager)
|
||||
{
|
||||
DisplayName = "视觉模板制作";
|
||||
_visionTemple = new VisionTempleViewModel();
|
||||
_visionTemple.Service = new MwFramework.Controls.PatternTemplate.ViewModel.MatchTemplateService();
|
||||
_visionTemple.Service.CameraModel.IsShowFoldDialog = false;
|
||||
_hardwareManager = hardwareManager;
|
||||
}
|
||||
|
||||
private string _templatePath;
|
||||
/// <summary>
|
||||
/// 模版路径
|
||||
/// </summary>
|
||||
public string TemplatePath
|
||||
{
|
||||
get { return _templatePath; }
|
||||
set
|
||||
{
|
||||
_templatePath = value;
|
||||
_visionTemple.Service.CameraModel.TemplatePath = value;
|
||||
}
|
||||
}
|
||||
|
||||
public VisionTempleViewModel VisionTemple
|
||||
{
|
||||
get
|
||||
{
|
||||
return _visionTemple;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCamera(CameraType cameraType)
|
||||
{
|
||||
switch (cameraType)
|
||||
{
|
||||
case CameraType.MapCamera:
|
||||
_visionTemple.Service.Cameras = _hardwareManager.CameraAxisManager.BottomCameraAxisDevices;
|
||||
break;
|
||||
case CameraType.TopPositionCamera:
|
||||
_visionTemple.Service.Cameras = _hardwareManager.CameraAxisManager.TopCameraAxisDevices;
|
||||
break;
|
||||
case CameraType.TopWideCamera:
|
||||
_visionTemple.Service.Cameras = _hardwareManager.CameraAxisManager.WideCameraAxisDevices;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(_visionTemple.Service.Cameras!=null&& _visionTemple.Service.Cameras.Count>0)
|
||||
{
|
||||
_visionTemple.Service.SelectItem = _visionTemple.Service.Cameras[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
{
|
||||
_window = new VisionTempleWindow();
|
||||
_window.DataContext = this;
|
||||
_window.Closing += OnWindowClosing;
|
||||
}
|
||||
|
||||
Window owner = Application.Current != null ? Application.Current.MainWindow : null;
|
||||
if (owner != null && _window.Owner == null)
|
||||
{
|
||||
_window.Owner = owner;
|
||||
owner.Closing += OnOwnerClosing;
|
||||
}
|
||||
|
||||
if (_window.IsVisible)
|
||||
{
|
||||
if (_window.WindowState == WindowState.Minimized)
|
||||
{
|
||||
_window.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
_window.Activate();
|
||||
return;
|
||||
}
|
||||
|
||||
_window.Show();
|
||||
_window.Activate();
|
||||
}
|
||||
|
||||
private void OnWindowClosing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (!_isShuttingDown)
|
||||
{
|
||||
e.Cancel = true;
|
||||
_window.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOwnerClosing(object sender, CancelEventArgs e)
|
||||
{
|
||||
_isShuttingDown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public class WindowService
|
||||
{
|
||||
// 定义一个名为 DialogResult 的附加属性
|
||||
public static readonly DependencyProperty DialogResultProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"DialogResult",
|
||||
typeof(bool?),
|
||||
typeof(WindowService),
|
||||
new PropertyMetadata(DialogResultChanged)); // 当此属性值改变时,调用 DialogResultChanged 方法
|
||||
|
||||
// 提供 Set 方法供外部设置附加属性的值
|
||||
public static void SetDialogResult(UIElement element, bool? value)
|
||||
{
|
||||
element.SetValue(DialogResultProperty, value);
|
||||
}
|
||||
|
||||
// 提供 Get 方法供外部获取附加属性的值
|
||||
public static bool? GetDialogResult(UIElement element)
|
||||
{
|
||||
return (bool?)element.GetValue(DialogResultProperty);
|
||||
}
|
||||
|
||||
// 当 DialogResult 附加属性的值改变时调用的回调方法
|
||||
private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
// 确保附加属性应用在一个 Window 控件上,并且新的值是 bool 类型
|
||||
if (d is Window window && e.NewValue is bool result)
|
||||
{
|
||||
// 设置窗口的 DialogResult
|
||||
window.DialogResult = result;
|
||||
// 关闭窗口
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Common
|
||||
{
|
||||
public static class WorkflowContextKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于传递 IEventAggregator 实例
|
||||
/// </summary>
|
||||
public const string EventAggregator = "EventAggregator";
|
||||
|
||||
/// <summary>
|
||||
/// 用于传递请求令牌 (Guid)
|
||||
/// </summary>
|
||||
public const string RequestToken = "RequestToken";
|
||||
/// <summary>
|
||||
/// 当前配方
|
||||
/// </summary>
|
||||
public const string RecipeManager = "RecipeManager";
|
||||
/// <summary>
|
||||
/// 流程结果管理器 Key
|
||||
/// </summary>
|
||||
public const string ProcessResultManager = "ProcessResultManager";
|
||||
|
||||
/// <summary>
|
||||
/// 恢复目标活动名称
|
||||
/// </summary>
|
||||
public const string ResumeTargetActivityName="ResumeTargetActivityName";
|
||||
|
||||
/// <summary>
|
||||
/// 流程名称
|
||||
/// </summary>
|
||||
public const string WorkflowName = "WorkflowName";
|
||||
|
||||
/// <summary>
|
||||
/// 当前步骤ID
|
||||
/// </summary>
|
||||
public const string CurrentStepId = "CurrentStepId";
|
||||
|
||||
/// <summary>
|
||||
/// 下一步骤ID
|
||||
/// </summary>
|
||||
public const string NextStepId = "NextStepId";
|
||||
|
||||
/// <summary>
|
||||
/// 流程路由配置
|
||||
/// </summary>
|
||||
public const string WorkflowRoutes = "WorkflowRoutes";
|
||||
|
||||
/// <summary>
|
||||
/// 晶片转移路由
|
||||
/// </summary>
|
||||
public const string DieTransferRoute = "DieTransferRoute";
|
||||
|
||||
/// <summary>
|
||||
/// 自动生产路由
|
||||
/// </summary>
|
||||
public const string AutoProductionRoute = "AutoProductionRoute";
|
||||
|
||||
/// <summary>
|
||||
/// 流程运行时追踪器
|
||||
/// </summary>
|
||||
public const string WorkflowRuntimeTracker = "WorkflowRuntimeTracker";
|
||||
|
||||
/// <summary>
|
||||
/// 流程失败消息
|
||||
/// </summary>
|
||||
public const string WorkflowFailureMessage = "WorkflowFailureMessage";
|
||||
|
||||
/// <summary>
|
||||
/// 流程失败消息键
|
||||
/// </summary>
|
||||
public const string WorkflowFailureMessageKey = "WorkflowFailureMessageKey";
|
||||
|
||||
/// <summary>
|
||||
/// 流程失败消息参数
|
||||
/// </summary>
|
||||
public const string WorkflowFailureMessageArguments = "WorkflowFailureMessageArguments";
|
||||
|
||||
/// <summary>
|
||||
/// 准备区服务
|
||||
/// </summary>
|
||||
public const string PreparationAreaService = "PreparationAreaService";
|
||||
|
||||
/// <summary>
|
||||
/// 当前晶片状态服务
|
||||
/// </summary>
|
||||
public const string CurrentChipStateService = "CurrentChipStateService";
|
||||
|
||||
/// <summary>
|
||||
/// 自动生产运行时状态服务
|
||||
/// </summary>
|
||||
public const string AutoProductionRuntimeStateService = "AutoProductionRuntimeStateService";
|
||||
|
||||
/// <summary>
|
||||
/// 准备区状态
|
||||
/// </summary>
|
||||
public const string PreparationAreaStatus = "PreparationAreaStatus";
|
||||
|
||||
/// <summary>
|
||||
/// 当前晶片状态
|
||||
/// </summary>
|
||||
public const string CurrentChipState = "CurrentChipState";
|
||||
|
||||
/// <summary>
|
||||
/// 基板处理状态
|
||||
/// </summary>
|
||||
public const string SubstrateProcessState = "SubstrateProcessState";
|
||||
|
||||
/// <summary>
|
||||
/// 待加载晶片
|
||||
/// </summary>
|
||||
public const string PendingChipLoad = "PendingChipLoad";
|
||||
|
||||
/// <summary>
|
||||
/// 当前基板待处理数量
|
||||
/// </summary>
|
||||
public const string CurrentSubstratePendingCount = "CurrentSubstratePendingCount";
|
||||
|
||||
/// <summary>
|
||||
/// 当前基板已处理数量
|
||||
/// </summary>
|
||||
public const string CurrentSubstrateProcessedCount = "CurrentSubstrateProcessedCount";
|
||||
|
||||
/// <summary>
|
||||
/// 当前晶片剩余数量
|
||||
/// </summary>
|
||||
public const string CurrentChipRemainingCount = "CurrentChipRemainingCount";
|
||||
|
||||
/// <summary>
|
||||
/// 转移需要重新检查
|
||||
/// </summary>
|
||||
public const string TransferNeedsRecheck = "TransferNeedsRecheck";
|
||||
|
||||
/// <summary>
|
||||
/// 转移晶片已耗尽
|
||||
/// </summary>
|
||||
public const string TransferChipExhausted = "TransferChipExhausted";
|
||||
|
||||
/// <summary>
|
||||
/// 晶片转移决策结果
|
||||
/// </summary>
|
||||
public const string DieTransferDecisionResult = "DieTransferDecisionResult";
|
||||
|
||||
/// <summary>
|
||||
/// 晶片转移路径生成请求
|
||||
/// </summary>
|
||||
public const string DieTransferPathRequest = "DieTransferPathRequest";
|
||||
|
||||
/// <summary>
|
||||
/// 晶片转移路径生成结果
|
||||
/// </summary>
|
||||
public const string DieTransferPathPlan = "DieTransferPathPlan";
|
||||
|
||||
/// <summary>
|
||||
/// 当前父级活动/子流程名称
|
||||
/// </summary>
|
||||
public const string ParentActivityName = "ParentActivityName";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀次数
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationTouchCount = "NeedleZCalibrationTouchCount";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀完成后是否自动抬高
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationAutoRaiseZ1 = "NeedleZCalibrationAutoRaiseZ1";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀取消令牌
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationCancellationToken = "NeedleZCalibrationCancellationToken";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀工作流请求数据
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationWorkflowData = "NeedleZCalibrationWorkflowData";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀结果集合
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationResults = "NeedleZCalibrationResults";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀最后一次结果
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationLastResult = "NeedleZCalibrationLastResult";
|
||||
|
||||
/// <summary>
|
||||
/// 针头Z对刀平均结果
|
||||
/// </summary>
|
||||
public const string NeedleZCalibrationAverageResult = "NeedleZCalibrationAverageResult";
|
||||
|
||||
/// <summary>
|
||||
/// 基板定位结果
|
||||
/// </summary>
|
||||
public const string SubstratePositionResult = "SubstratePositionResult";
|
||||
|
||||
/// <summary>
|
||||
/// 芯片定位结果
|
||||
/// </summary>
|
||||
public const string DiePositionResult = "DiePositionResult";
|
||||
|
||||
/// <summary>
|
||||
/// 芯片定位运行态上下文
|
||||
/// </summary>
|
||||
public const string DiePositionContext = "DiePositionContext";
|
||||
|
||||
/// <summary>
|
||||
/// 芯片定位扫描规划结果
|
||||
/// </summary>
|
||||
public const string DiePositionScanPlan = "DiePositionScanPlan";
|
||||
|
||||
/// <summary>
|
||||
/// 基板测高结果
|
||||
/// </summary>
|
||||
public const string SubstrateHeightMeasureResult = "SubstrateHeightMeasureResult";
|
||||
|
||||
/// <summary>
|
||||
/// 精度复检结果
|
||||
/// </summary>
|
||||
public const string DieRecheckResult = "DieRecheckResult";
|
||||
|
||||
/// <summary>
|
||||
/// 基板Mark识别服务
|
||||
/// </summary>
|
||||
public const string SubstrateMarkRecognitionService = "SubstrateMarkRecognitionService";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,581 @@
|
||||
<?xml version="1.0"?>
|
||||
<ArrayOfPersistenceObject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<PersistenceObject xsi:type="AxisCardPO">
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>AcsCard</CategoryName>
|
||||
<ID>2d23c400-ccf2-469a-add5-ae92a98a85e6</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardPO.xml</ConfigPath>
|
||||
<AxisCardType>DEMO</AxisCardType>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<PortNo>0</PortNo>
|
||||
<ListAxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-X1</CategoryName>
|
||||
<ID>3a9c772b-4a9c-4077-abbc-80fc038b81ee</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>0</AxisNum>
|
||||
<AxisName>PHS-X1</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-X2</CategoryName>
|
||||
<ID>c83e5f81-ef2c-413c-ace9-24bc97c30b32</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>1</AxisNum>
|
||||
<AxisName>PHS-X2</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>WS-X3</CategoryName>
|
||||
<ID>e0a2d6ed-2972-4595-a8dc-53a504187a9f</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>4</AxisNum>
|
||||
<AxisName>WS-X3</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Y1</CategoryName>
|
||||
<ID>4e145d2a-f7f7-4ce2-a5b0-919375a03d87</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>2</AxisNum>
|
||||
<AxisName>PHS-Y1</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>WS-R</CategoryName>
|
||||
<ID>cebe7f5c-8cdd-47e8-906a-6083047a078d</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>6</AxisNum>
|
||||
<AxisName>WS-R</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>SZ</CategoryName>
|
||||
<ID>ce1f8f65-3409-4124-9c9a-ba750c848e36</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>8</AxisNum>
|
||||
<AxisName>SZ</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-Y3</CategoryName>
|
||||
<ID>05dfa6d1-401b-4a55-808b-5af2efeb358c</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>AcsCard</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>7</AxisNum>
|
||||
<AxisName>Stage-Y3</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
</ListAxisCardParaPO>
|
||||
<Version>1</Version>
|
||||
<Core>0</Core>
|
||||
<CrossCompensate>0</CrossCompensate>
|
||||
<IsServoSeparate>false</IsServoSeparate>
|
||||
</PersistenceObject>
|
||||
<PersistenceObject xsi:type="AxisCardPO">
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Plc</CategoryName>
|
||||
<ID>80a2e320-d4da-46a6-9f35-0a6d0996ea22</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardPO.xml</ConfigPath>
|
||||
<AxisCardType>DEMO</AxisCardType>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<PortNo>0</PortNo>
|
||||
<ListAxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Z1</CategoryName>
|
||||
<ID>471e0395-0918-4e0b-b9cb-d0727281ef6c</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>0</AxisNum>
|
||||
<AxisName>PHS-Z1</AxisName>
|
||||
<Direction>Z</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Z3</CategoryName>
|
||||
<ID>5dd115ab-09a4-4bbb-9fdf-e9b76cc5e88e</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>1</AxisNum>
|
||||
<AxisName>PHS-Z3</AxisName>
|
||||
<Direction>Z</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Z4</CategoryName>
|
||||
<ID>e359bc21-c1e8-4e06-acdb-1df94ee7931b</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>10</AxisNum>
|
||||
<AxisName>PHS-Z4</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Z5</CategoryName>
|
||||
<ID>9d948211-59ae-498c-b124-531a69855752</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>2</AxisNum>
|
||||
<AxisName>PHS-Z5</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>PHS-Z6</CategoryName>
|
||||
<ID>477c569a-e460-4c45-917f-a0744ebed5ec</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>11</AxisNum>
|
||||
<AxisName>PHS-Z6</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-Z7</CategoryName>
|
||||
<ID>f761791c-8fb4-4a5b-8fef-0380e996e81f</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>7</AxisNum>
|
||||
<AxisName>Stage-Z7</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-Z8</CategoryName>
|
||||
<ID>28a1caa3-01bc-48ed-8551-68829b280a6f</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>8</AxisNum>
|
||||
<AxisName>Stage-Z8</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-Z9</CategoryName>
|
||||
<ID>71c8587a-1e85-4fa4-8809-14f00111a230</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>9</AxisNum>
|
||||
<AxisName>Stage-Z9</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-Z10</CategoryName>
|
||||
<ID>fc66c8d2-c35f-46b5-9c14-f3a017311e86</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>14</AxisNum>
|
||||
<AxisName>Stage-Z10</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-CV-Y4</CategoryName>
|
||||
<ID>6ebf862a-c91e-4bb2-a5b7-e67f307333b4</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>15</AxisNum>
|
||||
<AxisName>Stage-CV-Y4</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>Stage-CV-Y5</CategoryName>
|
||||
<ID>e1cf2e06-fe51-4115-8ad2-2a0b3dc53c00</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>16</AxisNum>
|
||||
<AxisName>Stage-CV-Y5</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>WEU-Z11</CategoryName>
|
||||
<ID>a765e366-03a3-451f-ab44-1e6129a6ac61</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>3</AxisNum>
|
||||
<AxisName>WEU-Z11</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>WEU-Z12</CategoryName>
|
||||
<ID>a4c43082-6841-45b4-83f2-b89a952a6547</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>4</AxisNum>
|
||||
<AxisName>WEU-Z12</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>WEU-Y6</CategoryName>
|
||||
<ID>670409e3-1e19-45c8-94b8-1f3fb1905dc2</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>5</AxisNum>
|
||||
<AxisName>WEU-Y6</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>CV-Z13</CategoryName>
|
||||
<ID>eb009565-40bf-4923-9b9b-fdf483dc1532</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>6</AxisNum>
|
||||
<AxisName>CV-Z13</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>CV-Y7</CategoryName>
|
||||
<ID>d75ee50a-ba99-4ec1-bb36-6e65cbd84180</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>18</AxisNum>
|
||||
<AxisName>CV-Y7</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>CV-Y8</CategoryName>
|
||||
<ID>8845c4e8-4d09-4f0a-b073-1b29e1ca59e6</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>19</AxisNum>
|
||||
<AxisName>CV-Y8</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>CV-Y9</CategoryName>
|
||||
<ID>4970be79-b46a-4004-84bf-82e922fb5cb8</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>20</AxisNum>
|
||||
<AxisName>CV-Y9</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
<AxisCardParaPO>
|
||||
<AlarmOffset>0</AlarmOffset>
|
||||
<CategoryName>CV-Y10</CategoryName>
|
||||
<ID>36583278-40bd-48ad-a749-02b4e58dcbca</ID>
|
||||
<EnableLog>false</EnableLog>
|
||||
<ConfigPath>AxisCardParaPO.xml</ConfigPath>
|
||||
<AxisCardId>0</AxisCardId>
|
||||
<AxisCardName>Plc</AxisCardName>
|
||||
<AxisCardNum>0</AxisCardNum>
|
||||
<AxisNum>21</AxisNum>
|
||||
<AxisName>CV-Y10</AxisName>
|
||||
<Direction>X</Direction>
|
||||
<GoogalCore>0</GoogalCore>
|
||||
<GoogalAxisNum>0</GoogalAxisNum>
|
||||
<GoolgalPosErr>0</GoolgalPosErr>
|
||||
<HomeDir>0</HomeDir>
|
||||
<EscapeStep>0</EscapeStep>
|
||||
<HomeMode>HOME_MODE_ERROR</HomeMode>
|
||||
<HomeCheck>false</HomeCheck>
|
||||
<MaxCheckPos>0.001</MaxCheckPos>
|
||||
</AxisCardParaPO>
|
||||
</ListAxisCardParaPO>
|
||||
<Version>1</Version>
|
||||
<Core>0</Core>
|
||||
<CrossCompensate>0</CrossCompensate>
|
||||
<IsServoSeparate>false</IsServoSeparate>
|
||||
</PersistenceObject>
|
||||
</ArrayOfPersistenceObject>
|
||||
@@ -0,0 +1,9 @@
|
||||
# 气缸定义表
|
||||
# 列顺序:Name,Module,ControlType,ExtendOutputIds,RetractOutputIds,ExtendedFeedbackIds,RetractedFeedbackIds,Description
|
||||
# ControlType: SingleOutput / DualOutput / MultiOutput
|
||||
# ExtendOutputIds / RetractOutputIds / ExtendedFeedbackIds / RetractedFeedbackIds 支持填写多个 IO 引用,使用分号分隔
|
||||
# IO 引用优先使用 Configuration\DeviceIoPoints.csv 中的 Name;若 Id 在全表唯一,也兼容旧 Id 写法
|
||||
Name,Module,ControlType,ExtendOutputIds,RetractOutputIds,ExtendedFeedbackIds,RetractedFeedbackIds,Description
|
||||
WS θ夹紧气缸,WS,SingleOutput,PG.WS.ThetaClampCylAct,,PG.WS.ThetaClampCyl1WorkPos;PG.WS.ThetaClampCyl2WorkPos;PG.WS.ThetaClampCyl3WorkPos;PG.WS.ThetaClampCyl4WorkPos,PG.WS.ThetaClampCyl1HomePos;PG.WS.ThetaClampCyl2HomePos;PG.WS.ThetaClampCyl3HomePos;PG.WS.ThetaClampCyl4HomePos,WS θ 夹紧气缸总动作输出,对应 4 组伸出/缩回反馈
|
||||
WS θ刹车压紧气缸,WS,SingleOutput,PG.WS.ThetaBrakePressCylAct,,,,当前 DeviceIoPoints.csv 未配置到位反馈
|
||||
Stage 顶升同步气缸,Stage,MultiOutput,PG.Stage.LifterCyl1Act;PG.Stage.LifterCyl2Act,,PG.Stage.LifterCyl1WorkPos;PG.Stage.LifterCyl2WorkPos,PG.Stage.LifterCyl1HomePos;PG.Stage.LifterCyl2HomePos,Stage 顶升气缸1和2同步动作,统一伸出/缩回
|
||||
|
@@ -0,0 +1,97 @@
|
||||
# Device IO 定义表
|
||||
# 列顺序:Id Module Name Type Card StationNo LineNo Enabled DefaultValue IsInverse Description
|
||||
# Module: 业务模块名(如 SubstrateLoad/ChipLoad/SubstrateOut/ChipUnload)
|
||||
# Type: Input/Output (也支持 IN/OUT/DI/DO)
|
||||
# Card: Td/Acs
|
||||
# StationNo: 台达站号
|
||||
# LineNo: 实际接线线标/号码管标识
|
||||
# Enabled: 1/0 或 true/false
|
||||
# DefaultValue: 当 IO 未启用或无法读取时使用的默认状态,1/0 或 true/false
|
||||
Id,Module,Name,Type,Card,StationNo,LineNo,Enabled,DefaultValue,IsInverse,Description
|
||||
0,WZ,PG.WZ.StartButton,Input,Td,1,X00100,1,1,0,WZ 启动按钮
|
||||
1,WZ,PG.WZ.StopButton,Input,Td,1,X00101,1,1,0,WZ 停止按钮
|
||||
2,WZ,PG.WZ.ResetButton,Input,Td,1,X00102,1,1,0,WZ 复位按钮
|
||||
3,WZ,PG.WZ.EmergencyStopButton,Input,Td,1,X00103,1,1,0,WZ 急停按钮
|
||||
4,WZ,PG.WZ.BlueButton,Input,Td,1,X00104,1,1,0,WZ 蓝色按钮(预留)
|
||||
5,Stage,PG.Stage.ToolSetterSignal,Input,Td,1,X00105,1,1,0,Stage 对刀信号
|
||||
6,Stage,PG.Stage.SubstrateInPlace,Input,Td,1,X00106,1,1,0,Stage 基板到位感应
|
||||
7,Stage,PG.Stage.LifterCyl1WorkPos,Input,Td,1,X00107,1,1,0,Stage 顶升气缸1动点
|
||||
8,Stage,PG.Stage.LifterCyl1HomePos,Input,Td,1,X00108,1,1,0,Stage 顶升气缸1原点
|
||||
9,Stage,PG.Stage.LifterCyl2WorkPos,Input,Td,1,X00109,1,1,0,Stage 顶升气缸2动点
|
||||
10,Stage,PG.Stage.LifterCyl2HomePos,Input,Td,1,X00110,1,1,0,Stage 顶升气缸2原点
|
||||
11,WS,PG.WS.ThetaClampCyl1WorkPos,Input,Td,1,X00111,1,1,0,WS θ夹紧气缸1动点
|
||||
12,WS,PG.WS.ThetaClampCyl1HomePos,Input,Td,1,X00112,1,1,0,WS θ夹紧气缸1原点
|
||||
13,WS,PG.WS.ThetaClampCyl2WorkPos,Input,Td,1,X00113,1,1,0,WS θ夹紧气缸2动点
|
||||
14,WS,PG.WS.ThetaClampCyl2HomePos,Input,Td,1,X00114,1,1,0,WS θ夹紧气缸2原点
|
||||
15,WS,PG.WS.ThetaClampCyl3WorkPos,Input,Td,1,X00115,1,1,0,WS θ夹紧气缸3动点
|
||||
0,WS,PG.WS.ThetaClampCyl3HomePos,Input,Td,2,X00200,1,1,0,WS θ夹紧气缸3原点
|
||||
1,WS,PG.WS.ThetaClampCyl4WorkPos,Input,Td,2,X00201,1,1,0,WS θ夹紧气缸4动点
|
||||
2,WS,PG.WS.ThetaClampCyl4HomePos,Input,Td,2,X00202,1,1,0,WS θ夹紧气缸4原点
|
||||
3,WS,PG.WS.ThetaTrayPresentSensor1,Input,Td,2,X00203,1,1,0,WS θ料盘有无感应1
|
||||
4,WS,PG.WS.ThetaTrayPresentSensor2,Input,Td,2,X00204,1,1,0,WS θ料盘有无感应2
|
||||
5,WS,PG.WS.ThetaTrayPresentSensor3,Input,Td,2,X00205,1,1,0,WS θ料盘有无感应3
|
||||
6,WS,PG.WS.ThetaTrayPresentSensor4,Input,Td,2,X00206,1,1,0,WS θ料盘有无感应4
|
||||
7,WS,PG.WS.BondHead1InPlace,Input,Td,2,X00207,1,1,0,WS 刺晶头1在位
|
||||
8,WS,PG.WS.BondHead2InPlace,Input,Td,2,X00208,1,1,0,WS 刺晶头2在位
|
||||
9,WS,PG.WS.BondHead3InPlace,Input,Td,2,X00209,1,1,0,WS 刺晶头3在位
|
||||
10,WS,PG.WS.BondHead4InPlace,Input,Td,2,X00210,1,1,0,WS 刺晶头4在位
|
||||
11,WEU,PG.WEU.Z11MaterialSensor1,Input,Td,2,X00211,1,1,0,WEU Z11 有无料感应1
|
||||
12,WEU,PG.WEU.Z11MaterialSensor2,Input,Td,2,X00212,1,1,0,WEU Z11 有无料感应2
|
||||
13,WEU,PG.WEU.Z12MaterialSensor3,Input,Td,2,X00213,1,1,0,WEU Z12 有无料感应3
|
||||
14,WEU,PG.WEU.Z12MaterialSensor4,Input,Td,2,X00214,1,1,0,WEU Z12 有无料感应4
|
||||
0,CV,PG.CV.UpperInletSensor,Input,Td,3,X00300,1,1,0,CV 上层进料感应
|
||||
1,CV,PG.CV.UpperInPlaceSensor,Input,Td,3,X00301,1,1,0,CV 上层到位感应
|
||||
2,CV,PG.CV.LowerOutletSensor,Input,Td,3,X00302,1,1,0,CV 下层出料感应
|
||||
3,CV,PG.CV.LowerInPlaceSensor,Input,Td,3,X00303,1,1,0,CV 下层到位感应
|
||||
4,WZ,PG.WZ.SafetyDoor1Closed,Input,Td,3,X00304,1,1,0,WZ 安全门1关门检测
|
||||
5,WZ,PG.WZ.SafetyDoor2Closed,Input,Td,3,X00305,1,1,0,WZ 安全门2关门检测
|
||||
6,WZ,PG.WZ.SafetyDoor3Closed,Input,Td,3,X00306,1,1,0,WZ 安全门3关门检测
|
||||
7,WZ,PG.WZ.SafetyDoor4Closed,Input,Td,3,X00307,1,1,0,WZ 安全门4关门检测
|
||||
8,WZ,PG.WZ.SecurityDoorShield,Input,Td,3,X00308,1,1,0,WZ 安全门屏蔽
|
||||
10,General,PG.General.PhaseLossSensor,Input,Td,3,X00310,1,1,0,缺相检测
|
||||
11,General,PG.General.SafetyCircuitStatus1,Input,Td,3,X00311,1,1,0,安全回路状态1
|
||||
12,General,PG.General.SafetyCircuitStatus2,Input,Td,3,X00312,1,1,0,安全回路状态2
|
||||
13,CV,PG.CV.IonWindRodAlarmDetection,Input,Td,3,X00313,1,1,0,CV 离子风棒报警检测
|
||||
14,EFEM,PG.EFEM.IonWindRodAlarmDetection1,Input,Td,3,X00314,1,1,0,EFEM离子风棒报警检测1
|
||||
15,EFEM,PG.EFEM.IonWindRodAlarmDetection2,Input,Td,3,X00315,1,1,0,EFEM离子风棒报警检测2
|
||||
0,AxisZ,PG.AxisZ.Z1GuideRailBrake,Output,Td,4,Y00100,1,1,0,Z1轴导轨抱闸
|
||||
1,AxisZ,PG.AxisZ.Z3CameraAirCooling,Output,Td,4,Y00101,1,1,0,Z3相机气冷
|
||||
2,AxisZ,PG.AxisZ.Z5CameraAirCooling,Output,Td,4,Y00102,1,1,0,Z5相机气冷
|
||||
3,AxisZ,PG.AxisZ.Z10CameraAirCooling,Output,Td,4,Y00103,1,1,0,Z10相机气冷
|
||||
4,AxisZ,PG.AxisZ.Z2BondHeadAirCooling,Output,Td,4,Y00104,1,1,0,Z2刺晶头气冷
|
||||
5,CV,PG.CV.IonBarAct,Output,Td,4,Y00105,1,1,0,CV 离子风棒
|
||||
6,WEU,PG.WEU.IonBarAct1,Output,Td,4,Y00106,1,1,0,WEU离子风棒1
|
||||
7,WEU,PG.WEU.IonBarAct2,Output,Td,4,Y00107,1,1,0,WEU离子风棒2
|
||||
8,WS,PG.WS.ThetaClampCylAct,Output,Td,4,Y00108,1,1,0,WS θ 夹紧气缸动作
|
||||
9,WS,PG.WS.ThetaBrakePressCylAct,Output,Td,4,Y00109,1,1,0,WS θ 刹车压紧气缸动作
|
||||
10,Stage,PG.Stage.LifterCyl1Act,Output,Td,4,Y00110,1,1,0,Stage 顶升气缸1动作
|
||||
11,Stage,PG.Stage.LifterCyl2Act,Output,Td,4,Y00111,1,1,0,Stage 顶升气缸2动作
|
||||
0,WZ,PG.WZ.StartButtonLight,Output,Td,5,Y00200,1,1,0,WZ 启动按钮灯
|
||||
1,WZ,PG.WZ.StopButtonLight,Output,Td,5,Y00201,1,1,0,WZ 停止按钮灯
|
||||
2,WZ,PG.WZ.ResetButtonLight,Output,Td,5,Y00202,1,1,0,WZ 复位按钮灯
|
||||
3,WZ,PG.WZ.BlueButtonLight,Output,Td,5,Y00203,1,1,0,WZ 蓝色按钮灯
|
||||
4,WZ,PG.WZ.WorkLight1,Output,Td,5,Y00204,1,1,0,WZ 照明灯1
|
||||
6,EFEM,PG.EFEM.WorkLight1,Output,Td,5,Y00206,1,1,0,EFEM 照明灯1
|
||||
8,WZ,PG.WZ.StackLightRed,Output,Td,5,Y00208,1,1,0,WZ 四色灯-红
|
||||
9,WZ,PG.WZ.StackLightYellow,Output,Td,5,Y00209,1,1,0,WZ 四色灯-黄
|
||||
10,WZ,PG.WZ.StackLightGreen,Output,Td,5,Y00210,1,1,0,WZ 四色灯-绿
|
||||
11,WZ,PG.WZ.StackLightBlue,Output,Td,5,Y00211,1,1,0,WZ 四色灯-蓝
|
||||
12,WZ,PG.WZ.BuzzerAct,Output,Td,5,Y00212,1,1,0,WZ 蜂鸣器
|
||||
0,Stage,PG.Stage.BreakingTheVacuum1,Output,Td,6,Y00300,1,1,0,Stage 破真空1
|
||||
1,Stage,PG.Stage.BreakingTheVacuum2,Output,Td,6,Y00301,1,1,0,STAGE 破真空2
|
||||
2,Stage,PG.Stage.BreakingTheVacuum3,Output,Td,6,Y00302,1,1,0,STAGE 破真空3
|
||||
3,Stage,PG.Stage.BreakingTheVacuum4,Output,Td,6,Y00303,1,1,0,STAGE 破真空4
|
||||
4,WEU,PG.WEU.TrayBreakVacuum1,Output,Td,6,Y00304,1,1,0,WEU 料盘破真空1
|
||||
5,WEU,PG.WEU.TrayBreakVacuum2,Output,Td,6,Y00305,1,1,0,WEU 料盘破真空2
|
||||
6,AxisZ,PG.AxisZ.Z2BondHeadBreakVacuum,Output,Td,6,Y00306,1,1,0,PHS Z2 刺晶头破真空
|
||||
7,Stage,PG.Stage.Vacuum1,Output,Td,6,Y00307,1,1,0,STAGE 吸真空1
|
||||
8,Stage,PG.Stage.Vacuum2,Output,Td,6,Y00308,1,1,0,STAGE 吸真空2
|
||||
9,Stage,PG.Stage.Vacuum3,Output,Td,6,Y00309,1,1,0,STAGE 吸真空3
|
||||
10,Stage,PG.Stage.Vacuum4,Output,Td,6,Y00310,1,1,0,STAGE 吸真空4
|
||||
11,WEU,PG.WEU.TrayVacuum1,Output,Td,6,Y00311,1,1,0,WEU 料盘吸真空1
|
||||
12,WEU,PG.WEU.TrayVacuum2,Output,Td,6,Y00312,1,1,0,WEU 料盘吸真空2
|
||||
13,AxisZ,PG.AxisZ.Z2BondHeadVacuum,Output,Td,6,Y00313,1,1,0,PHS Z2 刺晶头吸真空
|
||||
1,WZ,PG.WZ.SafetyDoor1Open,Output,Td,7,Y00401,1,1,0,WZ 安全门1打开
|
||||
2,WZ,PG.WZ.SafetyDoor2Open,Output,Td,7,Y00402,1,1,0,WZ 安全门2打开
|
||||
3,WZ,PG.WZ.SafetyDoor3Open,Output,Td,7,Y00402,1,1,0,WZ 安全门3打开
|
||||
4,WZ,PG.WZ.SafetyDoor4Open,Output,Td,7,Y00403,1,1,0,WZ 安全门4打开
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Layout Version="1.0.0.1" WindowHeight="1024" WindowWidth="1280" MachineId="12345678901234567">
|
||||
<Header Title="PG-A1">
|
||||
<HeaderItem Id="HideEMO"/>
|
||||
<HeaderItem Id="HideCIMStatus"/>
|
||||
</Header>
|
||||
<Body>
|
||||
<StatusBar>
|
||||
<StatusLight Name="设备一" LangName="Device" Binding="Device"></StatusLight>
|
||||
</StatusBar>
|
||||
<Pages>
|
||||
<Page Name="主页" LangName="PageHome" Target="Home">
|
||||
</Page>
|
||||
<Page Name="配方" LangName="PageRecipe" Target="Recipe">
|
||||
|
||||
</Page>
|
||||
<Page Name="参数设置" LangName="PageSettings" Target="PageSettings" DisabledState="SemiAutomatic;Automatic" UserRightId="PageSettings">
|
||||
</Page>
|
||||
<Page Name="设备维护" LangName="MenuDeviceMaint" Target="MenuDeviceMaint" DisabledState="SemiAutomatic;Automatic" UserRightId="PageSettings">
|
||||
</Page>
|
||||
<Page Name="标定与校准" LangName="PageCalib" Target="PageCalib" DisabledState="SemiAutomatic;Automatic" UserRightId="PageCalib">
|
||||
</Page>
|
||||
<Page Name="半自动" LangName="ManualModeOperation" Target="ManualOperate">
|
||||
|
||||
</Page>
|
||||
</Pages>
|
||||
|
||||
</Body>
|
||||
<Footer Target="Footer"/>
|
||||
</Layout>
|
||||
@@ -0,0 +1,28 @@
|
||||
using MainShell.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class BondingPathModeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
BondingPathMode speedMode = (BondingPathMode)value;
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
|
||||
return mode == (int)speedMode ? true : false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
return (BondingPathMode)mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using MainShell.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class BondingRegionModeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
BondingStagePathMode speedMode = (BondingStagePathMode)value;
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
|
||||
return mode == (int)speedMode ? true : false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
return (BondingStagePathMode)mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using MainShell.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class BondingWsPathModeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
BondingWSPathMode speedMode = (BondingWSPathMode)value;
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
|
||||
return mode == (int)speedMode ? true : false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
return (BondingWSPathMode)mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class BoolToInversionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return !System.Convert.ToBoolean(value);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class BoolToVisibleConverter : IValueConverter
|
||||
{
|
||||
// 将 bool (或可转换为 bool 的值) 转换为 Visibility
|
||||
// parameter 支持:
|
||||
// 包含 "invert" / "inverse" / "not" / "!" 的字符串 — 反转布尔值
|
||||
// 包含 "hidden" 的字符串 — 当为 false 时返回 Visibility.Hidden 而不是 Collapsed
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
bool isVisible = false;
|
||||
|
||||
if (value is bool b)
|
||||
{
|
||||
isVisible = b;
|
||||
}
|
||||
else if (value is bool?)
|
||||
{
|
||||
isVisible = ((bool?)value) ?? false;
|
||||
}
|
||||
else if (value is string s)
|
||||
{
|
||||
bool.TryParse(s, out isVisible);
|
||||
}
|
||||
else if (value != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
isVisible = System.Convert.ToBoolean(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
var paramString = parameter as string;
|
||||
bool invert = false;
|
||||
bool useHidden = false;
|
||||
if (!string.IsNullOrEmpty(paramString))
|
||||
{
|
||||
var p = paramString.ToLowerInvariant();
|
||||
if (p.Contains("invert") || p.Contains("inverse") || p.Contains("not") || p.Contains("!"))
|
||||
invert = true;
|
||||
if (p.Contains("hidden"))
|
||||
useHidden = true;
|
||||
}
|
||||
|
||||
if (invert)
|
||||
isVisible = !isVisible;
|
||||
|
||||
return isVisible ? Visibility.Visible : (useHidden ? Visibility.Hidden : Visibility.Collapsed);
|
||||
}
|
||||
|
||||
// 将 Visibility 转换回 bool
|
||||
// Visible => true;Hidden/Collapsed => false
|
||||
// 支持与 Convert 相同的 parameter 反转语义
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (!(value is Visibility))
|
||||
return Binding.DoNothing;
|
||||
|
||||
var vis = (Visibility)value;
|
||||
bool result = vis == Visibility.Visible;
|
||||
|
||||
var paramString = parameter as string;
|
||||
if (!string.IsNullOrEmpty(paramString))
|
||||
{
|
||||
var p = paramString.ToLowerInvariant();
|
||||
if (p.Contains("invert") || p.Contains("inverse") || p.Contains("not") || p.Contains("!"))
|
||||
result = !result;
|
||||
}
|
||||
|
||||
if (targetType == typeof(bool) || targetType == typeof(object))
|
||||
return result;
|
||||
if (targetType == typeof(bool?))
|
||||
return (bool?)result;
|
||||
|
||||
try
|
||||
{
|
||||
return System.Convert.ChangeType(result, targetType);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class DateTimeToStringConverter : IValueConverter
|
||||
{
|
||||
public string Format { get; set; } = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null) return string.Empty;
|
||||
if (!(value is DateTime dt)) return string.Empty;
|
||||
if (dt == DateTime.MinValue) return string.Empty;
|
||||
|
||||
// parameter 优先用于临时格式覆盖
|
||||
var fmt = parameter as string ?? Format;
|
||||
return dt.ToString(fmt, culture);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
// XAML 中可直接写 {conv:EnumBindingSource {x:Type local:MyEnum}}
|
||||
public class EnumBindingSourceExtension : MarkupExtension
|
||||
{
|
||||
public Type EnumType { get; set; }
|
||||
public bool UseDescription { get; set; } = true;
|
||||
|
||||
public EnumBindingSourceExtension() { }
|
||||
|
||||
public EnumBindingSourceExtension(Type enumType)
|
||||
{
|
||||
EnumType = enumType;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (EnumType == null || !EnumType.IsEnum) return null;
|
||||
|
||||
var values = Enum.GetValues(EnumType).Cast<Enum>();
|
||||
return values.Select(v => new EnumItem
|
||||
{
|
||||
Value = v,
|
||||
Description = UseDescription ? EnumHelper.GetEnumDescription(v) : v.ToString()
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumItem
|
||||
{
|
||||
public Enum Value { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int IntValue => Convert.ToInt32(Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取枚举类型的Description描述信息
|
||||
/// </summary>
|
||||
public class EnumDescriptionConverter : IValueConverter
|
||||
{
|
||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value.ToString() != "")
|
||||
{
|
||||
Enum myEnum = (Enum)value;
|
||||
string description = EnumHelper.GetEnumDescription(myEnum);
|
||||
return description;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumToBool : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (int)value == (int)parameter;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if ((bool)value)
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EnumHelper
|
||||
{
|
||||
public static string GetEnumDescription(Enum enumObj)
|
||||
{
|
||||
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
|
||||
var descriptionAttr = fieldInfo
|
||||
.GetCustomAttributes(false)
|
||||
.OfType<DescriptionAttribute>()
|
||||
.Cast<DescriptionAttribute>()
|
||||
.SingleOrDefault();
|
||||
if (descriptionAttr == null)
|
||||
{
|
||||
return enumObj.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return descriptionAttr.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class ObjectToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using MainShell.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class RunningModeEnumToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
RunningMode speedMode = (RunningMode)value;
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
|
||||
return mode == (int)speedMode ? true : false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
|
||||
int mode = System.Convert.ToInt32(parameter.ToString());
|
||||
return (RunningMode)mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
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 MainShell.Converter
|
||||
{
|
||||
public class ScreenToViewModelConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null) return null;
|
||||
|
||||
var viewModelType = value.GetType();
|
||||
var viewName = viewModelType.FullName.Replace("ViewModel", "View");
|
||||
var viewType = Type.GetType(viewName);
|
||||
|
||||
if (viewType != null)
|
||||
{
|
||||
// 创建View实例,并设置其DataContext为当前的ViewModel
|
||||
var view = (FrameworkElement)Activator.CreateInstance(viewType);
|
||||
view.DataContext = value;
|
||||
return view;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using MainShell.Recipe.Models.SubstrateParameter;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MainShell.Converter
|
||||
{
|
||||
public class SubstrateHeightMeasureModeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var mode = value is SubstrateHeightMeasureMode measureMode ? measureMode : SubstrateHeightMeasureMode.StandardTeachPosition;
|
||||
var parameterValue = System.Convert.ToInt32(parameter, CultureInfo.InvariantCulture);
|
||||
|
||||
return parameterValue == (int)mode;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (!(value is bool isChecked) || !isChecked)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
|
||||
var parameterValue = System.Convert.ToInt32(parameter, CultureInfo.InvariantCulture);
|
||||
return (SubstrateHeightMeasureMode)parameterValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
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 MainShell.Converter
|
||||
{
|
||||
public class WidthToMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
double actualWidth = 0;
|
||||
if (value is double d) actualWidth = d;
|
||||
|
||||
double expanded = 200;
|
||||
double extra = 0;
|
||||
|
||||
if (parameter is string s)
|
||||
{
|
||||
var parts = s.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 1 && double.TryParse(parts[0], out var p0)) expanded = p0;
|
||||
if (parts.Length >= 2 && double.TryParse(parts[1], out var p1)) extra = p1;
|
||||
}
|
||||
|
||||
// 计算右侧 Margin:
|
||||
// 当 actualWidth == expanded 时返回 0(不偏移)
|
||||
// 当 actualWidth 减小时会返回正值,从而把 ToggleButton 向左推(或根据需要调整公式)
|
||||
double right = Math.Max(0, expanded - actualWidth) + extra;
|
||||
|
||||
// 根据布局需要你可以修改这里返回的 Thickness 的哪一项(Left/Right)
|
||||
return new Thickness(-30, 0, 0, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
public enum CylinderControlType
|
||||
{
|
||||
SingleOutput = 0,
|
||||
DualOutput = 1,
|
||||
MultiOutput = 2
|
||||
}
|
||||
|
||||
public enum CylinderConditionType
|
||||
{
|
||||
PointOn = 0,
|
||||
PointOff = 1
|
||||
}
|
||||
|
||||
public class CylinderActionConditionDefinition
|
||||
{
|
||||
public CylinderConditionType ConditionType { get; set; }
|
||||
public string PointReference { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public bool ExpectedState => ConditionType == CylinderConditionType.PointOn;
|
||||
}
|
||||
|
||||
public class CylinderDefinition
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Module { get; set; }
|
||||
public CylinderControlType ControlType { get; set; }
|
||||
public List<string> ExtendOutputPoints { get; set; } = new List<string>();
|
||||
public List<string> RetractOutputPoints { get; set; } = new List<string>();
|
||||
public List<string> ExtendedFeedbackPoints { get; set; } = new List<string>();
|
||||
public List<string> RetractedFeedbackPoints { get; set; } = new List<string>();
|
||||
public List<CylinderActionConditionDefinition> ExtendConditions { get; set; } = new List<CylinderActionConditionDefinition>();
|
||||
public List<CylinderActionConditionDefinition> RetractConditions { get; set; } = new List<CylinderActionConditionDefinition>();
|
||||
|
||||
public bool HasRetractOutputs => RetractOutputPoints != null && RetractOutputPoints.Count > 0;
|
||||
}
|
||||
|
||||
public class CylinderExecutionResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string FailureReason { get; set; }
|
||||
public IReadOnlyList<string> FailurePointReferences { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
public static class CylinderDefinitionLoader
|
||||
{
|
||||
private const string CylinderConfigFileName = "CylinderDefinitions.csv";
|
||||
|
||||
public static IReadOnlyList<CylinderDefinition> LoadDefinitions()
|
||||
{
|
||||
var definitions = new List<CylinderDefinition>();
|
||||
var path = ResolveConfigPath();
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
{
|
||||
return definitions;
|
||||
}
|
||||
|
||||
var lines = File.ReadAllLines(path, Encoding.UTF8);
|
||||
foreach (var raw in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var line = raw.Trim();
|
||||
if (line.StartsWith("#") || line.StartsWith("Name", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cols = line.Split(',');
|
||||
if (cols.Length < 7)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var extendOutputPoints = ParsePointReferences(cols[3]);
|
||||
if (extendOutputPoints.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var retractOutputPoints = ParsePointReferences(cols[4]);
|
||||
|
||||
var hasConditionColumns = cols.Length >= 10;
|
||||
var extendConditionIndex = hasConditionColumns ? 7 : -1;
|
||||
var retractConditionIndex = hasConditionColumns ? 8 : -1;
|
||||
var descriptionIndex = hasConditionColumns ? 9 : 7;
|
||||
|
||||
definitions.Add(new CylinderDefinition
|
||||
{
|
||||
Name = cols[0].Trim(),
|
||||
Module = cols[1].Trim(),
|
||||
ControlType = ParseControlType(cols[2]),
|
||||
ExtendOutputPoints = extendOutputPoints,
|
||||
RetractOutputPoints = retractOutputPoints,
|
||||
ExtendedFeedbackPoints = ParsePointReferences(cols[5]),
|
||||
RetractedFeedbackPoints = ParsePointReferences(cols[6]),
|
||||
ExtendConditions = extendConditionIndex >= 0 ? ParseConditions(cols[extendConditionIndex]) : new List<CylinderActionConditionDefinition>(),
|
||||
RetractConditions = retractConditionIndex >= 0 ? ParseConditions(cols[retractConditionIndex]) : new List<CylinderActionConditionDefinition>(),
|
||||
Description = cols.Length > descriptionIndex ? string.Join(",", cols.Skip(descriptionIndex)).Trim() : string.Empty
|
||||
});
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
private static CylinderControlType ParseControlType(string raw)
|
||||
{
|
||||
if (string.Equals(raw, "DualOutput", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(raw, "Dual", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CylinderControlType.DualOutput;
|
||||
}
|
||||
|
||||
if (string.Equals(raw, "MultiOutput", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(raw, "Multi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CylinderControlType.MultiOutput;
|
||||
}
|
||||
|
||||
return CylinderControlType.SingleOutput;
|
||||
}
|
||||
|
||||
private static List<string> ParsePointReferences(string raw)
|
||||
{
|
||||
return (raw ?? string.Empty)
|
||||
.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim())
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static List<CylinderActionConditionDefinition> ParseConditions(string raw)
|
||||
{
|
||||
return (raw ?? string.Empty)
|
||||
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(ParseCondition)
|
||||
.Where(x => x != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static CylinderActionConditionDefinition ParseCondition(string raw)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parts = raw.Split(new[] { ':' }, 3);
|
||||
if (parts.Length < 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pointReference = parts[1].Trim();
|
||||
if (string.IsNullOrWhiteSpace(pointReference))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CylinderConditionType conditionType;
|
||||
switch ((parts[0] ?? string.Empty).Trim().ToUpperInvariant())
|
||||
{
|
||||
case "POINTON":
|
||||
case "ON":
|
||||
conditionType = CylinderConditionType.PointOn;
|
||||
break;
|
||||
case "POINTOFF":
|
||||
case "OFF":
|
||||
conditionType = CylinderConditionType.PointOff;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CylinderActionConditionDefinition
|
||||
{
|
||||
ConditionType = conditionType,
|
||||
PointReference = pointReference,
|
||||
Message = parts.Length > 2 ? parts[2].Trim() : string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private static string ResolveConfigPath()
|
||||
{
|
||||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var localPath = Path.Combine(baseDir, "Configuration", CylinderConfigFileName);
|
||||
var sourcePath = ResolveRootConfigPath(baseDir);
|
||||
|
||||
if (TrySyncConfigToLocal(sourcePath, localPath))
|
||||
{
|
||||
return localPath;
|
||||
}
|
||||
|
||||
return File.Exists(localPath) ? localPath : sourcePath;
|
||||
}
|
||||
|
||||
private static string ResolveRootConfigPath(string baseDir)
|
||||
{
|
||||
var current = new DirectoryInfo(baseDir);
|
||||
while (current != null)
|
||||
{
|
||||
var rootConfigDir = Path.Combine(current.FullName, "Configuration");
|
||||
if (Directory.Exists(rootConfigDir) && Directory.Exists(Path.Combine(current.FullName, "MainShell")))
|
||||
{
|
||||
var path = Path.Combine(rootConfigDir, CylinderConfigFileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool TrySyncConfigToLocal(string sourcePath, string localPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(Path.GetFullPath(sourcePath), Path.GetFullPath(localPath), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
if (!string.IsNullOrWhiteSpace(localDir))
|
||||
{
|
||||
Directory.CreateDirectory(localDir);
|
||||
}
|
||||
|
||||
if (!File.Exists(localPath) || File.GetLastWriteTimeUtc(localPath) < File.GetLastWriteTimeUtc(sourcePath))
|
||||
{
|
||||
File.Copy(sourcePath, localPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
public class DeviceMaintanceBaseViewModel : Screen
|
||||
{
|
||||
public event Action<bool> UiStateChangedEvent = null;
|
||||
|
||||
protected void OnUiStateChanged(bool uiStateChanged)
|
||||
{
|
||||
UiStateChangedEvent?.Invoke(uiStateChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using MainShell.Filewritable;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
public class LaserCompensationSetting : MXJM.FileWritable.JsonFileWritableBase, INotifyPropertyChanged
|
||||
{
|
||||
private string _axisName = "Axis_Stage_Y3";
|
||||
public string AxisName
|
||||
{
|
||||
get { return _axisName; }
|
||||
set { SetAndNotify(ref _axisName, value); }
|
||||
}
|
||||
|
||||
private double _startPos;
|
||||
public double StartPos
|
||||
{
|
||||
get { return _startPos; }
|
||||
set { SetAndNotify(ref _startPos, value); }
|
||||
}
|
||||
|
||||
private double _steps = 1.0d;
|
||||
public double Steps
|
||||
{
|
||||
get { return _steps; }
|
||||
set { SetAndNotify(ref _steps, value); }
|
||||
}
|
||||
|
||||
private int _stepsCount = 5;
|
||||
public int StepsCount
|
||||
{
|
||||
get { return _stepsCount; }
|
||||
set { SetAndNotify(ref _stepsCount, value); }
|
||||
}
|
||||
|
||||
private double _jumpPos = 1.0d;
|
||||
public double JumpPos
|
||||
{
|
||||
get { return _jumpPos; }
|
||||
set { SetAndNotify(ref _jumpPos, value); }
|
||||
}
|
||||
|
||||
private int _workCount = 1;
|
||||
public int WorkCount
|
||||
{
|
||||
get { return _workCount; }
|
||||
set { SetAndNotify(ref _workCount, value); }
|
||||
}
|
||||
|
||||
private double _speed = 5.0d;
|
||||
public double Speed
|
||||
{
|
||||
get { return _speed; }
|
||||
set { SetAndNotify(ref _speed, value); }
|
||||
}
|
||||
|
||||
private double _dwellTime = 0.5d;
|
||||
public double DwellTime
|
||||
{
|
||||
get { return _dwellTime; }
|
||||
set { SetAndNotify(ref _dwellTime, value); }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override string Dir => Paths.CalibSettingPath;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string FileName => "LaserCompensationSetting.json";
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public void LoadFromFile()
|
||||
{
|
||||
Read();
|
||||
}
|
||||
|
||||
public void SaveToFile()
|
||||
{
|
||||
Write();
|
||||
}
|
||||
|
||||
protected bool SetAndNotify<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (Equals(field, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
field = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Filewritable;
|
||||
using MaxwellControl.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
public enum MaintanceType
|
||||
{
|
||||
针尖维护 = 1,
|
||||
相机校验 = 2,
|
||||
针印验证 = 3,
|
||||
}
|
||||
public class MaintanceRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备编号
|
||||
/// </summary>
|
||||
public string DeviceId { get; set; }
|
||||
/// <summary>
|
||||
/// 设备名称
|
||||
/// </summary>
|
||||
public string DeviceName { get; set; }
|
||||
/// <summary>
|
||||
/// 维护时间
|
||||
/// </summary>
|
||||
public DateTime MaintanceTime { get; set; }
|
||||
/// <summary>
|
||||
/// 维护内容
|
||||
/// </summary>
|
||||
public MaintanceType MaintanceType { get; set; }
|
||||
|
||||
public void WriteToFile(string info)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Paths.MaintanceRecordDir))
|
||||
{
|
||||
Directory.CreateDirectory(Paths.MaintanceRecordDir);
|
||||
}
|
||||
string filePath = Path.Combine(Paths.MaintanceRecordDir, $"{MaintanceType}_MaintanceRecord.txt");
|
||||
using (var writer = new System.IO.StreamWriter(filePath, true))
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
writer.WriteLine("设备ID,日期,信息");
|
||||
}
|
||||
writer.WriteLine($"{DeviceId},{DateTime.Now}: {info}");
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"写入文件失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,757 @@
|
||||
using MwFramework.Controls.UIControl;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
[Export(typeof(IParameter))]
|
||||
public class NeedleCalibrationSetting : ParameterBase
|
||||
{
|
||||
public NeedleZCalibrationItem NeedleZCalibrationItem { get; set; } = new NeedleZCalibrationItem();
|
||||
|
||||
public NeedleXYCalibrationItem NeedleXYCalibrationItem { get; set; } = new NeedleXYCalibrationItem();
|
||||
|
||||
public NeedleXYCalibrationItemNew NeedleXYCalibrationItemNew { get; set; } = new NeedleXYCalibrationItemNew();
|
||||
|
||||
public override void Copy(IParameter source)
|
||||
{
|
||||
NeedleCalibrationSetting setting = source as NeedleCalibrationSetting;
|
||||
if (setting != null)
|
||||
{
|
||||
ReflectionExtension.Copy<NeedleZCalibrationItem>(NeedleZCalibrationItem, setting.NeedleZCalibrationItem);
|
||||
ReflectionExtension.Copy<NeedleXYCalibrationItem>(NeedleXYCalibrationItem, setting.NeedleXYCalibrationItem);
|
||||
ReflectionExtension.Copy<NeedleXYCalibrationItemNew>(NeedleXYCalibrationItemNew, setting.NeedleXYCalibrationItemNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NeedleZCalibrationItem : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
|
||||
private double _supportPinPositionX;
|
||||
[WatchValue("针尖对准对刀仪X1位置")]
|
||||
public double SupportPinPositionX
|
||||
{
|
||||
get { return _supportPinPositionX; }
|
||||
set { if (_supportPinPositionX != value) { _supportPinPositionX = value; OnPropertyChanged(nameof(SupportPinPositionX)); } }
|
||||
}
|
||||
|
||||
private double _supportPinPositionY;
|
||||
[WatchValue("针尖对准对刀仪Y1位置")]
|
||||
public double SupportPinPositionY
|
||||
{
|
||||
get { return _supportPinPositionY; }
|
||||
set { if (_supportPinPositionY != value) { _supportPinPositionY = value; OnPropertyChanged(nameof(SupportPinPositionY)); } }
|
||||
}
|
||||
|
||||
private double _knifeOffset;
|
||||
[WatchValue("对刀仪偏差")]
|
||||
/// <summary>
|
||||
/// 对刀仪偏差
|
||||
/// </summary>
|
||||
public double KnifeOffset
|
||||
{
|
||||
get { return _knifeOffset; }
|
||||
set { if (_knifeOffset != value) { _knifeOffset = value; OnPropertyChanged(nameof(KnifeOffset)); } }
|
||||
}
|
||||
|
||||
private double _cZHeight = -0.725;
|
||||
[WatchValue("SZ高度")]
|
||||
public double CZHeight
|
||||
{
|
||||
get { return _cZHeight; }
|
||||
set { if (_cZHeight != value) { _cZHeight = value; OnPropertyChanged(nameof(CZHeight)); } }
|
||||
}
|
||||
|
||||
private double _stageHeight;
|
||||
[WatchValue("载台高度")]
|
||||
public double StageHeight
|
||||
{
|
||||
get { return _stageHeight; }
|
||||
set { if (_stageHeight != value) { _stageHeight = value; OnPropertyChanged(nameof(StageHeight)); } }
|
||||
}
|
||||
|
||||
private double _gantry2AvoidPositionX = 10;
|
||||
[WatchValue("对刀时龙门X2的避让位置")]
|
||||
public double Gantry2AvoidPositionX
|
||||
{
|
||||
get { return _gantry2AvoidPositionX; }
|
||||
set { if (_gantry2AvoidPositionX != value) { _gantry2AvoidPositionX = value; OnPropertyChanged(nameof(Gantry2AvoidPositionX)); } }
|
||||
}
|
||||
private double _gantry2AvoidPositionY = 200;
|
||||
[WatchValue("对刀时龙门Y2的避让位置")]
|
||||
public double Gantry2AvoidPositionY
|
||||
{
|
||||
get { return _gantry2AvoidPositionY; }
|
||||
set { if (_gantry2AvoidPositionY != value) { _gantry2AvoidPositionY = value; OnPropertyChanged(nameof(Gantry2AvoidPositionY)); } }
|
||||
}
|
||||
private double _z1StartPosition;
|
||||
[WatchValue("Z1开始位置")]
|
||||
public double Z1StartPosition
|
||||
{
|
||||
get { return _z1StartPosition; }
|
||||
set { if (_z1StartPosition != value) { _z1StartPosition = value; OnPropertyChanged(nameof(Z1StartPosition)); } }
|
||||
}
|
||||
|
||||
private double _z1Speed;
|
||||
[WatchValue("Z1速度")]
|
||||
public double Z1Speed
|
||||
{
|
||||
get { return _z1Speed; }
|
||||
set { if (_z1Speed != value) { _z1Speed = value; OnPropertyChanged(nameof(Z1Speed)); } }
|
||||
}
|
||||
|
||||
private double _z1DropMaxPosition;
|
||||
[WatchValue("Z1下降距离")]
|
||||
public double Z1DropMaxPosition
|
||||
{
|
||||
get { return _z1DropMaxPosition; }
|
||||
set { if (_z1DropMaxPosition != value) { _z1DropMaxPosition = value; OnPropertyChanged(nameof(Z1DropMaxPosition)); } }
|
||||
}
|
||||
|
||||
private int _needleTouchCount = 1;
|
||||
[WatchValue("对刀次数")]
|
||||
public int NeedleTouchCount
|
||||
{
|
||||
get { return _needleTouchCount; }
|
||||
set { if (_needleTouchCount != value) { _needleTouchCount = value; OnPropertyChanged(nameof(NeedleTouchCount)); } }
|
||||
}
|
||||
|
||||
private double _needleTouchHeight = 14;
|
||||
|
||||
/// <summary>
|
||||
/// Z1接触对刀仪高度
|
||||
/// </summary>
|
||||
[WatchValue("Z1接触对刀仪高度")]
|
||||
public double NeedleTouchHeight
|
||||
{
|
||||
get { return _needleTouchHeight; }
|
||||
set { if (_needleTouchHeight != value) { _needleTouchHeight = value; OnPropertyChanged(nameof(NeedleTouchHeight)); } }
|
||||
}
|
||||
|
||||
private double _needleTouchHeightBase;
|
||||
|
||||
/// <summary>
|
||||
/// 基准值
|
||||
/// </summary>
|
||||
[WatchValue("基准值")]
|
||||
public double NeedleTouchHeightBase
|
||||
{
|
||||
get { return _needleTouchHeightBase; }
|
||||
set { if (_needleTouchHeightBase != value) { _needleTouchHeightBase = value; OnPropertyChanged(nameof(NeedleTouchHeightBase)); } }
|
||||
}
|
||||
|
||||
private double _currentNeedleTouchHeight;
|
||||
[WatchValue("当前使用对刀高度")]
|
||||
/// <summary>
|
||||
/// 当前使用对刀高度
|
||||
/// </summary>
|
||||
public double CurrentNeedleTouchHeight
|
||||
{
|
||||
get { return _currentNeedleTouchHeight; }
|
||||
set { if (_currentNeedleTouchHeight != value) { _currentNeedleTouchHeight = value; OnPropertyChanged(nameof(CurrentNeedleTouchHeight)); } }
|
||||
}
|
||||
|
||||
private double _needleTouchOffset;
|
||||
[WatchValue("对刀与基准偏差")]
|
||||
/// <summary>
|
||||
/// 对刀与基准偏差
|
||||
/// </summary>
|
||||
public double NeedleTouchOffset
|
||||
{
|
||||
get { return _needleTouchOffset; }
|
||||
set { if (_needleTouchOffset != value) { _needleTouchOffset = value; OnPropertyChanged(nameof(NeedleTouchOffset)); } }
|
||||
}
|
||||
|
||||
private double _needleTouchHeightAve;
|
||||
[WatchValue("Z1对刀平均高度")]
|
||||
/// <summary>
|
||||
/// Z1对刀平均高度
|
||||
/// </summary>
|
||||
public double NeedleTouchHeightAve
|
||||
{
|
||||
get { return _needleTouchHeightAve; }
|
||||
set { if (_needleTouchHeightAve != value) { _needleTouchHeightAve = value; OnPropertyChanged(nameof(NeedleTouchHeightAve)); } }
|
||||
}
|
||||
|
||||
private ObservableCollection<NeedleTouchRecord> _needleTouchRecords = new ObservableCollection<NeedleTouchRecord>();
|
||||
|
||||
public ObservableCollection<NeedleTouchRecord> NeedleTouchRecords
|
||||
{
|
||||
get { return _needleTouchRecords; }
|
||||
set
|
||||
{
|
||||
_needleTouchRecords = value;
|
||||
OnPropertyChanged(nameof(NeedleTouchRecords));
|
||||
}
|
||||
}
|
||||
|
||||
private double _laserToNeedleOffset = 0;
|
||||
public double LaserToNeedleOffset
|
||||
{
|
||||
get { return _laserToNeedleOffset; }
|
||||
set { if (_laserToNeedleOffset != value) { _laserToNeedleOffset = value; OnPropertyChanged(nameof(LaserToNeedleOffset)); } }
|
||||
}
|
||||
|
||||
private double _needleCameraHeightOffset;
|
||||
public double NeedleCameraHeightOffset
|
||||
{
|
||||
get { return _needleCameraHeightOffset; }
|
||||
set { if (_needleCameraHeightOffset != value) { _needleCameraHeightOffset = value; OnPropertyChanged(nameof(NeedleCameraHeightOffset)); } }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
NeedleZCalibrationItem clone = new NeedleZCalibrationItem();
|
||||
clone.CurrentNeedleTouchHeight = _needleCameraHeightOffset;
|
||||
clone.CZHeight = CZHeight;
|
||||
clone.Gantry2AvoidPositionX = Gantry2AvoidPositionX;
|
||||
clone.Gantry2AvoidPositionY = Gantry2AvoidPositionY;
|
||||
clone.LaserToNeedleOffset = LaserToNeedleOffset;
|
||||
clone.NeedleCameraHeightOffset = NeedleCameraHeightOffset;
|
||||
clone.NeedleTouchCount = NeedleTouchCount;
|
||||
clone.NeedleTouchHeight = NeedleTouchHeight;
|
||||
clone.NeedleTouchHeightAve = NeedleTouchHeightAve;
|
||||
clone.NeedleTouchHeightBase = NeedleTouchHeightBase;
|
||||
clone.NeedleTouchOffset = NeedleTouchOffset;
|
||||
clone.StageHeight = StageHeight;
|
||||
clone.SupportPinPositionX = SupportPinPositionX;
|
||||
clone.SupportPinPositionY = SupportPinPositionY;
|
||||
clone.Z1DropMaxPosition = Z1DropMaxPosition;
|
||||
clone.Z1Speed = Z1Speed;
|
||||
clone.Z1StartPosition = Z1StartPosition;
|
||||
if (this.NeedleTouchRecords != null)
|
||||
{
|
||||
foreach (var item in this.NeedleTouchRecords)
|
||||
{
|
||||
clone.NeedleTouchRecords.Add(item.Clone() as NeedleTouchRecord);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class NeedleXYCalibrationItem : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private double _needleX;
|
||||
[WatchValue("设置—刺晶头X")]
|
||||
public double NeedleX
|
||||
{
|
||||
get { return _needleX; }
|
||||
set { if (_needleX != value) { _needleX = value; OnPropertyChanged(nameof(NeedleX)); } }
|
||||
}
|
||||
|
||||
private double _needleY;
|
||||
[WatchValue("设置—刺晶头Y")]
|
||||
public double NeedleY
|
||||
{
|
||||
get { return _needleY; }
|
||||
set { if (_needleY != value) { _needleY = value; OnPropertyChanged(nameof(NeedleY)); } }
|
||||
}
|
||||
|
||||
private double _cameraX;
|
||||
[WatchValue("设置—相机X")]
|
||||
public double CameraX
|
||||
{
|
||||
get { return _cameraX; }
|
||||
set { if (_cameraX != value) { _cameraX = value; OnPropertyChanged(nameof(CameraX)); } }
|
||||
}
|
||||
|
||||
private double _cameraY;
|
||||
[WatchValue("设置—相机Y")]
|
||||
public double CameraY
|
||||
{
|
||||
get { return _cameraY; }
|
||||
set { if (_cameraY != value) { _cameraY = value; OnPropertyChanged(nameof(CameraY)); } }
|
||||
}
|
||||
private double _needleZ1 = 0.0;
|
||||
[WatchValue("设置—刺晶头Z1")]
|
||||
public double NeedleZ1
|
||||
{
|
||||
get { return _needleZ1; }
|
||||
set { if (_needleZ1 != value) { _needleZ1 = value; OnPropertyChanged(nameof(NeedleZ1)); } }
|
||||
}
|
||||
|
||||
private double _offsetX;
|
||||
[WatchValue("X方向偏差")]
|
||||
public double OffsetX
|
||||
{
|
||||
get { return _offsetX; }
|
||||
set { if (_offsetX != value) { _offsetX = value; OnPropertyChanged(nameof(OffsetX)); } }
|
||||
}
|
||||
|
||||
private double _offsetY;
|
||||
[WatchValue("Y方向偏差")]
|
||||
public double OffsetY
|
||||
{
|
||||
get { return _offsetY; }
|
||||
set { if (_offsetY != value) { _offsetY = value; OnPropertyChanged(nameof(OffsetY)); } }
|
||||
}
|
||||
|
||||
private double _initialOffsetX;
|
||||
/// <summary>
|
||||
/// 针和相机之间的X初始偏差,不加补偿
|
||||
/// </summary>
|
||||
[WatchValue("X方向初始偏差")]
|
||||
public double InitialOffsetX
|
||||
{
|
||||
get { return _initialOffsetX; }
|
||||
set { if (_initialOffsetX != value) { _initialOffsetX = value; OnPropertyChanged(nameof(InitialOffsetX)); } }
|
||||
}
|
||||
|
||||
private double _initialOffsetY;
|
||||
/// <summary>
|
||||
/// 针和相机之间的Y初始偏差,不加补偿
|
||||
/// </summary>
|
||||
[WatchValue("Y方向初始偏差")]
|
||||
public double InitialOffsetY
|
||||
{
|
||||
get { return _initialOffsetY; }
|
||||
set { if (_initialOffsetY != value) { _initialOffsetY = value; OnPropertyChanged(nameof(InitialOffsetY)); } }
|
||||
}
|
||||
|
||||
private double _compensateX;
|
||||
/// <summary>
|
||||
/// 针和相机之间的X方向偏差补偿
|
||||
/// </summary>
|
||||
[WatchValue("X方向补偿")]
|
||||
public double CompensateX
|
||||
{
|
||||
get { return _compensateX; }
|
||||
set { if (_compensateX != value) { _compensateX = value; OnPropertyChanged(nameof(CompensateX)); } }
|
||||
}
|
||||
|
||||
private double _compensateY;
|
||||
/// <summary>
|
||||
/// 针和相机之间的Y方向偏差补偿
|
||||
/// </summary>
|
||||
[WatchValue("Y方向补偿")]
|
||||
public double CompensateY
|
||||
{
|
||||
get { return _compensateY; }
|
||||
set { if (_compensateY != value) { _compensateY = value; OnPropertyChanged(nameof(CompensateY)); } }
|
||||
}
|
||||
|
||||
private double _offsetXMax;
|
||||
[WatchValue("偏差限制—X偏差最大值")]
|
||||
public double OffsetXMax
|
||||
{
|
||||
get { return _offsetXMax; }
|
||||
set { if (_offsetXMax != value) { _offsetXMax = value; OnPropertyChanged(nameof(OffsetXMax)); } }
|
||||
}
|
||||
|
||||
private double _offsetXMin;
|
||||
[WatchValue("偏差限制—X偏差最小值")]
|
||||
public double OffsetXMin
|
||||
{
|
||||
get { return _offsetXMin; }
|
||||
set { if (_offsetXMin != value) { _offsetXMin = value; OnPropertyChanged(nameof(OffsetXMin)); } }
|
||||
}
|
||||
|
||||
private double _offsetYMax;
|
||||
[WatchValue("偏差限制—Y偏差最大值")]
|
||||
public double OffsetYMax
|
||||
{
|
||||
get { return _offsetYMax; }
|
||||
set { if (_offsetYMax != value) { _offsetYMax = value; OnPropertyChanged(nameof(OffsetYMax)); } }
|
||||
}
|
||||
|
||||
private double _offsetYMin;
|
||||
[WatchValue("偏差限制—Y偏差最小值")]
|
||||
public double OffsetYMin
|
||||
{
|
||||
get { return _offsetYMin; }
|
||||
set { if (_offsetYMin != value) { _offsetYMin = value; OnPropertyChanged(nameof(OffsetYMin)); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扎铜箔时龙门X2避让位置
|
||||
/// </summary>
|
||||
private double _x2AvoidPosition;
|
||||
[WatchValue("扎铜箔时龙门X2避让位置")]
|
||||
public double X2AvoidPosition
|
||||
{
|
||||
get { return _x2AvoidPosition; }
|
||||
set { if (_x2AvoidPosition != value) { _x2AvoidPosition = value; OnPropertyChanged(nameof(X2AvoidPosition)); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扎铜箔时龙门Y2避让位置
|
||||
/// </summary>
|
||||
private double _y2AvoidPosition;
|
||||
[WatchValue("扎铜箔时龙门Y2避让位置")]
|
||||
public double Y2AvoidPosition
|
||||
{
|
||||
get { return _y2AvoidPosition; }
|
||||
set { if (_y2AvoidPosition != value) { _y2AvoidPosition = value; OnPropertyChanged(nameof(Y2AvoidPosition)); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扎铜箔时Stage的位置
|
||||
/// </summary>
|
||||
private double _stagePosition;
|
||||
[WatchValue("扎铜箔时Stage的位置")]
|
||||
public double StagePosition
|
||||
{
|
||||
get { return _stagePosition; }
|
||||
set { if (_stagePosition != value) { _stagePosition = value; OnPropertyChanged(nameof(StagePosition)); } }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
NeedleXYCalibrationItem clone = new NeedleXYCalibrationItem();
|
||||
clone.NeedleX = this.NeedleX;
|
||||
clone.NeedleY = this.NeedleY;
|
||||
clone.CameraX = this.CameraY;
|
||||
clone.CameraY = this.CameraY;
|
||||
clone.OffsetX = this.OffsetX;
|
||||
clone.OffsetY = this.OffsetY;
|
||||
clone.OffsetXMax = this.OffsetXMax;
|
||||
clone.OffsetXMin = this.OffsetXMin;
|
||||
clone.OffsetYMax = this.OffsetYMax;
|
||||
clone.OffsetYMin = this.OffsetYMin;
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
|
||||
public class NeedleXYCalibrationItemNew : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
//private VisionParData _needleVisionParData;
|
||||
|
||||
//public VisionParData NeedleVisionParData
|
||||
//{
|
||||
// get { return _needleVisionParData ?? new VisionParData() { Exposure = 2000 }; }
|
||||
// set { SetAndNotify(ref _needleVisionParData, value); }
|
||||
//}
|
||||
|
||||
private double _x1Calib;
|
||||
/// <summary>
|
||||
/// 相机标定位X1
|
||||
/// </summary>
|
||||
[WatchValue("相机标定位X1")]
|
||||
public double X1Calib
|
||||
{
|
||||
get { return _x1Calib; }
|
||||
set { if (_x1Calib != value) { _x1Calib = value; OnPropertyChanged(nameof(X1Calib)); } }
|
||||
}
|
||||
|
||||
private double _x1MechanicalOffset = 0.0;
|
||||
/// <summary>
|
||||
/// 机械X1Offset
|
||||
/// </summary>
|
||||
[WatchValue("机械X1Offset")]
|
||||
public double X1MechanicalOffset
|
||||
{
|
||||
get { return _x1MechanicalOffset; }
|
||||
set { if (_x1MechanicalOffset != value) { _x1MechanicalOffset = value; OnPropertyChanged(nameof(X1MechanicalOffset)); } }
|
||||
}
|
||||
|
||||
private double _wSCalibX2;
|
||||
/// <summary>
|
||||
/// 方片标定位X2
|
||||
/// </summary>
|
||||
[WatchValue("方片标定位X2")]
|
||||
public double WSCalibX2
|
||||
{
|
||||
get { return _wSCalibX2; }
|
||||
set { if (_wSCalibX2 != value) { _wSCalibX2 = value; OnPropertyChanged(nameof(WSCalibX2)); } }
|
||||
}
|
||||
|
||||
private double _wSCalibY2;
|
||||
/// <summary>
|
||||
/// 方片标定位Y2
|
||||
/// </summary>
|
||||
[WatchValue("方片标定位Y2")]
|
||||
public double WSCalibY2
|
||||
{
|
||||
get { return _wSCalibY2; }
|
||||
set { if (_wSCalibY2 != value) { _wSCalibY2 = value; OnPropertyChanged(nameof(WSCalibY2)); } }
|
||||
}
|
||||
|
||||
private double _needleX1;
|
||||
[WatchValue("刺晶头X1")]
|
||||
public double NeedleX1
|
||||
{
|
||||
get { return _needleX1; }
|
||||
set { if (_needleX1 != value) { _needleX1 = value; OnPropertyChanged(nameof(NeedleX1)); } }
|
||||
}
|
||||
|
||||
private double _needleZ1 = 0.0;
|
||||
[WatchValue("刺晶头Z1")]
|
||||
public double NeedleZ1
|
||||
{
|
||||
get { return _needleZ1; }
|
||||
set { if (_needleZ1 != value) { _needleZ1 = value; OnPropertyChanged(nameof(NeedleZ1)); } }
|
||||
}
|
||||
|
||||
private int _z1WorkTime = 0;
|
||||
/// <summary>
|
||||
/// Z1保持下扎时长
|
||||
/// </summary>
|
||||
[WatchValue("Z1保持下扎时长")]
|
||||
public int Z1WorkTime
|
||||
{
|
||||
get { return _z1WorkTime; }
|
||||
set { if (_z1WorkTime != value) { _z1WorkTime = value; OnPropertyChanged(nameof(Z1WorkTime)); } }
|
||||
}
|
||||
|
||||
private double _offsetX;
|
||||
/// <summary>
|
||||
/// 针和相机之间的X初始偏差,不加补偿
|
||||
/// </summary>
|
||||
[WatchValue("X方向偏差")]
|
||||
public double OffsetX
|
||||
{
|
||||
get { return _offsetX; }
|
||||
set { if (_offsetX != value) { _offsetX = value; OnPropertyChanged(nameof(OffsetX)); } }
|
||||
}
|
||||
|
||||
private double _offsetY;
|
||||
/// <summary>
|
||||
/// 针和相机之间的Y初始偏差,不加补偿
|
||||
/// </summary>
|
||||
[WatchValue("Y方向偏差")]
|
||||
public double OffsetY
|
||||
{
|
||||
get { return _offsetY; }
|
||||
set { if (_offsetY != value) { _offsetY = value; OnPropertyChanged(nameof(OffsetY)); } }
|
||||
}
|
||||
|
||||
private double _compensateX;
|
||||
/// <summary>
|
||||
/// 针和相机之间的X方向偏差补偿
|
||||
/// </summary>
|
||||
[WatchValue("X方向补偿")]
|
||||
public double CompensateX
|
||||
{
|
||||
get { return _compensateX; }
|
||||
set { if (_compensateX != value) { _compensateX = value; OnPropertyChanged(nameof(CompensateX)); } }
|
||||
}
|
||||
|
||||
private double _compensateY;
|
||||
/// <summary>
|
||||
/// 针和相机之间的Y方向偏差补偿
|
||||
/// </summary>
|
||||
[WatchValue("Y方向补偿")]
|
||||
public double CompensateY
|
||||
{
|
||||
get { return _compensateY; }
|
||||
set { if (_compensateY != value) { _compensateY = value; OnPropertyChanged(nameof(CompensateY)); } }
|
||||
}
|
||||
|
||||
private double _offsetXMax;
|
||||
[WatchValue("偏差限制—X偏差最大值")]
|
||||
public double OffsetXMax
|
||||
{
|
||||
get { return _offsetXMax; }
|
||||
set { if (_offsetXMax != value) { _offsetXMax = value; OnPropertyChanged(nameof(OffsetXMax)); } }
|
||||
}
|
||||
|
||||
private double _offsetXMin;
|
||||
[WatchValue("偏差限制—X偏差最小值")]
|
||||
public double OffsetXMin
|
||||
{
|
||||
get { return _offsetXMin; }
|
||||
set { if (_offsetXMin != value) { _offsetXMin = value; OnPropertyChanged(nameof(OffsetXMin)); } }
|
||||
}
|
||||
|
||||
private double _offsetYMax;
|
||||
[WatchValue("偏差限制—Y偏差最大值")]
|
||||
public double OffsetYMax
|
||||
{
|
||||
get { return _offsetYMax; }
|
||||
set { if (_offsetYMax != value) { _offsetYMax = value; OnPropertyChanged(nameof(OffsetYMax)); } }
|
||||
}
|
||||
|
||||
private double _offsetYMin;
|
||||
[WatchValue("偏差限制—Y偏差最小值")]
|
||||
public double OffsetYMin
|
||||
{
|
||||
get { return _offsetYMin; }
|
||||
set { if (_offsetYMin != value) { _offsetYMin = value; OnPropertyChanged(nameof(OffsetYMin)); } }
|
||||
}
|
||||
|
||||
private double _wSApproachX2;
|
||||
/// <summary>
|
||||
/// 方片逼近位X2
|
||||
/// </summary>
|
||||
[WatchValue("方片逼近位X2")]
|
||||
public double WSApproachX2
|
||||
{
|
||||
get { return _wSApproachX2; }
|
||||
set { if (_wSApproachX2 != value) { _wSApproachX2 = value; OnPropertyChanged(nameof(WSApproachX2)); } }
|
||||
}
|
||||
|
||||
private double _wSApproachY2;
|
||||
/// <summary>
|
||||
/// 方片逼近位Y2
|
||||
/// </summary>
|
||||
[WatchValue("方片逼近位Y2")]
|
||||
public double WSApproachY2
|
||||
{
|
||||
get { return _wSApproachY2; }
|
||||
set { if (_wSApproachY2 != value) { _wSApproachY2 = value; OnPropertyChanged(nameof(WSApproachY2)); } }
|
||||
}
|
||||
|
||||
private double _stampThreRadius;
|
||||
/// <summary>
|
||||
/// 针印理论半径
|
||||
/// </summary>
|
||||
[WatchValue("针印理论半径")]
|
||||
public double StampThreRadius
|
||||
{
|
||||
get { return _stampThreRadius; }
|
||||
set { if (_stampThreRadius != value) { _stampThreRadius = value; OnPropertyChanged(nameof(StampThreRadius)); } }
|
||||
}
|
||||
|
||||
private double _stampThreErrorRange;
|
||||
/// <summary>
|
||||
/// 针印误差范围
|
||||
/// </summary>
|
||||
[WatchValue("针印误差范围")]
|
||||
public double StampThreErrorRange
|
||||
{
|
||||
get { return _stampThreErrorRange; }
|
||||
set { if (_stampThreErrorRange != value) { _stampThreErrorRange = value; OnPropertyChanged(nameof(StampThreErrorRange)); } }
|
||||
}
|
||||
|
||||
private double _stampMinCircularity;
|
||||
/// <summary>
|
||||
/// 针印最小圆度
|
||||
/// </summary>
|
||||
[WatchValue("针印最小圆度")]
|
||||
public double StampMinCircularity
|
||||
{
|
||||
get { return _stampMinCircularity; }
|
||||
set { if (_stampMinCircularity != value) { _stampMinCircularity = value; OnPropertyChanged(nameof(StampMinCircularity)); } }
|
||||
}
|
||||
|
||||
private double _stampPolarity;
|
||||
/// <summary>
|
||||
/// 针印颜色,0黑1白
|
||||
/// </summary>
|
||||
[WatchValue("针印理论半径")]
|
||||
public double StampPolarity
|
||||
{
|
||||
get { return _stampPolarity; }
|
||||
set { if (_stampPolarity != value) { _stampPolarity = value; OnPropertyChanged(nameof(StampPolarity)); } }
|
||||
}
|
||||
|
||||
private bool _isBlack = false;
|
||||
public bool IsBlack
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isBlack;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isBlack = value;
|
||||
StampPolarityUpdate();
|
||||
OnPropertyChanged(nameof(IsBlack));
|
||||
}
|
||||
}
|
||||
|
||||
public void StampPolarityUpdate()
|
||||
{
|
||||
if (IsBlack)
|
||||
{
|
||||
StampPolarity = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
StampPolarity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
NeedleXYCalibrationItemNew clone = new NeedleXYCalibrationItemNew();
|
||||
clone.NeedleX1 = this.NeedleX1;
|
||||
clone.NeedleZ1 = this.NeedleZ1;
|
||||
clone.WSApproachX2 = this.WSApproachX2;
|
||||
clone.WSApproachY2 = this.WSApproachY2;
|
||||
clone.Z1WorkTime = Z1WorkTime;
|
||||
clone.X1MechanicalOffset = X1MechanicalOffset;
|
||||
clone.X1Calib = X1Calib;
|
||||
clone.WSCalibX2 = WSCalibX2;
|
||||
clone.WSCalibY2 = WSCalibY2;
|
||||
clone.CompensateX = CompensateX;
|
||||
clone.CompensateY = CompensateY;
|
||||
clone.OffsetX = this.OffsetX;
|
||||
clone.OffsetY = this.OffsetY;
|
||||
clone.OffsetXMax = this.OffsetXMax;
|
||||
clone.OffsetXMin = this.OffsetXMin;
|
||||
clone.OffsetYMax = this.OffsetYMax;
|
||||
clone.OffsetYMin = this.OffsetYMin;
|
||||
clone.IsBlack = this.IsBlack;
|
||||
clone.StampMinCircularity = this.StampMinCircularity;
|
||||
clone.StampPolarity = this.StampPolarity;
|
||||
clone.StampThreErrorRange = this.StampThreErrorRange;
|
||||
clone.StampThreRadius = this.StampThreRadius;
|
||||
|
||||
|
||||
//clone.NeedleVisionParData.Exposure = this.NeedleVisionParData.Exposure;
|
||||
//clone.NeedleVisionParData.Gain = this.NeedleVisionParData.Gain;
|
||||
//clone.NeedleVisionParData.LightSourceBack = this.NeedleVisionParData.LightSourceBack;
|
||||
//clone.NeedleVisionParData.LightSourcePointBlue = this.NeedleVisionParData.LightSourcePointBlue;
|
||||
//clone.NeedleVisionParData.LightSourcePointRed = this.NeedleVisionParData.LightSourcePointRed;
|
||||
//clone.NeedleVisionParData.LightSourceRingBlue = this.NeedleVisionParData.LightSourceRingBlue;
|
||||
//clone.NeedleVisionParData.LightSourceRingRed = this.NeedleVisionParData.LightSourceRingRed;
|
||||
//clone.NeedleVisionParData.Z2 = this.NeedleVisionParData.Z2;
|
||||
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
|
||||
public class NeedleTouchRecord : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
|
||||
private int _CurrentCount;
|
||||
/// <summary>
|
||||
/// 当前次数
|
||||
/// </summary>
|
||||
public int CurrentCount
|
||||
{
|
||||
get { return _CurrentCount; }
|
||||
set
|
||||
{ SetAndNotify(ref _CurrentCount, value); }
|
||||
}
|
||||
|
||||
private double _Height;
|
||||
/// <summary>
|
||||
/// 高度
|
||||
/// </summary>
|
||||
public double Height
|
||||
{
|
||||
get { return _Height; }
|
||||
set
|
||||
{ SetAndNotify(ref _Height, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public NeedleTouchRecord()
|
||||
{
|
||||
|
||||
}
|
||||
public NeedleTouchRecord(int count, double height)
|
||||
{
|
||||
CurrentCount = count;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using MainShell.Models;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.Model
|
||||
{
|
||||
[Export(typeof(IParameter))]
|
||||
public class NeedlePrintCalibrateSetting : ParameterBase
|
||||
{
|
||||
public NeedlePrintCalibrateParameter NeedlePrintCalibrateParameter { get; set; } = new NeedlePrintCalibrateParameter();
|
||||
public NeedlePrintCalibrateSetting() { }
|
||||
public override void Copy(IParameter source)
|
||||
{
|
||||
if (source is NeedlePrintCalibrateSetting setting)
|
||||
{
|
||||
ReflectionExtension.Copy(NeedlePrintCalibrateParameter, setting.NeedlePrintCalibrateParameter);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NeedlePrintCalibrateParameter : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private MPoint _startPoint = new MPoint();
|
||||
public MPoint StartPoint
|
||||
{
|
||||
get { return _startPoint; }
|
||||
set { SetAndNotify(ref _startPoint, value); }
|
||||
}
|
||||
|
||||
private MPoint _endPoint = new MPoint();
|
||||
public MPoint EndPoint
|
||||
{
|
||||
get { return _endPoint; }
|
||||
set { SetAndNotify(ref _endPoint, value); }
|
||||
}
|
||||
|
||||
private MPoint _avoidancePoint = new MPoint();
|
||||
|
||||
public MPoint AvoidancePoint
|
||||
{
|
||||
get { return _avoidancePoint; }
|
||||
set { SetAndNotify(ref _avoidancePoint, value); }
|
||||
}
|
||||
|
||||
private double _z1WorkHeight;
|
||||
|
||||
public double Z1WorkHeight
|
||||
{
|
||||
get { return _z1WorkHeight; }
|
||||
set { SetAndNotify(ref _z1WorkHeight, value); }
|
||||
}
|
||||
|
||||
private double _z2WorkHeight;
|
||||
|
||||
public double Z2WorkHeight
|
||||
{
|
||||
get { return _z2WorkHeight; }
|
||||
set { SetAndNotify(ref _z2WorkHeight, value); }
|
||||
}
|
||||
|
||||
private double _xPitch;
|
||||
|
||||
public double Xpitch
|
||||
{
|
||||
get { return _xPitch; }
|
||||
set { SetAndNotify(ref _xPitch, value); }
|
||||
}
|
||||
|
||||
private double _yPitch;
|
||||
|
||||
public double Ypitch
|
||||
{
|
||||
get { return _yPitch; }
|
||||
set { SetAndNotify(ref _yPitch, value); }
|
||||
}
|
||||
|
||||
private int _usedNum;
|
||||
|
||||
public int UsedNum
|
||||
{
|
||||
get { return _usedNum; }
|
||||
set { SetAndNotify(ref _usedNum, value); }
|
||||
}
|
||||
|
||||
private int _sleepTime = 1000;
|
||||
public int SleepTime
|
||||
{
|
||||
get { return _sleepTime; }
|
||||
set { SetAndNotify(ref _sleepTime, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return MemberwiseClone() as NeedlePrintCalibrateParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.CameraAccuracyCalibrationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="700">
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="GroupBox" BasedOn="{StaticResource GroupStepControl}"/>
|
||||
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
</Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="90"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid mwControls:ParameterAttach.DelayAcceptValue ="{Binding ParameterHelper}">
|
||||
<StackPanel>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Header="【第一步】针尖高度设置">
|
||||
<customControl:AxisMoveControl LableContent1="Z1(mm):"
|
||||
Value1="{Binding QuickNeedlePrintParameter.Z1InkHeight}"
|
||||
IsAllShow="False"
|
||||
ReadCommand="{mwControls:Action TeachZ1Pos}"
|
||||
IsReadOnly="False"
|
||||
MoveCommand="{mwControls:Action MoveToZ1Pos}"/>
|
||||
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Header="【第二步】WS避让位">
|
||||
<GroupBox.Content>
|
||||
<customControl:AxisMoveControl LableContent1="X2(mm):"
|
||||
Value1="{Binding QuickNeedlePrintParameter.AvoidancePoint.PointX}"
|
||||
LableContent2="Y2(mm):"
|
||||
Value2="{Binding QuickNeedlePrintParameter.AvoidancePoint.PointY}"
|
||||
ReadCommand="{mwControls:Action TeachWSPos}"
|
||||
MoveCommand="{mwControls:Action MoveToWsPos}"
|
||||
IsReadOnly="True"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Label VerticalAlignment="Center" Content="X2:"/>
|
||||
<mwControls:NumberBox Value="{Binding QuickNeedlePrintParameter.AvoidancePoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y2:"/>
|
||||
<mwControls:NumberBox Value="{Binding QuickNeedlePrintParameter.AvoidancePoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachWSPos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToWsPos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第三步】墨水位置">
|
||||
<GroupBox.Content>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<customControl:AxisMoveControl LableContent1="X2(mm):"
|
||||
Value1="{Binding QuickNeedlePrintParameter.InkPos.PointX}"
|
||||
LableContent2="Y2(mm):"
|
||||
Value2="{Binding QuickNeedlePrintParameter.InkPos.PointY}"
|
||||
ReadCommand="{mwControls:Action TeachInkPos}"
|
||||
MoveCommand="{mwControls:Action MoveToInkPos}"
|
||||
IsReadOnly="True"/>
|
||||
|
||||
<Button Margin="2,0" HorizontalAlignment="Right" Click="{mwControls:Action InkSmearing}" Content="涂墨"/>
|
||||
</Grid>
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第四步】快打针印参数设置">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label VerticalAlignment="Center" HorizontalAlignment="Left" Content="打件颗数:"/>
|
||||
<mwControls:IntNumberBox Value="{Binding BondingNumber}" IsReadOnly="True" Width="75" Margin="4,0" />
|
||||
<Button IsEnabled="{Binding UiEnable}" Margin="2,0" Click="{mwControls:Action PositiveBonding}" Content="快打正向"/>
|
||||
<Button IsEnabled="{Binding UiEnable}" Margin="2,0" Click="{mwControls:Action NegativeBonding}" Content="快打反向"/>
|
||||
<Button IsEnabled="{Binding UiEnable}" Margin="2,0" Click="{mwControls:Action SlowBonding}" Content="补打"/>
|
||||
<Button Margin="2,0" Content="停止打件" Click="{mwControls:Action StopBonding}"/>
|
||||
</StackPanel>
|
||||
<Label Content="正向针印查看:" HorizontalAlignment="Left"/>
|
||||
<StackPanel IsEnabled="{Binding UiEnable}" HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanLastPositiveIndex}" Click="{mwControls:Action LastPositiveIndex}" Content="上一个"/>
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanNextPositiveIndex}" Click="{mwControls:Action NextPositiveIndex}" Content="下一个"/>
|
||||
</StackPanel>
|
||||
<Label Content="反向针印查看:" HorizontalAlignment="Left"/>
|
||||
<StackPanel IsEnabled="{Binding UiEnable}" HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanLastNegativeIndex}" Click="{mwControls:Action LastNegativeIndex}" Content="上一个"/>
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanNextNegativeIndex}" Click="{mwControls:Action NextNegativeIndex}" Content="下一个"/>
|
||||
</StackPanel>
|
||||
<Label Content="补打针印查看:" HorizontalAlignment="Left"/>
|
||||
<StackPanel IsEnabled="{Binding UiEnable}" HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanLastSlowIndex}" Click="{mwControls:Action LastSlowIndex}" Content="上一个"/>
|
||||
<Button Margin="2,0" IsEnabled="{Binding CanNextSlowIndex}" Click="{mwControls:Action NextSlowIndex}" Content="下一个"/>
|
||||
</StackPanel>
|
||||
<Button IsEnabled="{Binding UiEnable}" HorizontalAlignment="Right" Click="{mwControls:Action SaveParameter}" Margin="10,2" Content="保存"/>
|
||||
</StackPanel>
|
||||
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraAccuracyCalibrationView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraAccuracyCalibrationView : UserControl
|
||||
{
|
||||
public CameraAccuracyCalibrationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.CylinderView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="CylinderCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F8FAFD"/>
|
||||
<Setter Property="BorderBrush" Value="#D4DCE8"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Padding" Value="14"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CylinderDotStyle" TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="10"/>
|
||||
<Setter Property="Height" Value="10"/>
|
||||
<Setter Property="Fill" Value="#CBD5E1"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOn}" Value="True">
|
||||
<Setter Property="Fill" Value="#22C55E"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CylinderActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="Padding" Value="12,6"/>
|
||||
<Setter Property="MinWidth" Value="90"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Margin" Value="0,0,8,0"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
CornerRadius="18"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="#EDF1F7">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Margin="12,12,12,8">
|
||||
<TextBlock Text="CYLINDER CONTROL / 气缸控制" FontSize="20" FontWeight="Bold" Foreground="#0F3B7A"/>
|
||||
<Border Background="#EFF6FF" BorderBrush="#BFDBFE" BorderThickness="1" CornerRadius="6" Padding="10" Margin="0,8,0,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="最近操作:" Foreground="#475569" Margin="0,0,8,0"/>
|
||||
<TextBlock Text="{Binding PageState.LastActionTime, StringFormat={}{0:HH:mm:ss}}" Foreground="#0F172A" FontWeight="Bold" Margin="0,0,12,0"/>
|
||||
<TextBlock Text="{Binding PageState.LastActionMessage}" Foreground="#1D4ED8" FontWeight="SemiBold" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" Margin="12,0,12,12" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding PageState.Cylinders}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource CylinderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold" Foreground="#0F3B7A"/>
|
||||
<TextBlock Text="{Binding Description}" Foreground="#64748B" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
<Border Grid.Column="1" Background="#FEF3C7" CornerRadius="12" Padding="10,4" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ControlTypeText}" Foreground="#92400E" FontWeight="Bold"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Margin="0,12,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Margin="0,0,16,0">
|
||||
<TextBlock Text="控制" Foreground="#1D4ED8" FontWeight="Bold" Margin="0,0,0,8"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="伸出"
|
||||
Command="{Binding ExtendCommand}"
|
||||
Background="#2563EB"
|
||||
BorderBrush="#2563EB"
|
||||
Style="{StaticResource CylinderActionButtonStyle}"/>
|
||||
<Button Content="缩回"
|
||||
Command="{Binding RetractCommand}"
|
||||
Background="#F97316"
|
||||
BorderBrush="#F97316"
|
||||
Style="{StaticResource CylinderActionButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1" Margin="0,0,16,0">
|
||||
<TextBlock Text="输出信号" Foreground="#C2410C" FontWeight="Bold" Margin="0,0,0,8"/>
|
||||
<ItemsControl ItemsSource="{Binding OutputSignals}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="#FFF7ED" BorderBrush="#FED7AA" BorderThickness="1" CornerRadius="4" Padding="8,6" Margin="0,0,0,6">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Style="{StaticResource CylinderDotStyle}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{Binding Name}" Foreground="#9A3412" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding IoNameText}" Foreground="#7C2D12" FontSize="11" TextWrapping="Wrap"/>
|
||||
<TextBlock Text="{Binding LineNo, StringFormat=线标:{0}}" Foreground="#C2410C" FontSize="11"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding StateText}" Foreground="#C2410C" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Text="反馈信号" Foreground="#166534" FontWeight="Bold" Margin="0,0,0,8"/>
|
||||
<ItemsControl ItemsSource="{Binding FeedbackSignals}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="#F0FDF4" BorderBrush="#BBF7D0" BorderThickness="1" CornerRadius="4" Padding="8,6" Margin="0,0,0,6">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Style="{StaticResource CylinderDotStyle}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{Binding Name}" Foreground="#166534" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding IoNameText}" Foreground="#15803D" FontSize="11" TextWrapping="Wrap"/>
|
||||
<TextBlock Text="{Binding LineNo, StringFormat=线标:{0}}" Foreground="#15803D" FontSize="11"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding StateText}" Foreground="#166534" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CylinderView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CylinderView : UserControl
|
||||
{
|
||||
public CylinderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.DeviceIoView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="900">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="IoCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F8FAFD"/>
|
||||
<Setter Property="BorderBrush" Value="#D4DCE8"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Padding" Value="14"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StatusBadgeBorderStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="12"/>
|
||||
<Setter Property="Padding" Value="10,4"/>
|
||||
<Setter Property="Margin" Value="0,0,8,0"/>
|
||||
<Setter Property="Background" Value="#E2E8F0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="InputStatusDotStyle" TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="10"/>
|
||||
<Setter Property="Height" Value="10"/>
|
||||
<Setter Property="Fill" Value="#93C5FD"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOn}" Value="True">
|
||||
<Setter Property="Fill" Value="#2563EB"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="OutputStatusDotStyle" TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="10"/>
|
||||
<Setter Property="Height" Value="10"/>
|
||||
<Setter Property="Fill" Value="#FCD34D"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOn}" Value="True">
|
||||
<Setter Property="Fill" Value="#F97316"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="InputItemBorderStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#EFF6FF"/>
|
||||
<Setter Property="BorderBrush" Value="#DBEAFE"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="OutputItemBorderStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#FFF7ED"/>
|
||||
<Setter Property="BorderBrush" Value="#FED7AA"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoSectionBorderStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoOutputToggleButtonStyle" TargetType="ToggleButton">
|
||||
<Setter Property="Width" Value="90"/>
|
||||
<Setter Property="Height" Value="30"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Border x:Name="Root" Background="#CBD5E1" BorderBrush="#94A3B8" BorderThickness="1" CornerRadius="15">
|
||||
<Grid Margin="2">
|
||||
<Border x:Name="Knob" Width="24" Height="24" Background="White" CornerRadius="12" HorizontalAlignment="Left"/>
|
||||
<TextBlock x:Name="ToggleLabel" Text="OFF" Foreground="#334155" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="Root" Property="Background" Value="#16A34A"/>
|
||||
<Setter TargetName="Root" Property="BorderBrush" Value="#16A34A"/>
|
||||
<Setter TargetName="Knob" Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter TargetName="ToggleLabel" Property="Text" Value="ON"/>
|
||||
<Setter TargetName="ToggleLabel" Property="Foreground" Value="White"/>
|
||||
<Setter TargetName="ToggleLabel" Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter TargetName="ToggleLabel" Property="Margin" Value="10,0,0,0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Root" Property="Opacity" Value="0.45"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="#EDF1F7">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Margin="10,10,10,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="DEVICE IO MONITOR / 设备IO监控" FontSize="20" FontWeight="Bold" Foreground="#0F3B7A"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource StatusBadgeBorderStyle}">
|
||||
<TextBlock Text="{Binding PageState.LastRefreshTime, StringFormat=刷新:{0:HH:mm:ss}}" Foreground="#475569"/>
|
||||
</Border>
|
||||
<Border>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource StatusBadgeBorderStyle}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PageState.IsOnline}" Value="True">
|
||||
<Setter Property="Background" Value="#DCFCE7"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding PageState.IsOnline}" Value="False">
|
||||
<Setter Property="Background" Value="#FEE2E2"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock Text="{Binding PageState.OnlineText}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#B91C1C"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PageState.IsOnline}" Value="True">
|
||||
<Setter Property="Foreground" Value="#166534"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Border Margin="0,8,0,0" Padding="12,6">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource StatusBadgeBorderStyle}">
|
||||
<Setter Property="Background" Value="#EFF6FF"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PageState.IsWriteSuccess}" Value="True">
|
||||
<Setter Property="Background" Value="#DCFCE7"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding PageState.IsWriteSuccess}" Value="False">
|
||||
<Setter Property="Background" Value="#FEF3C7"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding PageState.LastWriteTime, StringFormat=写入时间:{0:HH:mm:ss}}" Foreground="#475569" Margin="0,0,14,0"/>
|
||||
<TextBlock Text="{Binding PageState.LastWriteMessage}" FontWeight="SemiBold" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" Margin="10,0,10,10" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding PageState.Modules}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource IoCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold" Foreground="#0F3B7A"/>
|
||||
|
||||
<Grid Grid.Row="1" Margin="0,10,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition>
|
||||
<ColumnDefinition.Style>
|
||||
<Style TargetType="ColumnDefinition">
|
||||
<Setter Property="Width" Value="*"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasInputs}" Value="False">
|
||||
<Setter Property="Width" Value="0"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ColumnDefinition.Style>
|
||||
</ColumnDefinition>
|
||||
<ColumnDefinition>
|
||||
<ColumnDefinition.Style>
|
||||
<Style TargetType="ColumnDefinition">
|
||||
<Setter Property="Width" Value="*"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasOutputs}" Value="False">
|
||||
<Setter Property="Width" Value="0"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ColumnDefinition.Style>
|
||||
</ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border BorderBrush="#BFDBFE" Background="#F8FBFF">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource IoSectionBorderStyle}">
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasInputs}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding HasOutputs}" Value="False">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel>
|
||||
<TextBlock Text="输入 IO" Foreground="#1D4ED8" FontWeight="Bold" Margin="0,0,0,8"/>
|
||||
<ItemsControl ItemsSource="{Binding InputPoints}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource InputItemBorderStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Style="{StaticResource InputStatusDotStyle}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{Binding Description}" Foreground="#1E3A8A" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding StationNo, StringFormat=站号:{0}}" Foreground="#1D4ED8" FontSize="11"/>
|
||||
<TextBlock Text="{Binding LineNo, StringFormat=线标:{0}}" Foreground="#1D4ED8" FontSize="11"/>
|
||||
<TextBlock Text="{Binding Name}" Foreground="#64748B" FontSize="11" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding StateText}" VerticalAlignment="Center" Foreground="#1E40AF" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Column="1" BorderBrush="#FDBA74" Background="#FFF9F2">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource IoSectionBorderStyle}">
|
||||
<Setter Property="Margin" Value="6,0,0,0"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasOutputs}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding HasInputs}" Value="False">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel>
|
||||
<TextBlock Text="输出 IO" Foreground="#C2410C" FontWeight="Bold" Margin="0,0,0,8"/>
|
||||
<ItemsControl ItemsSource="{Binding OutputPoints}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource OutputItemBorderStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Style="{StaticResource OutputStatusDotStyle}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{Binding Description}" Foreground="#9A3412" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding StationNo, StringFormat=站号:{0}}" Foreground="#C2410C" FontSize="11"/>
|
||||
<TextBlock Text="{Binding LineNo, StringFormat=线标:{0}}" Foreground="#C2410C" FontSize="11"/>
|
||||
<TextBlock Text="{Binding Name}" Foreground="#7C2D12" FontSize="11" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding StateText}" Margin="0,0,10,0" VerticalAlignment="Center" Foreground="#C2410C" FontWeight="Bold"/>
|
||||
<ToggleButton Grid.Column="3"
|
||||
Style="{StaticResource IoOutputToggleButtonStyle}"
|
||||
IsChecked="{Binding IsOn, Mode=OneWay}"
|
||||
Command="{Binding ToggleCommand}"
|
||||
IsEnabled="{Binding CanWrite}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
public partial class DeviceIoView : UserControl
|
||||
{
|
||||
public DeviceIoView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.DeviceMaintanceView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Margin="-40,0,0,0" Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<mw:SideMenu ItemsSource="{Binding MenuItemWraps}"
|
||||
SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}"
|
||||
Grid.Row ="0" Width="180"
|
||||
ExpandMode="Accordion"
|
||||
AutoSelect="True"
|
||||
>
|
||||
<mw:SideMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type mw:SideMenuItem}" BasedOn="{StaticResource SideMenuItemHeaderAccordionBaseStyle}">
|
||||
<Setter Property="Header" Value="{Binding Header}" />
|
||||
<Setter Property="Tag" Value="{Binding Tag}" />
|
||||
</Style>
|
||||
</mw:SideMenu.ItemContainerStyle>
|
||||
</mw:SideMenu>
|
||||
|
||||
</Grid>
|
||||
|
||||
<ContentControl Margin="5,0" Grid.Column="1" mw:View.Model="{Binding CurrentScreen}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// DeviceMaintanceView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DeviceMaintanceView : UserControl
|
||||
{
|
||||
public DeviceMaintanceView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.HardwareTestView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style x:Key="HardwareTestLabelStyle" TargetType="Label" BasedOn="{StaticResource ProcessLabelStyle}">
|
||||
<Setter Property="Width" Value="126"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestValueBorderStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F8FAFC"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource ProcessCardBorderBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="Padding" Value="12,6"/>
|
||||
<Setter Property="Margin" Value="8,0,18,0"/>
|
||||
<Setter Property="MinWidth" Value="150"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestValueTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource ProcessBodyForegroundBrush}"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestIntNumberBoxStyle" TargetType="{x:Type mw:IntNumberBox}" BasedOn="{StaticResource ProcessLargeIntNumberBoxStyle}">
|
||||
<Setter Property="Margin" Value="8,0,18,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestButtonStyle" TargetType="Button" BasedOn="{StaticResource TestButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Margin" Value="8,0,0,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestStartButtonStyle" TargetType="Button" BasedOn="{StaticResource StartButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Margin" Value="8,0,0,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HardwareTestStopButtonStyle" TargetType="Button" BasedOn="{StaticResource CloseButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Margin" Value="8,0,0,0"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="{StaticResource ProcessPageBackgroundBrush}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="4" Padding="0,0,4,0">
|
||||
<StackPanel Margin="0,0,0,4">
|
||||
<GroupBox Header="{DynamicResource Diastimeter}" Style="{StaticResource ProcessWideCardGroupBoxStyle}">
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource HardwareTestLabelStyle}" Content="{DynamicResource DiastimeterValue}"/>
|
||||
<Border Style="{StaticResource HardwareTestValueBorderStyle}">
|
||||
<TextBlock Style="{StaticResource HardwareTestValueTextStyle}" Text="{Binding Message}"/>
|
||||
</Border>
|
||||
<Button Style="{StaticResource HardwareTestButtonStyle}" Click="{mw:Action btnZeroClick}" Content="{DynamicResource SetZero}"/>
|
||||
<Button Style="{StaticResource HardwareTestButtonStyle}" Click="{mw:Action btnGetCurrentValueClick}" Content="{DynamicResource GetCurrentValue}"/>
|
||||
</WrapPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="FFU" Style="{StaticResource ProcessWideCardGroupBoxStyle}">
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource HardwareTestLabelStyle}" Content="{DynamicResource FFURotateSpeed}"/>
|
||||
<mw:IntNumberBox Style="{StaticResource HardwareTestIntNumberBoxStyle}" Value="{Binding FFURotateSpeed}" ValueChanged="{mw:Action FFURotateSpeedChanged}"/>
|
||||
<Button Style="{StaticResource HardwareTestStartButtonStyle}" Content="{DynamicResource Open}" Click="{mw:Action BtnOpenFFU}"/>
|
||||
<Button Style="{StaticResource HardwareTestStopButtonStyle}" Content="{DynamicResource Close}" Click="{mw:Action BtnCloseFFU}"/>
|
||||
</WrapPanel>
|
||||
</GroupBox>
|
||||
|
||||
<WrapPanel>
|
||||
<GroupBox Header="{DynamicResource WaferScaner}" Style="{StaticResource ProcessCardGroupBoxStyle}" Width="430" Margin="0,0,18,18">
|
||||
<WrapPanel>
|
||||
<Button Style="{StaticResource HardwareTestButtonStyle}" Click="{mw:Action btnScanWaferBarcodeClick}" Content="{DynamicResource GetCurrentValue}"/>
|
||||
<Border Style="{StaticResource HardwareTestValueBorderStyle}" MinWidth="180" Margin="8,0,0,0">
|
||||
<TextBlock Style="{StaticResource HardwareTestValueTextStyle}" Text="{Binding WaferBarcode}"/>
|
||||
</Border>
|
||||
</WrapPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="{DynamicResource GlassScaner}" Style="{StaticResource ProcessCardGroupBoxStyle}" Width="430" Margin="0,0,0,18">
|
||||
<WrapPanel>
|
||||
<Button Style="{StaticResource HardwareTestButtonStyle}" Click="{mw:Action btnScanGlassBarcodeClick}" Content="{DynamicResource GetCurrentValue}"/>
|
||||
<Border Style="{StaticResource HardwareTestValueBorderStyle}" MinWidth="180" Margin="8,0,0,0">
|
||||
<TextBlock Style="{StaticResource HardwareTestValueTextStyle}" Text="{Binding GlassBarcode}"/>
|
||||
</Border>
|
||||
</WrapPanel>
|
||||
</GroupBox>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// HardwareTestView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class HardwareTestView : UserControl
|
||||
{
|
||||
public HardwareTestView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.IOMaintanceView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Border Background="{StaticResource BackgroundBrush}" BorderBrush="{StaticResource BorderBrush}" BorderThickness="2,2,2,2">
|
||||
<TabControl mw:TabControlAttach.FontSize="14">
|
||||
<TabItem Header="IO监控" >
|
||||
<ContentControl mw:View.Model="{Binding IOMonitorViewModel}" Margin="15"/>
|
||||
</TabItem>
|
||||
<TabItem Header="气缸控制" >
|
||||
<ContentControl mw:View.Model="{Binding CylinderViewModel}" Margin="15"/>
|
||||
</TabItem>
|
||||
<TabItem Header="IO测试" >
|
||||
<ContentControl mw:View.Model="{Binding IoTestViewModel}" Margin="15"/>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.IOMonitorView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<ContentControl mw:View.Model="{Binding DeviceIoViewModel}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// IOMonitorView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class IOMonitorView : UserControl
|
||||
{
|
||||
public IOMonitorView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.IoTestView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="560" d:DesignWidth="980">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="IoTestGroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource ProcessWideCardGroupBoxStyle}">
|
||||
<Setter Property="Margin" Value="0,0,0,16"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoTestLabelStyle" TargetType="Label" BasedOn="{StaticResource ProcessLabelStyle}">
|
||||
<Setter Property="Width" Value="95"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoTestNumberBoxStyle" TargetType="{x:Type mw:IntNumberBox}" BasedOn="{StaticResource ProcessLargeIntNumberBoxStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Margin" Value="0,0,12,8"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoTestButtonStyle" TargetType="Button" BasedOn="{StaticResource TestButtonStyle}">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Margin" Value="0,0,12,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoTestResultBorderStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F8FAFC"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource ProcessCardBorderBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="Padding" Value="12,8"/>
|
||||
<Setter Property="Margin" Value="0,4,0,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IoTestCheckBoxStyle" TargetType="CheckBox">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="0,0,18,8"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="{StaticResource ProcessPageBackgroundBrush}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="4" Padding="0,0,4,0">
|
||||
<StackPanel Margin="0,0,0,4">
|
||||
<GroupBox Header="Delta IO状态" Style="{StaticResource IoTestGroupBoxStyle}">
|
||||
<StackPanel>
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="控制卡状态"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding CardStatusText}" TextWrapping="Wrap" Width="620"/>
|
||||
<Button Style="{StaticResource IoTestButtonStyle}" Content="刷新状态" Click="{mw:Action RefreshCardStatus}"/>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="数字量 Bit 测试" Style="{StaticResource IoTestGroupBoxStyle}">
|
||||
<StackPanel>
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="CardNo"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.CardNo}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Node"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.Node}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Slot"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.Slot}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Index"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.Index}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="SubIndex"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.SubIndex}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="BitNo"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.BitNo}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="IoType"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.IoType}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="ReadIoType"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding BitState.ReadIoType}"/>
|
||||
<CheckBox Style="{StaticResource IoTestCheckBoxStyle}" Content="写入值" IsChecked="{Binding BitState.WriteValue}"/>
|
||||
<CheckBox Style="{StaticResource IoTestCheckBoxStyle}" Content="读取结果" IsChecked="{Binding BitState.ReadValue}" IsEnabled="False"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel Margin="0,4,0,0">
|
||||
<Button Style="{StaticResource IoTestButtonStyle}" Content="读取 Bit" Click="{mw:Action ReadBit}"/>
|
||||
<Button Style="{StaticResource IoTestButtonStyle}" Content="写入 Bit" Click="{mw:Action WriteBit}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding BitState.ReturnCode, StringFormat=返回码:{0}}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<Border Style="{StaticResource IoTestResultBorderStyle}">
|
||||
<TextBlock Text="{Binding BitState.ResultMessage}" TextWrapping="Wrap"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="模拟量 DA 测试" Style="{StaticResource IoTestGroupBoxStyle}">
|
||||
<StackPanel>
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="CardNo"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.CardNo}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Node"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.Node}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Slot"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.Slot}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="Index"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.Index}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="SubIndex"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.SubIndex}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="ByteSize"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.ByteSize}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="IoType"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.IoType}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="写入值"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.WriteRawValue}"/>
|
||||
<Label Style="{StaticResource IoTestLabelStyle}" Content="读取值"/>
|
||||
<mw:IntNumberBox Style="{StaticResource IoTestNumberBoxStyle}" Value="{Binding DaState.ReadRawValue}" IsEnabled="False"/>
|
||||
</WrapPanel>
|
||||
|
||||
<WrapPanel>
|
||||
<CheckBox Style="{StaticResource IoTestCheckBoxStyle}" Content="有符号" IsChecked="{Binding DaState.Signed}"/>
|
||||
<Button Style="{StaticResource IoTestButtonStyle}" Content="读取 DA" Click="{mw:Action ReadDa}"/>
|
||||
<Button Style="{StaticResource IoTestButtonStyle}" Content="写入 DA" Click="{mw:Action WriteDa}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding DaState.ReturnCode, StringFormat=返回码:{0}}"/>
|
||||
</WrapPanel>
|
||||
|
||||
<Border Style="{StaticResource IoTestResultBorderStyle}">
|
||||
<TextBlock Text="{Binding DaState.ResultMessage}" TextWrapping="Wrap"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// IoTestView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class IoTestView : UserControl
|
||||
{
|
||||
public IoTestView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.LaserCompensationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="560"
|
||||
d:DesignWidth="900">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="Margin" Value="8,0,8,0"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource ProcessBodyForegroundBrush}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
|
||||
<Setter Property="Foreground" Value="{StaticResource ProcessBodyForegroundBrush}"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Margin" Value="8,0,0,0"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<Grid Background="{StaticResource ProcessPageBackgroundBrush}" Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Row="0" Header="{DynamicResource LaserCompensationParameters}" Style="{StaticResource ProcessWideCardGroupBoxStyle}">
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="280"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="280"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="280"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource AxisName}"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||
Style="{StaticResource ProcessLargeComboBoxStyle}"
|
||||
|
||||
ItemsSource="{Binding AxisNames}"
|
||||
SelectedItem="{Binding SelectedAxisName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="2" Content="{DynamicResource LaserCompensationStartPosition}"/>
|
||||
<mw:NumberBox Grid.Row="0" Grid.Column="3"
|
||||
Style="{StaticResource ProcessLargeNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.StartPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
DecimalPlaces="4"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="4" Content="{DynamicResource LaserCompensationStepDistance}"/>
|
||||
<mw:NumberBox Grid.Row="0" Grid.Column="5"
|
||||
Style="{StaticResource ProcessLargeNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.Steps, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
DecimalPlaces="4"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource LaserCompensationStepCount}"/>
|
||||
<mw:IntNumberBox Grid.Row="1" Grid.Column="1"
|
||||
Style="{StaticResource ProcessLargeIntNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.StepsCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="2" Content="{DynamicResource LaserCompensationJumpPosition}"/>
|
||||
<mw:NumberBox Grid.Row="1" Grid.Column="3"
|
||||
Style="{StaticResource ProcessLargeNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.JumpPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
DecimalPlaces="4"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="4" Content="{DynamicResource LaserCompensationCycleCount}"/>
|
||||
<mw:IntNumberBox Grid.Row="1" Grid.Column="5"
|
||||
Style="{StaticResource ProcessLargeIntNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.WorkCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Speed}"/>
|
||||
<mw:NumberBox Grid.Row="2" Grid.Column="1"
|
||||
Style="{StaticResource ProcessLargeNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.Speed, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
DecimalPlaces="4"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="2" Content="{DynamicResource LaserCompensationDelaySeconds}"/>
|
||||
<mw:NumberBox Grid.Row="2" Grid.Column="3"
|
||||
Style="{StaticResource ProcessLargeNumberBoxStyle}"
|
||||
|
||||
Value="{Binding Setting.DwellTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
DecimalPlaces="3"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
ShowUpDownButton="True"/>
|
||||
|
||||
<Button Grid.Row="2" Grid.Column="5" Content="{DynamicResource Save}" Click="{mw:Action Save}" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="1" Header="{DynamicResource LaserCompensationExecutionControl}" Style="{StaticResource ProcessWideCardGroupBoxStyle}" Margin="0,12,0,0">
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Content="{DynamicResource Start}" IsEnabled="{Binding UiEnable}" Click="{mw:Action StartAsync}"/>
|
||||
<Button Grid.Column="1" Content="{DynamicResource Stop}" IsEnabled="{Binding IsRunning}" Click="{mw:Action Stop}"/>
|
||||
|
||||
<TextBlock Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource LaserCompensationTrajectoryOrder}"
|
||||
Margin="18,0,0,0"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="2" Header="{DynamicResource LaserCompensationExecutionStatus}" Style="{StaticResource ProcessWideCardGroupBoxStyle}" Margin="0,12,0,0">
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Content="{DynamicResource LaserCompensationCurrentCycle}"/>
|
||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding CurrentLoopIndex}"/>
|
||||
<Label Grid.Column="2" Content="{DynamicResource LaserCompensationCurrentPoint}"/>
|
||||
<TextBlock Grid.Column="3" VerticalAlignment="Center" Text="{Binding CurrentPointIndex}"/>
|
||||
<Label Grid.Column="4" Content="{DynamicResource LaserCompensationCurrentTarget}"/>
|
||||
<TextBlock Grid.Column="5" VerticalAlignment="Center" Text="{Binding CurrentTargetPosition, StringFormat=F4}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="3" Header="{DynamicResource Description}" Style="{StaticResource ProcessWideCardGroupBoxStyle}" Margin="0,12,0,0">
|
||||
<StackPanel Margin="4">
|
||||
<TextBlock TextWrapping="Wrap"
|
||||
Text="{DynamicResource LaserCompensationDescriptionPrimary}"/>
|
||||
<TextBlock Margin="0,8,0,0"
|
||||
TextWrapping="Wrap"
|
||||
Text="{DynamicResource LaserCompensationDescriptionSecondary}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
public partial class LaserCompensationView : UserControl
|
||||
{
|
||||
public LaserCompensationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.NeedleBaseView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox Grid.Row="0" Background="#D7DDE4"
|
||||
Style="{StaticResource NavigationListBoxStyle}"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ItemsSource="{Binding NavigationItems}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate >
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}"
|
||||
FontWeight="Bold"
|
||||
Foreground="#505050"
|
||||
FontSize="14" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl Margin="2" Content="{Binding CameraAxisViewModel}"/>
|
||||
<Border BorderBrush="Gray" BorderThickness="1" Margin="5,2" Grid.Column="1">
|
||||
<ContentControl Margin="2"
|
||||
mw:View.Model="{Binding CurrentScreen}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// NeedleBaseView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class NeedleBaseView : UserControl
|
||||
{
|
||||
public NeedleBaseView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.NeedleCaliView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
xmlns:Att="clr-namespace:MainShell.Common.ControlAttribute"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="850" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="GroupBox" BasedOn="{StaticResource GroupStepControl}"/>
|
||||
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="80"/>
|
||||
</Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="90"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid mwControls:ParameterAttach.DelayAcceptValue="{Binding ParameterHelper}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible" Margin="5" ClipToBounds="True">
|
||||
<StackPanel>
|
||||
<GroupBox Header="【第一步】对刀仪偏差设置" IsEnabled="{Binding UiEnable}">
|
||||
<StackPanel Margin="5" HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Label Content="对刀时偏差:" />
|
||||
<mwControls:NumberBox Value="{Binding NeedleZCalibrationItem.KnifeOffset}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" HorizontalAlignment="Left" Margin="2" Width="80" Height="35" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第二步】SZ / StagePlatform设置" IsEnabled="{Binding UiEnable}">
|
||||
<customControl:AxisMoveControl LableContent1="SZ(mm):"
|
||||
Value1="{Binding NeedleZCalibrationItem.CZHeight}"
|
||||
LableContent2="StagePlatform高度:"
|
||||
Value2="{Binding NeedleZCalibrationItem.StageHeight}"
|
||||
IsAllShow="{Binding HasStagePlatform}"
|
||||
MoveCommand="{mwControls:Action MoveCzCurrentLocation}"/>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第三步】龙门2的避让位置" IsEnabled="{Binding UiEnable}">
|
||||
<customControl:AxisMoveControl LableContent1="X2(mm):"
|
||||
Value1="{Binding NeedleZCalibrationItem.Gantry2AvoidPositionX}"
|
||||
LableContent2="Y2(mm):"
|
||||
Value2="{Binding NeedleZCalibrationItem.Gantry2AvoidPositionY}"
|
||||
ReadCommand="{mwControls:Action ReadGantry2CurrentLocation}"
|
||||
MoveCommand="{mwControls:Action MoveGantry2ToCurrentLocation}"/>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第四步】针尖对准对刀仪位置" IsEnabled="{Binding UiEnable}">
|
||||
<customControl:AxisMoveControl LableContent1="X1(mm):"
|
||||
Value1="{Binding NeedleZCalibrationItem.SupportPinPositionX}"
|
||||
LableContent2="Y1(mm):"
|
||||
Value2="{Binding NeedleZCalibrationItem.SupportPinPositionY}"
|
||||
ReadCommand="{mwControls:Action ReadSupportPinCurrentLocation}"
|
||||
MoveCommand="{mwControls:Action MoveSupportPinToCurrentLocation}"/>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第五步】Z1设置" IsEnabled="{Binding UiEnable}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<UniformGrid Columns="4" Rows="1">
|
||||
<Label Content="开始位置(mm)" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding NeedleZCalibrationItem.Z1StartPosition}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Margin="2" Width="80" Height="35" />
|
||||
<Label Content="速度(mm/s)" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding NeedleZCalibrationItem.Z1Speed}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Left" Margin="2" Width="80" Height="35" />
|
||||
</UniformGrid>
|
||||
<UniformGrid Columns="2" Rows="1" Grid.Column="1">
|
||||
<Label Content="下降距离(mm)" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding NeedleZCalibrationItem.Z1DropMaxPosition}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="2" Width="80" Height="35" />
|
||||
</UniformGrid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第六步】刺针触碰到对刀仪" IsEnabled="{Binding UiEnable}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Visibility="Visible" Content="基准值(mm):" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Visibility="Visible" IsReadOnly="True" Value="{Binding NeedleZCalibrationItem.NeedleTouchHeightBase}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
|
||||
<Label Content="Z1平均高度(mm):" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox IsReadOnly="True" Value="{Binding NeedleZCalibrationItem.NeedleTouchHeightAve}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
|
||||
<Label Content="对刀次数:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding NeedleZCalibrationItem.NeedleTouchCount}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="1" Maximum="100" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
|
||||
<Label Content="当前使用对刀高度(mm):" Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right" Width="140"/>
|
||||
<mwControls:NumberBox IsEnabled="False" Grid.Row="3" Value="{Binding NeedleZCalibrationItem.CurrentNeedleTouchHeight}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
|
||||
<Label Content="对刀与基准偏差(mm):" Grid.Row="4" Grid.Column="0" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox IsReadOnly="True" Grid.Row="4" Value="{Binding NeedleZCalibrationItem.NeedleTouchOffset}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
|
||||
<Grid Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="5">
|
||||
<ListView ItemsSource="{Binding NeedleZCalibrationItem.NeedleTouchRecords}" SelectedItem="{Binding SelectedRecord}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="当前次数" DisplayMemberBinding="{Binding CurrentCount}" Width="100"/>
|
||||
<GridViewColumn Header="Z1高度(mm)" DisplayMemberBinding="{Binding Height}" Width="210"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="【第七步】对刀控制" IsEnabled="{Binding IsEnabledNeedleCalibrationControl}">
|
||||
<StackPanel>
|
||||
<StackPanel Margin="4" IsEnabled="{Binding UiEnable}" Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<CheckBox Content="自动抬高" Margin="6,0" IsChecked="{Binding AutoRaiseZ1}"/>
|
||||
<Button Visibility="Collapsed" Content="设置当前基准值" Tag="设置当前基准值" Click="{mwControls:Action SetBaseHeight}" Margin="6,0" />
|
||||
<Button Content="Z1对刀" Tag="Z1对刀" Margin="6,0" Click="{mwControls:Action StartSingleZ1CalibrationAsync}"/>
|
||||
<Button Content="使用当前对刀高度" Width="120" Tag="使用当前对刀高度" Click="{mwControls:Action UseCurrentZ1Height}" Margin="6,0" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="4" Orientation="Horizontal">
|
||||
<Button Content="开始" Tag="开始" Click="{mwControls:Action StartCalibrationAsync}" Margin="6,0" IsEnabled="{Binding UiEnable}"/>
|
||||
<Button Content="停止" Tag="停止" Click="{mwControls:Action StopCalibrationAsync}" Margin="6,0" IsEnabled="{Binding UiEnable, Converter={StaticResource boolToInversionConverter}}"/>
|
||||
<Button Content="保存" Tag="保存" Click="{mwControls:Action SaveCalibration}" Margin="6,0" IsEnabled="{Binding UiEnable}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// NeedleCaliView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class NeedleCaliView : UserControl
|
||||
{
|
||||
public NeedleCaliView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<UserControl x:Class="MainShell.DeviceMaintance.View.NeedleCameraPrintView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.DeviceMaintance.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="750" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="GroupBox" BasedOn="{StaticResource GroupStepControl}"/>
|
||||
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="80"/>
|
||||
</Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="90"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid mwControls:ParameterAttach.DelayAcceptValue ="{Binding ParameterHelper}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第一步】基础设置">
|
||||
<GroupBox.Content>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Button Click="{mwControls:Action MoveToOrginPos}" Content="SXSZ至初始位" Width="100"/>
|
||||
<GroupBox Header="速度设置" Style="{x:Null}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton GroupName="speed" Click="{mwControls:Action SpeedChanged}" Tag="10" Margin="5,0" Content="10"/>
|
||||
<RadioButton GroupName="speed" IsChecked="True" Click="{mwControls:Action SpeedChanged}" Tag="50" Margin="5,0" Content="50"/>
|
||||
<RadioButton GroupName="speed" Click="{mwControls:Action SpeedChanged}" Tag="100" Margin="5,0" Content="100"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第二步】WS避让位">
|
||||
<GroupBox.Content>
|
||||
<customControl:AxisMoveControl LableContent1="X2(mm):"
|
||||
Value1="{Binding NeedlePrintCalibrateParameter.AvoidancePoint.PointX}"
|
||||
LableContent2="Y2(mm):"
|
||||
Value2="{Binding NeedlePrintCalibrateParameter.AvoidancePoint.PointY}"
|
||||
ReadCommand="{mwControls:Action TeachWSPos}"
|
||||
MoveCommand="{mwControls:Action MoveToWsPos}"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Label VerticalAlignment="Center" Content="X2:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.AvoidancePoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y2:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.AvoidancePoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachWSPos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToWsPos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第三步】Z1位置设置">
|
||||
<GroupBox.Content>
|
||||
<customControl:AxisMoveControl LableContent1="Z1(mm):"
|
||||
Value1="{Binding NeedlePrintCalibrateParameter.Z1WorkHeight}"
|
||||
IsAllShow="False"
|
||||
ReadCommand="{mwControls:Action TeachZ1Pos}"
|
||||
MoveCommand="{mwControls:Action MoveToZ1Pos}"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Label VerticalAlignment="Center" Content="Z1:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding NeedlePrintCalibrateParameter.Z1WorkHeight, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="False" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachZ1Pos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToZ1Pos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第四步】Z2位置设置">
|
||||
<GroupBox.Content>
|
||||
<customControl:AxisMoveControl LableContent1="Z2(mm):"
|
||||
Value1="{Binding NeedlePrintCalibrateParameter.Z2WorkHeight}"
|
||||
IsAllShow="False"
|
||||
ReadCommand="{mwControls:Action TeachZ2Pos}"
|
||||
MoveCommand="{mwControls:Action MoveToZ2Pos}"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Label VerticalAlignment="Center" Content="Z2:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding NeedlePrintCalibrateParameter.Z2WorkHeight, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="False" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachZ2Pos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToZ2Pos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第五步】铜箔区域设置">
|
||||
<GroupBox.Content>
|
||||
<StackPanel>
|
||||
<Label Content="起点设置:"/>
|
||||
<customControl:AxisMoveControl LableContent1="X1(mm):"
|
||||
Value1="{Binding NeedlePrintCalibrateParameter.StartPoint.PointX}"
|
||||
LableContent2="Y1(mm):"
|
||||
Value2="{Binding NeedlePrintCalibrateParameter.StartPoint.PointY}"
|
||||
ReadCommand="{mwControls:Action TeachStartPos}"
|
||||
MoveCommand="{mwControls:Action MoveToStartPos}"
|
||||
IsReadOnly="True"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Label VerticalAlignment="Center" Content="X1:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.StartPoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y1:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.StartPoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachStartPos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToStartPos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
<Label Content="尾点设置:"/>
|
||||
<customControl:AxisMoveControl LableContent1="X2(mm):"
|
||||
Value1="{Binding NeedlePrintCalibrateParameter.EndPoint.PointX}"
|
||||
LableContent2="Y2(mm):"
|
||||
Value2="{Binding NeedlePrintCalibrateParameter.EndPoint.PointY}"
|
||||
ReadCommand="{mwControls:Action TeachEndPos}"
|
||||
MoveCommand="{mwControls:Action MoveToEndPos}"
|
||||
IsReadOnly="True"/>
|
||||
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Label VerticalAlignment="Center" Content="X1:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.EndPoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y1:"/>
|
||||
<mwControls:NumberBox Value="{Binding NeedlePrintCalibrateParameter.EndPoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachEndPos}" Content="示教"/>
|
||||
<Button Margin="2,0" Click="{mwControls:Action MoveToEndPos}" Content="移动"/>
|
||||
</StackPanel>-->
|
||||
<Label Content="间距设置:"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label VerticalAlignment="Center" Content="Xpitch:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding NeedlePrintCalibrateParameter.Xpitch}" IsReadOnly="False" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Ypitch:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding NeedlePrintCalibrateParameter.Ypitch}" IsReadOnly="False" Width="80" Margin="4,0" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox Margin="2" Header="【第六步】针印检验">
|
||||
<GroupBox.Content>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button IsEnabled="{Binding UiEnable}" Click="{mwControls:Action StartVerify}" Content="开始校验"/>
|
||||
<Button IsEnabled="{Binding UiEnable,Converter={StaticResource boolToInversionConverter}}" Click="{mwControls:Action StopVerify}" Content="停止校验"/>
|
||||
<Button IsEnabled="{Binding UiEnable}" Click="{mwControls:Action SaveParam}" Content="保存"/>
|
||||
<Button IsEnabled="{Binding UiEnable}" Click="{mwControls:Action ResetRecord}" Content="重置记录"/>
|
||||
</StackPanel>
|
||||
<StackPanel IsEnabled="{Binding UiEnable}" Margin="0,2" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Click="{mwControls:Action NeedleAlignment}" Content="针尖对准"/>
|
||||
<Button Click="{mwControls:Action CameraAlignment}" Content="相机对准"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
<GroupBox IsEnabled="{Binding UiEnable}" Margin="2" Header="【第七步】偏差补偿">
|
||||
<GroupBox.Content>
|
||||
<StackPanel>
|
||||
<Label Content="当前针尖补偿:" Width="90"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label VerticalAlignment="Center" Content="XOffset:"/>
|
||||
<mwControls:NumberBox Value="{Binding CurrentNeedleOffsetPoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="YOffsetY:"/>
|
||||
<mwControls:NumberBox Value="{Binding CurrentNeedleOffsetPoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
</StackPanel>
|
||||
<Label Content="针尖点位:"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label VerticalAlignment="Center" Content="X1:"/>
|
||||
<mwControls:NumberBox Value="{Binding CurrentNeedlePoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y1:"/>
|
||||
<mwControls:NumberBox Value="{Binding CurrentNeedlePoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
</StackPanel>
|
||||
<Label Content="相机点位:"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<Label VerticalAlignment="Center" Content="X1:"/>
|
||||
<mwControls:NumberBox Value="{Binding CameraPoint.PointX}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Label VerticalAlignment="Center" Content="Y1:"/>
|
||||
<mwControls:NumberBox Value="{Binding CameraPoint.PointY}" IsReadOnly="True" Width="80" Margin="4,0" />
|
||||
<Button Margin="2,0" Click="{mwControls:Action TeachCameraPos}" Content="示教"/>
|
||||
<Button Margin="2,0" Content="补偿偏差" Click="{mwControls:Action CalculateOffset}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</GroupBox.Content>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.DeviceMaintance.View
|
||||
{
|
||||
/// <summary>
|
||||
/// NeedleCameraPrintView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class NeedleCameraPrintView : UserControl
|
||||
{
|
||||
public NeedleCameraPrintView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using MainShell.DeviceMaintance.Model;
|
||||
using MainShell.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.ViewModel
|
||||
{
|
||||
public class CameraAccuracyCalibrationViewModel: DeviceMaintanceBaseViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
using MainShell.DeviceMaintance.Model;
|
||||
using MainShell.DeviceMaintance.ViewModel.State;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Manual.ViewModel.State;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.ViewModel
|
||||
{
|
||||
public class CylinderViewModel : Screen, IPage
|
||||
{
|
||||
private readonly IDeviceIoMonitorService _ioMonitorService;
|
||||
private readonly IDeviceCylinderService _cylinderService;
|
||||
private readonly Dictionary<string, List<CylinderSignalState>> _signalMap = new Dictionary<string, List<CylinderSignalState>>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, DeviceIoPointDefinition> _ioDefinitionsByName;
|
||||
|
||||
private CylinderPageState _pageState;
|
||||
public CylinderPageState PageState
|
||||
{
|
||||
get { return _pageState; }
|
||||
set { SetAndNotify(ref _pageState, value); }
|
||||
}
|
||||
|
||||
public CylinderViewModel(IDeviceIoMonitorService ioMonitorService, IDeviceCylinderService cylinderService)
|
||||
{
|
||||
_ioMonitorService = ioMonitorService;
|
||||
_cylinderService = cylinderService;
|
||||
_ioDefinitionsByName = _ioMonitorService.Definitions.ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);
|
||||
PageState = BuildState();
|
||||
_ioMonitorService.IoChanged += OnIoChanged;
|
||||
_ioMonitorService.Start();
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
ApplyIoPoints(_ioMonitorService.LatestPoints.Values);
|
||||
InitializePointsAsync();
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
_ioMonitorService.IoChanged -= OnIoChanged;
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private CylinderPageState BuildState()
|
||||
{
|
||||
var state = new CylinderPageState();
|
||||
_signalMap.Clear();
|
||||
|
||||
foreach (var definition in _cylinderService.Definitions)
|
||||
{
|
||||
var item = new CylinderItemState
|
||||
{
|
||||
Name = definition.Name,
|
||||
Description = definition.Description,
|
||||
Module = definition.Module,
|
||||
ControlTypeText = GetControlTypeText(definition.ControlType)
|
||||
};
|
||||
|
||||
item.ExtendCommand = new ActionCommand(() => ExecuteCylinderAction(definition, item, true), () => !item.IsBusy);
|
||||
item.RetractCommand = new ActionCommand(() => ExecuteCylinderAction(definition, item, false), () => !item.IsBusy);
|
||||
|
||||
for (var i = 0; i < definition.ExtendOutputPoints.Count; i++)
|
||||
{
|
||||
AddOutputSignal(item, definition.ExtendOutputPoints[i], definition.ExtendOutputPoints.Count > 1 ? string.Format("{0}-伸出输出{1}", definition.Name, i + 1) : definition.Name + "-伸出输出");
|
||||
}
|
||||
|
||||
for (var i = 0; i < definition.RetractOutputPoints.Count; i++)
|
||||
{
|
||||
AddOutputSignal(item, definition.RetractOutputPoints[i], definition.RetractOutputPoints.Count > 1 ? string.Format("{0}-缩回输出{1}", definition.Name, i + 1) : definition.Name + "-缩回输出");
|
||||
}
|
||||
|
||||
foreach (var pointReference in definition.ExtendedFeedbackPoints)
|
||||
{
|
||||
AddFeedbackSignal(item, pointReference, definition.Name + "-伸出到位");
|
||||
}
|
||||
|
||||
foreach (var pointReference in definition.RetractedFeedbackPoints)
|
||||
{
|
||||
AddFeedbackSignal(item, pointReference, definition.Name + "-缩回到位");
|
||||
}
|
||||
|
||||
state.Cylinders.Add(item);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private void AddOutputSignal(CylinderItemState item, string pointReference, string fallbackName)
|
||||
{
|
||||
var definition = ResolveDefinition(pointReference);
|
||||
var signal = new CylinderSignalState
|
||||
{
|
||||
PointReference = pointReference,
|
||||
PointKey = definition?.PointKey,
|
||||
Name = definition != null ? definition.Name : fallbackName,
|
||||
LineNo = definition != null ? definition.LineNo : string.Empty,
|
||||
IsOutput = true
|
||||
};
|
||||
item.OutputSignals.Add(signal);
|
||||
MapSignal(signal, pointReference);
|
||||
}
|
||||
|
||||
private void AddFeedbackSignal(CylinderItemState item, string pointReference, string fallbackName)
|
||||
{
|
||||
var definition = ResolveDefinition(pointReference);
|
||||
var signal = new CylinderSignalState
|
||||
{
|
||||
PointReference = pointReference,
|
||||
PointKey = definition?.PointKey,
|
||||
Name = definition != null ? definition.Name : fallbackName,
|
||||
LineNo = definition != null ? definition.LineNo : string.Empty,
|
||||
IsOutput = false
|
||||
};
|
||||
item.FeedbackSignals.Add(signal);
|
||||
MapSignal(signal, pointReference);
|
||||
}
|
||||
|
||||
private DeviceIoPointDefinition ResolveDefinition(string pointReference)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pointReference))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DeviceIoPointDefinition definition;
|
||||
if (_ioDefinitionsByName.TryGetValue(pointReference, out definition))
|
||||
{
|
||||
return definition;
|
||||
}
|
||||
|
||||
int id;
|
||||
if (!int.TryParse(pointReference, out id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches = _ioMonitorService.Definitions.Where(x => x.Id == id).Take(2).ToList();
|
||||
return matches.Count == 1 ? matches[0] : null;
|
||||
}
|
||||
|
||||
private void MapSignal(CylinderSignalState signal, string pointReference)
|
||||
{
|
||||
var key = !string.IsNullOrWhiteSpace(signal.PointKey) ? signal.PointKey : pointReference;
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<CylinderSignalState> signals;
|
||||
if (!_signalMap.TryGetValue(key, out signals))
|
||||
{
|
||||
signals = new List<CylinderSignalState>();
|
||||
_signalMap[key] = signals;
|
||||
}
|
||||
|
||||
signals.Add(signal);
|
||||
}
|
||||
|
||||
private void OnIoChanged(object sender, EventArgs e)
|
||||
{
|
||||
var args = e as MainShell.EventArgsFolder.DeviceIoChangedEventArgs;
|
||||
if (args == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyIoPoints(args.ChangedPoints);
|
||||
}
|
||||
|
||||
private async void InitializePointsAsync()
|
||||
{
|
||||
_ioMonitorService.RequestRefresh();
|
||||
await Task.Delay(150);
|
||||
ApplyIoPoints(_ioMonitorService.LatestPoints.Values);
|
||||
}
|
||||
|
||||
private void ApplyIoPoints(IEnumerable<DeviceIoPointState> points)
|
||||
{
|
||||
if (points == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
if (point == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
List<CylinderSignalState> signals;
|
||||
if (!_signalMap.TryGetValue(point.PointKey, out signals))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var signal in signals)
|
||||
{
|
||||
signal.IsOn = point.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteCylinderAction(CylinderDefinition definition, CylinderItemState item, bool extend)
|
||||
{
|
||||
item.IsBusy = true;
|
||||
RaiseCommands(item);
|
||||
|
||||
string failureReason;
|
||||
var result = extend ? _cylinderService.TryExtend(definition.Name, out failureReason) : _cylinderService.TryRetract(definition.Name, out failureReason);
|
||||
|
||||
if (result)
|
||||
{
|
||||
SimulateCylinderFeedback(definition, extend);
|
||||
PageState.LastActionMessage = definition.Name + (extend ? " 执行伸出成功。" : " 执行缩回成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
PageState.LastActionMessage = string.IsNullOrWhiteSpace(failureReason)
|
||||
? definition.Name + (extend ? " 伸出失败。" : " 缩回失败。")
|
||||
: failureReason;
|
||||
}
|
||||
|
||||
PageState.LastActionTime = DateTime.Now;
|
||||
item.IsBusy = false;
|
||||
RaiseCommands(item);
|
||||
}
|
||||
|
||||
private void SimulateCylinderFeedback(CylinderDefinition definition, bool extend)
|
||||
{
|
||||
foreach (var output in definition.ExtendOutputPoints.SelectMany(GetSignals))
|
||||
{
|
||||
output.IsOn = extend;
|
||||
}
|
||||
|
||||
foreach (var output in definition.RetractOutputPoints.SelectMany(GetSignals))
|
||||
{
|
||||
output.IsOn = !extend;
|
||||
}
|
||||
|
||||
foreach (var feedback in definition.ExtendedFeedbackPoints.SelectMany(GetSignals))
|
||||
{
|
||||
feedback.IsOn = extend;
|
||||
}
|
||||
|
||||
foreach (var feedback in definition.RetractedFeedbackPoints.SelectMany(GetSignals))
|
||||
{
|
||||
feedback.IsOn = !extend;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<CylinderSignalState> GetSignals(string pointReference)
|
||||
{
|
||||
var definition = ResolveDefinition(pointReference);
|
||||
var key = definition != null ? definition.PointKey : pointReference;
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return Enumerable.Empty<CylinderSignalState>();
|
||||
}
|
||||
|
||||
List<CylinderSignalState> signals;
|
||||
if (_signalMap.TryGetValue(key, out signals))
|
||||
{
|
||||
return signals;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<CylinderSignalState>();
|
||||
}
|
||||
|
||||
private static void RaiseCommands(CylinderItemState item)
|
||||
{
|
||||
var extend = item.ExtendCommand as ActionCommand;
|
||||
if (extend != null)
|
||||
{
|
||||
extend.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
var retract = item.RetractCommand as ActionCommand;
|
||||
if (retract != null)
|
||||
{
|
||||
retract.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetControlTypeText(CylinderControlType controlType)
|
||||
{
|
||||
switch (controlType)
|
||||
{
|
||||
case CylinderControlType.DualOutput:
|
||||
return "双输出控制";
|
||||
case CylinderControlType.MultiOutput:
|
||||
return "多输出单控";
|
||||
default:
|
||||
return "单输出控制";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using MainShell.EventArgsFolder;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Manual.Model;
|
||||
using MainShell.DeviceMaintance.ViewModel.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.DeviceMaintance.ViewModel
|
||||
{
|
||||
public class DeviceIoViewModel : OperateViewModelBase
|
||||
{
|
||||
private readonly IDeviceIoMonitorService _ioMonitorService;
|
||||
private readonly Dictionary<string, DeviceIoPointItemState> _pointStateMap = new Dictionary<string, DeviceIoPointItemState>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private DeviceIoPageState _pageState;
|
||||
public DeviceIoPageState PageState
|
||||
{
|
||||
get { return _pageState; }
|
||||
set { SetAndNotify(ref _pageState, value); }
|
||||
}
|
||||
|
||||
public DeviceIoViewModel(IDeviceIoMonitorService ioMonitorService)
|
||||
{
|
||||
_ioMonitorService = ioMonitorService;
|
||||
PageState = BuildState();
|
||||
_ioMonitorService.IoChanged += OnIoChanged;
|
||||
_ioMonitorService.Start();
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
RefreshFromCurrentPoints();
|
||||
InitializeLatestPointsAsync();
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
_ioMonitorService.IoChanged -= OnIoChanged;
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private DeviceIoPageState BuildState()
|
||||
{
|
||||
var state = new DeviceIoPageState();
|
||||
_pointStateMap.Clear();
|
||||
|
||||
foreach (var moduleGroup in _ioMonitorService.Definitions.GroupBy(x => string.IsNullOrWhiteSpace(x.Module) ? "Default" : x.Module))
|
||||
{
|
||||
var moduleState = new DeviceIoModuleState
|
||||
{
|
||||
Name = moduleGroup.Key
|
||||
};
|
||||
|
||||
foreach (var definition in moduleGroup.OrderBy(x => x.StationNo).ThenBy(x => x.Id).ThenBy(x => x.LineNo))
|
||||
{
|
||||
var item = new DeviceIoPointItemState
|
||||
{
|
||||
Id = definition.Id,
|
||||
PointKey = definition.PointKey,
|
||||
Module = definition.Module,
|
||||
Name = definition.Name,
|
||||
StationNo = definition.StationNo,
|
||||
LineNo = definition.LineNo,
|
||||
Description = definition.Description,
|
||||
IsOutput = definition.Type == IoPointType.Output,
|
||||
IsOn = definition.DefaultValue,
|
||||
IsInverse = definition.IsInverse,
|
||||
CanWrite = definition.Type == IoPointType.Output && definition.Enabled,
|
||||
};
|
||||
|
||||
if (item.IsOutput)
|
||||
{
|
||||
var command = new ActionCommand(() => ToggleOutput(item), () => item.CanWrite);
|
||||
item.ToggleCommand = command;
|
||||
}
|
||||
|
||||
_pointStateMap[item.PointKey] = item;
|
||||
|
||||
if (item.IsOutput)
|
||||
{
|
||||
moduleState.OutputPoints.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
moduleState.InputPoints.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
state.Modules.Add(moduleState);
|
||||
}
|
||||
|
||||
state.IsOnline = _ioMonitorService.IsOnline;
|
||||
return state;
|
||||
}
|
||||
|
||||
private async void InitializeLatestPointsAsync()
|
||||
{
|
||||
_ioMonitorService.RequestRefresh();
|
||||
await Task.Delay(150);
|
||||
RefreshFromCurrentPoints();
|
||||
}
|
||||
|
||||
private void RefreshFromCurrentPoints()
|
||||
{
|
||||
var points = _ioMonitorService.LatestPoints.Values.ToList();
|
||||
ApplyPoints(points);
|
||||
}
|
||||
|
||||
private void OnIoChanged(object sender, EventArgs e)
|
||||
{
|
||||
var args = e as DeviceIoChangedEventArgs;
|
||||
if (args == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyPoints(args.ChangedPoints);
|
||||
PageState.LastRefreshTime = DateTime.Now;
|
||||
}
|
||||
|
||||
private void ApplyPoints(IEnumerable<DeviceIoPointState> points)
|
||||
{
|
||||
if (points == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hasPoint = false;
|
||||
foreach (var point in points)
|
||||
{
|
||||
if (point == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasPoint = true;
|
||||
DeviceIoPointItemState item;
|
||||
if (!_pointStateMap.TryGetValue(point.PointKey, out item))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.IsOn = point.Value;
|
||||
|
||||
var outputPoint = point as DeviceOutputPointState;
|
||||
item.CanWrite = outputPoint != null && outputPoint.CanWrite;
|
||||
|
||||
var command = item.ToggleCommand as ActionCommand;
|
||||
if (command != null)
|
||||
{
|
||||
command.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPoint)
|
||||
{
|
||||
PageState.LastRefreshTime = DateTime.Now;
|
||||
}
|
||||
|
||||
PageState.IsOnline = hasPoint && _ioMonitorService.IsOnline;
|
||||
}
|
||||
|
||||
private void ToggleOutput(DeviceIoPointItemState item)
|
||||
{
|
||||
DeviceIoPointState point;
|
||||
if (!_ioMonitorService.TryGetPoint(item.PointKey, out point))
|
||||
{
|
||||
UpdateWriteResult(item.Name + " 写入失败:未找到输出点。", false);
|
||||
return;
|
||||
}
|
||||
|
||||
var outputPoint = point as DeviceOutputPointState;
|
||||
if (outputPoint == null || !outputPoint.CanWrite)
|
||||
{
|
||||
UpdateWriteResult(item.Name + " 写入失败:输出点不可写。", false);
|
||||
return;
|
||||
}
|
||||
|
||||
var targetState = !item.IsOn;
|
||||
var result = outputPoint.TrySetOutput(targetState);
|
||||
UpdateWriteResult(item.Name + (result ? (targetState ? " 已切换为 ON。" : " 已切换为 OFF。") : " 写入失败。"), result);
|
||||
}
|
||||
|
||||
private void UpdateWriteResult(string message, bool success)
|
||||
{
|
||||
PageState.LastWriteMessage = message;
|
||||
PageState.IsWriteSuccess = success;
|
||||
PageState.LastWriteTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using MainShell.HeightMeasure.ViewModel;
|
||||
using MainShell.Models;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using Stylet;
|
||||
using StyletIoC;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace MainShell.DeviceMaintance.ViewModel
|
||||
{
|
||||
public class DeviceMaintanceViewModel : BaseScreen, IPage
|
||||
{
|
||||
public string Name => "MenuDeviceMaint";
|
||||
private const string NEEDLEBASE = "刺晶头维护";
|
||||
private const string IOMONITOR = "IO监控";
|
||||
private const string HARDWARETEST = "硬件维护";
|
||||
private const string LASERCOMPENSATION = "激光补偿";
|
||||
private readonly Dictionary<string, Screen> _viewModelDict = new Dictionary<string, Screen>();
|
||||
public ObservableCollection<MenuItemWrap> MenuItemWraps { get; private set; }
|
||||
|
||||
private MenuItemWrap _selectedMenuItem;
|
||||
|
||||
public MenuItemWrap SelectedMenuItem
|
||||
{
|
||||
get { return _selectedMenuItem; }
|
||||
set
|
||||
{
|
||||
if (SetAndNotify(ref _selectedMenuItem, value))
|
||||
{
|
||||
CurrentScreen = _viewModelDict[value.Header];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Screen _currentScreen;
|
||||
|
||||
public Screen CurrentScreen
|
||||
{
|
||||
get { return _currentScreen; }
|
||||
set { SetAndNotify(ref _currentScreen, value); }
|
||||
}
|
||||
|
||||
private NeedleBaseViewModel _needleBaseViewModel;
|
||||
[Inject]
|
||||
public NeedleBaseViewModel NeedleBaseViewModel
|
||||
{
|
||||
get { return _needleBaseViewModel; }
|
||||
set { _needleBaseViewModel = value; }
|
||||
}
|
||||
|
||||
private IOMaintanceViewModel _ioMaintanceViewModel;
|
||||
[Inject]
|
||||
public IOMaintanceViewModel IOMaintanceViewModel
|
||||
{
|
||||
get { return _ioMaintanceViewModel; }
|
||||
set { _ioMaintanceViewModel = value; }
|
||||
}
|
||||
|
||||
private HardwareTestViewModel _hardwareTestViewModel;
|
||||
[Inject]
|
||||
public HardwareTestViewModel HardwareTestViewModel
|
||||
{
|
||||
get { return _hardwareTestViewModel; }
|
||||
set { _hardwareTestViewModel = value; }
|
||||
}
|
||||
|
||||
private LaserCompensationViewModel _laserCompensationViewModel;
|
||||
[Inject]
|
||||
public LaserCompensationViewModel LaserCompensationViewModel
|
||||
{
|
||||
get { return _laserCompensationViewModel; }
|
||||
set { _laserCompensationViewModel = value; }
|
||||
}
|
||||
|
||||
public DeviceMaintanceViewModel()
|
||||
{
|
||||
InitMenuItems();
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (_viewModelDict.Count == 0)
|
||||
{
|
||||
InitViewModelDict();
|
||||
}
|
||||
|
||||
if (SelectedMenuItem == null)
|
||||
{
|
||||
SelectedMenuItem = MenuItemWraps[0];
|
||||
}
|
||||
}
|
||||
|
||||
private void InitMenuItems()
|
||||
{
|
||||
MenuItemWraps = new ObservableCollection<MenuItemWrap>
|
||||
{
|
||||
new MenuItemWrap() { Header = NEEDLEBASE, Tag = NEEDLEBASE },
|
||||
new MenuItemWrap() { Header = IOMONITOR, Tag = IOMONITOR },
|
||||
new MenuItemWrap() { Header = HARDWARETEST, Tag = HARDWARETEST },
|
||||
new MenuItemWrap() { Header = LASERCOMPENSATION, Tag = LASERCOMPENSATION },
|
||||
};
|
||||
}
|
||||
|
||||
private void InitViewModelDict()
|
||||
{
|
||||
_viewModelDict.Clear();
|
||||
_viewModelDict.Add(NEEDLEBASE, NeedleBaseViewModel);
|
||||
_viewModelDict.Add(IOMONITOR, IOMaintanceViewModel);
|
||||
_viewModelDict.Add(HARDWARETEST, HardwareTestViewModel);
|
||||
_viewModelDict.Add(LASERCOMPENSATION, LaserCompensationViewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user