alielie
2025-03-23 40014e6e41f1ec017a07b7a620b3c700807d0519
新增DOControl
39个文件已修改
21个文件已添加
1个文件已删除
2704 ■■■■■ 已修改文件
HMI.AlermInfoManage/HMI.AlarmInfoManage.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.AlermInfoManage/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.DataViewer/HMI.DataViewer.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.DataViewer/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.IOMonitor/HMI.IOMonitor.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.IOMonitor/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.LogViewer/HMI.LogViewer.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.LogViewer/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.MenuManage/HMI.MenuManage.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.MenuManage/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.ParameterManage/HMI.ParameterManage.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.ParameterManage/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.SettingControl/HMI.SettingControl.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.SettingControl/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/Converter/VisibilityBoolConverter.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/Custom/NumberInput.cs 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/DpUtil/FormGroupHelper.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/HMI.UI.csproj 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/Style/FormStyle.xaml 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/Style/MsgBoxStyle.xaml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/Style/PanuonResource.xaml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UI/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UnitTest/HMI.UnitTest.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.UnitTest/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Libs/OpcInterface.dll 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/DOControl.xaml 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/DOControl.xaml.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Plugin.DOControl.csproj 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Properties/AssemblyInfo.cs 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Properties/Resources.Designer.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Properties/Resources.resx 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Properties/Settings.Designer.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/Properties/Settings.settings 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.DOControl/packages.config 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/Entity/ServoData.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/Entity/ServoProductData.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/NumberPanel.xaml 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/NumberPanel.xaml.cs 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/Plugin.ServoManage.csproj 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoManage.xaml 448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoManage.xaml.cs 707 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoModal.xaml 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoModal.xaml.cs 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoProductModal.xaml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoProductModal.xaml.cs 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoSetting.xaml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/ServoSetting.xaml.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.ServoManage/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TestResult/Plugin.TestResult.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TestResult/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TsExecution/Plugin.TsExecution.csproj 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TsExecution/TsExecution.xaml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TsExecution/TsExecution.xaml.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Plugin.TsExecution/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/App.config 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/Lang/en-US/ServoManage.json 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/Lang/zh-CN/ServoManage.json 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/PanuonWindow.xaml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/WPFProject.csproj 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/WPFProject.sln 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WPFProject/packages.config 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HMI.AlermInfoManage/HMI.AlarmInfoManage.csproj
@@ -71,8 +71,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="SimensDriver">
      <HintPath>..\Libs\SimensDriver.dll</HintPath>
HMI.AlermInfoManage/packages.config
@@ -3,6 +3,6 @@
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="NPOI" version="2.4.1" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="SharpZipLib" version="1.0.0" targetFramework="net472" />
</packages>
HMI.DataViewer/HMI.DataViewer.csproj
@@ -71,8 +71,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.DataViewer/packages.config
@@ -3,6 +3,6 @@
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="NPOI" version="2.4.1" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="SharpZipLib" version="1.0.0" targetFramework="net472" />
</packages>
HMI.IOMonitor/HMI.IOMonitor.csproj
@@ -74,8 +74,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="SimensDriver">
      <HintPath>..\Libs\SimensDriver.dll</HintPath>
HMI.IOMonitor/packages.config
@@ -3,6 +3,6 @@
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="NPOI" version="2.4.1" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="SharpZipLib" version="1.0.0" targetFramework="net472" />
</packages>
HMI.LogViewer/HMI.LogViewer.csproj
@@ -56,8 +56,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.LogViewer/packages.config
@@ -2,5 +2,5 @@
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
HMI.MenuManage/HMI.MenuManage.csproj
@@ -62,8 +62,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.MenuManage/packages.config
@@ -3,5 +3,5 @@
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
HMI.ParameterManage/HMI.ParameterManage.csproj
@@ -57,8 +57,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.ParameterManage/packages.config
@@ -2,5 +2,5 @@
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
HMI.SettingControl/HMI.SettingControl.csproj
@@ -56,8 +56,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.SettingControl/packages.config
@@ -2,5 +2,5 @@
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
HMI.UI/Converter/VisibilityBoolConverter.cs
@@ -18,7 +18,11 @@
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
            if (value is Visibility flag && flag == Visibility.Visible)
            {
                return true;
            }
            return false;
        }
    }
}
HMI.UI/Custom/NumberInput.cs
New file
@@ -0,0 +1,98 @@
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace HMI.UI
{
    public class NumberInput : TextBox
    {
        public NumberInput()
        {
            DataObject.AddPastingHandler(this, OnPasting);
            // 禁用输入法
            InputMethod.SetIsInputMethodEnabled(this, false);
            // 设置输入法模式为字母
            InputScope inputScope = new InputScope();
            InputScopeName inputScopeName = new InputScopeName();
            inputScopeName.NameValue = InputScopeNameValue.Number;
            inputScope.Names.Add(inputScopeName);
            this.InputScope = inputScope;
        }
        static NumberInput()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NumberInput),
                new FrameworkPropertyMetadata(typeof(NumberInput)));
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }
        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            // 允许输入数字、负号和小数点
            Regex regex = new Regex(@"^-?\d*\.?\d*$");
            string newText = this.Text.Insert(this.CaretIndex, e.Text);
            // 检查是否已经有负号,如果有则不允许再输入负号
            if (e.Text == "-" && this.Text.Contains("-"))
            {
                e.Handled = true;
                return;
            }
            // 检查是否已经有小数点,如果有则不允许再输入小数点
            if (e.Text == "." && this.Text.Contains("."))
            {
                e.Handled = true;
                return;
            }
            // 验证完整的新文本是否符合数字格式
            if (!regex.IsMatch(newText))
            {
                e.Handled = true;
                return;
            }
            base.OnPreviewTextInput(e);
        }
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            // 允许使用退格键和删除键
            if (e.Key == Key.Back || e.Key == Key.Delete)
            {
                base.OnPreviewKeyDown(e);
                return;
            }
            // 允许复制粘贴等快捷键
            if (Keyboard.Modifiers == ModifierKeys.Control &&
                (e.Key == Key.C || e.Key == Key.V || e.Key == Key.X))
            {
                base.OnPreviewKeyDown(e);
                return;
            }
        }
        private void OnPasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof(string)))
            {
                string text = (string)e.DataObject.GetData(typeof(string));
                Regex regex = new Regex(@"^-?\d*\.?\d*$");
                if (!regex.IsMatch(text))
                {
                    e.CancelCommand();
                }
            }
        }
    }
}
HMI.UI/DpUtil/FormGroupHelper.cs
@@ -92,7 +92,7 @@
            if (content is ComboBox cBox) return cBox.SelectedItem ?? cBox.SelectedValue ?? cBox.Text;
            if (content is Panel panel) return GetValidateValue(panel.Children);
            if (content is NumberInput numberInput) return numberInput.Value;
            if (content is Panuon.WPF.UI.NumberInput numberInput) return numberInput.Value;
            if (content is PasswordBox passwordInput) return passwordInput.Password;
            return null;
        }
HMI.UI/HMI.UI.csproj
@@ -61,8 +61,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Data" />
@@ -84,6 +84,7 @@
    <Compile Include="Converter\DataGridRowFlagConverter.cs" />
    <Compile Include="Converter\DataGridRowNumberConverter.cs" />
    <Compile Include="Converter\PathImageConverter.cs" />
    <Compile Include="Custom\NumberInput.cs" />
    <Compile Include="DpUtil\DataGridHelper.cs" />
    <Compile Include="DpUtil\DataGridTextColumnHelper.cs" />
    <Compile Include="DpUtil\FormGroupHelper.cs" />
HMI.UI/Style/FormStyle.xaml
HMI.UI/Style/MsgBoxStyle.xaml
@@ -13,6 +13,7 @@
                <Setter Property="pu:WindowXCaption.Foreground" Value="{StaticResource WarningColorContract}" />
                <Setter Property="Width" Value="350" />
                <Setter Property="Height" Value="200" />
                <Setter Property="SizeToContent" Value="Manual" />
            </Style>
        </pu:MessageBoxXSettings.WindowXStyle>
@@ -51,6 +52,7 @@
                <Setter Property="pu:WindowXCaption.Foreground" Value="{StaticResource DangerColorContrast}" />
                <Setter Property="Width" Value="350" />
                <Setter Property="Height" Value="200" />
                <Setter Property="SizeToContent" Value="Manual" />
            </Style>
        </pu:MessageBoxXSettings.WindowXStyle>
@@ -89,6 +91,7 @@
                <Setter Property="pu:WindowXCaption.Foreground" Value="{StaticResource PrimaryColorContract}" />
                <Setter Property="Width" Value="350" />
                <Setter Property="Height" Value="200" />
                <Setter Property="SizeToContent" Value="Manual" />
            </Style>
        </pu:MessageBoxXSettings.WindowXStyle>
HMI.UI/Style/PanuonResource.xaml
@@ -155,7 +155,7 @@
    <Style x:Key="CardBoarder" TargetType="Border">
        <Setter Property="BorderBrush" Value="{StaticResource CommonBoarder}"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Background" Value="#FFF"/>
        <Setter Property="Background" Value="#f3f9ff"/>
        <Setter Property="Margin" Value="10"/>
        <Setter Property="Padding" Value="10"/>
    </Style>
HMI.UI/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
HMI.UnitTest/HMI.UnitTest.csproj
@@ -61,8 +61,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
HMI.UnitTest/packages.config
@@ -2,5 +2,5 @@
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
Libs/OpcInterface.dll
Binary files differ
Plugin.DOControl/DOControl.xaml
New file
@@ -0,0 +1,112 @@
<hb:PluginControl x:Class="HMI.DOControl.DOControl"
             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:hb="clr-namespace:HMI.Base;assembly=HMI.Base"
             xmlns:local="clr-namespace:HMI.DOControl"
             xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
             xmlns:pw="https://opensource.panuon.com/wpf"
             xmlns:pu="https://opensource.panuon.com/wpf-ui"
             xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
             mc:Ignorable="d"
             Loaded="UserControl_Loaded"
             Background="{StaticResource WorkspaceBackground}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Border Style="{StaticResource CardBoarder}">
        <Grid dp:GridHelper.Space="10" Cursor="">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock FontSize="{StaticResource TitleFontSize}"
VerticalAlignment="Center" HorizontalAlignment="Left" Text="日志查询"/>
            <DockPanel Grid.Row="1" Cursor="">
                <StackPanel DockPanel.Dock="Right" Style="{StaticResource ButtonGroup}">
                    <Button Style="{StaticResource QueryBtn}"
                            x:Name="queryBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource RfhBtn}"
                            x:Name="resetBtn" Click="Button_Click"/>
                    <Button x:Name="exportBtn"
                            Style="{StaticResource ExportBtn}" Click="Button_Click"/>
                </StackPanel>
                <StackPanel Style="{StaticResource ButtonGroup}" HorizontalAlignment="Left">
                    <TextBlock Style="{StaticResource TitleBox}" FontSize="14" Text="级别"/>
                    <ComboBox Style="{StaticResource FormComboxStyle}" x:Name="levelInput"
                              Width="180"
                              SelectedValuePath="Content">
                        <ComboBoxItem Content="info"/>
                        <ComboBoxItem Content="warn"/>
                        <ComboBoxItem Content="error"/>
                    </ComboBox>
                    <TextBlock Style="{StaticResource TitleBox}" FontSize="14" Text="开始时间"/>
                    <pu:DateTimePicker Style="{StaticResource TimePicker}" x:Name="startTimeInput"/>
                    <TextBlock Style="{StaticResource TitleBox}" FontSize="14" Text="结束时间"/>
                    <pu:DateTimePicker Style="{StaticResource TimePicker}" x:Name="endTimeInput"/>
                    <TextBlock Style="{StaticResource TitleBox}" FontSize="14" Text="来源"/>
                    <!--<ComboBox Style="{StaticResource FormComboxStyle}" x:Name="sourceInput" Width="180"></ComboBox>-->
                    <TextBox Style="{StaticResource EditorTextBoxStyle}" x:Name="sourceInput" Width="180"/>
                    <TextBlock Style="{StaticResource TitleBox}" FontSize="14" Text="实时刷新"/>
                    <CheckBox x:Name="autoRfhInput" HorizontalAlignment="Center" VerticalAlignment="Center"
                              IsChecked="{Binding AutoRfh,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                              />
                </StackPanel>
            </DockPanel>
            <DataGrid Grid.Row="2" x:Name="table" Style="{StaticResource DefaultDataGrid}">
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridRowStyle}}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding type}" Value="warn">
                                <Setter Property="Background" Value="{StaticResource WarningColor}"/>
                                <Setter Property="Foreground" Value="Black"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding type}" Value="error">
                                <Setter Property="Background" Value="{StaticResource DangerColor}"/>
                                <Setter Property="Foreground" Value="Black"/>
                            </DataTrigger>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Background" Value="Transparent"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="Transparent"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </DataGrid.RowStyle>
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="" Width="Auto" CanUserResize="False">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox VerticalAlignment="Center" IsChecked="{Binding Selected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="#" CanUserResize="False">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Converter={StaticResource rowNumber},
    RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow},AncestorLevel=1}}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn Width="*" Binding="{Binding type}" Header="级别" />
                    <DataGridTextColumn Width="*" Binding="{Binding time}" Header="时间" />
                    <DataGridTextColumn Width="*" Binding="{Binding source}" Header="来源" />
                    <DataGridTextColumn Width="*" Binding="{Binding text}" Header="文本" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Border>
</hb:PluginControl>
Plugin.DOControl/DOControl.xaml.cs
New file
@@ -0,0 +1,46 @@
using HMI.Base;
using System.Windows;
using System.Windows.Controls;
namespace HMI.DOControl
{
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class DOControl : PluginControl
    {
        public DOControl()
        {
            InitializeComponent();
        }
        public override void InitFinish()
        {
            base.InitFinish();
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Loaded -= UserControl_Loaded;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            switch (btn.Name)
            {
                case "queryBtn":
                    break;
                case "resetBtn":
                    break;
                case "exportBtn":
                    break;
                default:
                    break;
            }
        }
    }
}
Plugin.DOControl/Plugin.DOControl.csproj
New file
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{306A83DC-A7DB-4057-BAA7-477D8756F5D9}</ProjectGuid>
    <OutputType>library</OutputType>
    <RootNamespace>Plugin.DOControl</RootNamespace>
    <AssemblyName>Plugin.DOControl</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <WarningLevel>4</WarningLevel>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="log4net, Version=3.0.4.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\log4net.3.0.4\lib\net462\log4net.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
    <Reference Include="System.Data" />
    <Reference Include="System.Web" />
    <Reference Include="System.Xml" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xaml">
      <RequiredTargetFramework>4.0</RequiredTargetFramework>
    </Reference>
    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
  </ItemGroup>
  <ItemGroup>
    <Page Include="DOControl.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Compile Include="DOControl.xaml.cs">
      <DependentUpon>DOControl.xaml</DependentUpon>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs">
      <SubType>Code</SubType>
    </Compile>
    <Compile Include="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
    <Compile Include="Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
    <EmbeddedResource Include="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
    <None Include="packages.config" />
    <None Include="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\HMI.Base\HMI.Base.csproj">
      <Project>{2a6f9720-a890-4036-9d73-41a0dae28341}</Project>
      <Name>HMI.Base</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.Core\HMI.Core.csproj">
      <Project>{3e3bf44a-0b69-45c5-9512-528cb48a7106}</Project>
      <Name>HMI.Core</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.UI\HMI.UI.csproj">
      <Project>{f17de6b5-af1d-48c6-94a0-6b763a6546a6}</Project>
      <Name>HMI.UI</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.Util\HMI.Util.csproj">
      <Project>{afea100a-9223-448d-ab10-3015d93dd98c}</Project>
      <Name>HMI.Util</Name>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Plugin.DOControl/Properties/AssemblyInfo.cs
New file
@@ -0,0 +1,52 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Plugin.DOControl")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Plugin.DOControl")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//在 <PropertyGroup> 中。例如,如果你使用的是美国英语。
//使用的是美国英语,请将 <UICulture> 设置为 en-US。  然后取消
//对以下 NeutralResourceLanguage 特性的注释。  更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
    ResourceDictionaryLocation.None, //主题特定资源词典所处位置
                             //(未在页面中找到资源时使用,
                             //或应用程序资源字典中找到时使用)
    ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
                                      //(未在页面中找到资源时使用,
                                      //、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
//      主版本
//      次版本
//      生成号
//      修订号
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Plugin.DOControl/Properties/Resources.Designer.cs
New file
@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由工具生成。
//     运行时版本: 4.0.30319.42000
//
//     对此文件的更改可能导致不正确的行为,如果
//     重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Plugin.DOControl.Properties {
    /// <summary>
    ///   强类型资源类,用于查找本地化字符串等。
    /// </summary>
    // 此类是由 StronglyTypedResourceBuilder
    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
    // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
    // (以 /str 作为命令选项),或重新生成 VS 项目。
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resources {
        private static global::System.Resources.ResourceManager resourceMan;
        private static global::System.Globalization.CultureInfo resourceCulture;
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources() {
        }
        /// <summary>
        ///   返回此类使用的缓存 ResourceManager 实例。
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if ((resourceMan == null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Plugin.DOControl.Properties.Resources", typeof(Resources).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        /// <summary>
        ///   重写当前线程的 CurrentUICulture 属性,对
        ///   使用此强类型资源类的所有资源查找执行重写。
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
    }
}
Plugin.DOControl/Properties/Resources.resx
New file
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--
    Microsoft ResX Schema
    Version 2.0
    The primary goals of this format is to allow a simple XML format
    that is mostly human readable. The generation and parsing of the
    various data types are done through the TypeConverter classes
    associated with the data types.
    Example:
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
    There are any number of "resheader" rows that contain simple
    name/value pairs.
    Each data row contains a name, and value. The row also contains a
    type or mimetype. Type corresponds to a .NET class that support
    text/value conversion through the TypeConverter architecture.
    Classes that don't support this are serialized and stored with the
    mimetype set.
    The mimetype is used for serialized objects, and tells the
    ResXResourceReader how to depersist the object. This is currently not
    extensible. For a given mimetype the value must be set accordingly:
    Note - application/x-microsoft.net.object.binary.base64 is the format
    that the ResXResourceWriter will generate, however the reader can
    read any of the formats listed below.
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with
            : System.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
</root>
Plugin.DOControl/Properties/Settings.Designer.cs
New file
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Plugin.DOControl.Properties
{
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
    {
        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
        public static Settings Default
        {
            get
            {
                return defaultInstance;
            }
        }
    }
}
Plugin.DOControl/Properties/Settings.settings
New file
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
  <Profiles>
    <Profile Name="(Default)" />
  </Profiles>
  <Settings />
</SettingsFile>
Plugin.DOControl/packages.config
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
Plugin.ServoManage/Entity/ServoData.cs
New file
@@ -0,0 +1,15 @@
using HMI.Core.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.ServoManage.Entity
{
    public class ServoData :SelectBase
    {
        public string Name { get; set; }
        public string Unit { get; set; }
    }
}
Plugin.ServoManage/Entity/ServoProductData.cs
New file
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.ServoManage.Entity
{
    public class ServoProductData
    {
        public string Model { get; set; }
        public string ProgramCode { get; set; }
    }
}
Plugin.ServoManage/NumberPanel.xaml
New file
@@ -0,0 +1,78 @@
<pu:WindowX x:Class="Plugin.ServoManage.NumberPanel"
            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:Plugin.ServoManage"
            xmlns:pw="https://opensource.panuon.com/wpf"
            xmlns:pu="https://opensource.panuon.com/wpf-ui"
            xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
            xmlns:ui="clr-namespace:HMI.UI;assembly=HMI.UI"
            xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
            mc:Ignorable="d"
            Title="Form"
            SizeToContent="Height"
            Width="500"
            FontSize="14"
            FontWeight="Bold"
            WindowStartupLocation="CenterOwner"
            pu:WindowXModalDialog.Buttons="{x:Null}"
            Style="{StaticResource ModalWindow}">
    <Window.Resources>
        <Style TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
            <Setter Property="Padding" Value="16"/>
        </Style>
    </Window.Resources>
    <Grid dp:GridHelper.Space="10" Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ui:NumberInput Grid.ColumnSpan="4" BorderThickness="1"
                        BorderBrush="Black"
                        Style="{StaticResource EditorTextBoxStyle}"
                        x:Name="NiNumber"/>
        <!--<Button Grid.Row="1" Tag="LeftArrow" Click="Button_Click" Content="⬅"/>
        <Button Grid.Row="1" Grid.Column="1"
                Tag="RightArrow"
                Click="Button_Click"
                Content="zuojiantou"/>-->
        <Button Grid.Row="1" Tag="ESC" Click="Button_Click" Content="ESC"/>
        <Button Grid.Row="1" Grid.Column="1" Tag="-" Click="Button_Click" Content="-"/>
        <Button Grid.Row="1" Grid.Column="2" Tag="AC" Click="Button_Click" Content="AC"/>
        <Button Grid.Row="1" Grid.Column="3" Tag="Backspace" Click="Button_Click" Content="Del"/>
        <Button Grid.Row="2" Tag="7" Click="Button_Click" Content="7"/>
        <Button Grid.Row="2" Grid.Column="1" Tag="8" Click="Button_Click" Content="8"/>
        <Button Grid.Row="2" Grid.Column="2" Tag="9" Click="Button_Click" Content="9"/>
        <Button Grid.Row="2" Grid.RowSpan="4" Tag="Enter" Click="Button_Click" Grid.Column="3" Content="Enter"/>
        <Button Grid.Row="3" Tag="4" Click="Button_Click" Content="4"/>
        <Button Grid.Row="3" Grid.Column="1" Tag="5" Click="Button_Click" Content="5"/>
        <Button Grid.Row="3" Grid.Column="2" Tag="6" Click="Button_Click" Content="6"/>
        <Button Grid.Row="4" Tag="1" Click="Button_Click" Content="1"/>
        <Button Grid.Row="4" Grid.Column="1" Tag="2" Click="Button_Click" Content="2"/>
        <Button Grid.Row="4" Grid.Column="2" Tag="3" Click="Button_Click" Content="3"/>
        <Button Grid.Row="5" Grid.ColumnSpan="2" Tag="0" Click="Button_Click" Content="0"/>
        <Button Grid.Row="5" Grid.Column="2" Tag="." Click="Button_Click" Content="."/>
    </Grid>
</pu:WindowX>
Plugin.ServoManage/NumberPanel.xaml.cs
New file
@@ -0,0 +1,160 @@
using HMI.Core.Util;
using HMI.UI.DpUtil;
using HMI.UI.Util;
using Panuon.WPF.UI;
using Plugin.ServoManage.Entity;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
namespace Plugin.ServoManage
{
    /// <summary>
    /// ModalWindow.xaml 的交互逻辑
    /// </summary>
    public partial class NumberPanel : WindowX
    {
        public NumberPanel()
        {
            this.DataContext = this;
            InitializeComponent();
        }
        public double? Data { get; private set; }
        private bool _isProcessing;
        protected override void OnClosing(CancelEventArgs e)
        {
            //Press Continue Button
            if (DialogResult == true)
            {
                if (_isProcessing)
                {
                    e.Cancel = true;
                    return;
                }
                try
                {
                }
                catch (Exception ex)
                {
                    return;
                }
                finally
                {
                    _isProcessing = false;
                }
            }
            base.OnClosing(e);
        }
        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Button btn = sender as Button;
            switch (btn.Tag.ToString())
            {
                case "LeftArrow":
                    break;
                case "RightArrow":
                    break;
                case "AC":
                    NiNumber.Text = null;
                    break;
                case "Backspace":
                    HandleBackspace();
                    break;
                case "Enter":
                    DialogResult = true;
                    Data = double.Parse(NiNumber.Text);
                    this.Close();
                    break;
                case "ESC":
                    DialogResult = false;
                    this.Close();
                    break;
                case "-":
                    var str = NiNumber.Text;
                    if (string.IsNullOrEmpty(str))
                    {
                        NiNumber.Text = "-";
                    }
                    else if (str.StartsWith("-"))
                    {
                        NiNumber.Text = str.Replace("-", "");
                    }
                    else
                    {
                        NiNumber.Text = "-" + str;
                    }
                    break;
                case ".":
                    HandleDot();
                    break;
                default:
                    HandleNumberInput(btn.Tag.ToString());
                    break;
            }
        }
        private void HandleBackspace()
        {
            var str = NiNumber.Text?.ToString();
            if (string.IsNullOrEmpty(str))
            {
                return;
            }
            else
            {
                NiNumber.Text = str.Substring(0, str.Length - 1);
            }
        }
        private void HandleDot()
        {
            var str = NiNumber.Text?.ToString();
            if (string.IsNullOrEmpty(str) || str.IndexOf(".") > 0)
            {
                return;
            }
            else
            {
                NiNumber.Text = str + ".";
            }
        }
        public bool? Open(string dataStr)
        {
            try
            {
                Data = double.Parse(dataStr);
                NiNumber.Text = dataStr;
            }
            catch (Exception ex)
            {
                Data = null;
                NiNumber.Text = null;
            }
            return this.ShowDialog();
        }
        private void HandleNumberInput(string numStr)
        {
            var str = NiNumber.Text?.ToString();
            if (string.IsNullOrEmpty(str))
            {
                NiNumber.Text = numStr;
            }
            else
            {
                NiNumber.Text = str + numStr;
            }
        }
    }
}
Plugin.ServoManage/Plugin.ServoManage.csproj
@@ -56,8 +56,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
@@ -77,6 +77,20 @@
    <Reference Include="PresentationFramework" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Entity\ServoData.cs" />
    <Compile Include="Entity\ServoProductData.cs" />
    <Compile Include="NumberPanel.xaml.cs">
      <DependentUpon>NumberPanel.xaml</DependentUpon>
    </Compile>
    <Compile Include="ServoProductModal.xaml.cs">
      <DependentUpon>ServoProductModal.xaml</DependentUpon>
    </Compile>
    <Compile Include="ServoModal.xaml.cs">
      <DependentUpon>ServoModal.xaml</DependentUpon>
    </Compile>
    <Compile Include="ServoSetting.xaml.cs">
      <DependentUpon>ServoSetting.xaml</DependentUpon>
    </Compile>
    <Page Include="ServoManage.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
@@ -85,6 +99,22 @@
      <DependentUpon>ServoManage.xaml</DependentUpon>
      <SubType>Code</SubType>
    </Compile>
    <Page Include="NumberPanel.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Page Include="ServoProductModal.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Page Include="ServoModal.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Page Include="ServoSetting.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs">
@@ -111,6 +141,10 @@
    </None>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\HMI.Old\OPCInterface\OpcInterface\OpcInterface.csproj">
      <Project>{e1464149-2c0a-499d-ab90-0c72e6ed1c53}</Project>
      <Name>OpcInterface</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.Base\HMI.Base.csproj">
      <Project>{2a6f9720-a890-4036-9d73-41a0dae28341}</Project>
      <Name>HMI.Base</Name>
@@ -119,10 +153,17 @@
      <Project>{3e3bf44a-0b69-45c5-9512-528cb48a7106}</Project>
      <Name>HMI.Core</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.ParameterManage\HMI.ParameterManage.csproj">
      <Project>{736cd77d-b81e-4866-bb00-84b0b57110f0}</Project>
      <Name>HMI.ParameterManage</Name>
    </ProjectReference>
    <ProjectReference Include="..\HMI.UI\HMI.UI.csproj">
      <Project>{f17de6b5-af1d-48c6-94a0-6b763a6546a6}</Project>
      <Name>HMI.UI</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <WCFMetadata Include="Connected Services\" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Plugin.ServoManage/ServoManage.xaml
@@ -1,4 +1,4 @@
<UserControl x:Class="Plugin.ServoManage.ServoManage"
<hb:PluginControl x:Class="Plugin.ServoManage.ServoManage"
             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" 
@@ -14,17 +14,40 @@
             Loaded="UserControl_Loaded"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Style x:Key="PrimaryButton" TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
            <Setter Property="Padding" Value="15"/>
        </Style>
        <Style x:Key="LightBall" TargetType="Ellipse">
            <Setter Property="Height" Value="35"/>
            <Setter Property="Width" Value="35"/>
            <Setter Property="Fill" Value="{StaticResource Normal}"/>
            <Setter Property="Margin" Value="0,10,0,0"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding }" Value="1">
                    <Setter Property="Fill" Value="{StaticResource Ok}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <Style x:Key="Desc" TargetType="Label">
            <Setter Property="Padding" Value="10"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Padding" Value="10,15"/>
            <Setter Property="MinWidth" Value="90"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="#3a3a3a"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
        </Style>
        <Style x:Key="ReadLabel" TargetType="Label" BasedOn="{StaticResource Desc}">
            <Setter Property="BorderThickness" Value="1,0,1,1"/>
            <Setter Property="Background" Value="LightGray"/>
        </Style>
        <Style x:Key="LabelText" TargetType="Label" BasedOn="{StaticResource Desc}">
            <Setter Property="BorderThickness" Value="1,0,1,1"/>
            <Setter Property="Cursor" Value="Hand"/>
        </Style>
        <Style x:Key="BDesc" TargetType="Label" BasedOn="{StaticResource Desc}">
@@ -33,6 +56,10 @@
        <Style x:Key="YDesc" TargetType="Label" BasedOn="{StaticResource Desc}">
            <Setter Property="Background" Value="#ffff00"/>
        </Style>
        <Style TargetType="GroupBox">
            <Setter Property="Padding" Value="5"/>
        </Style>
    </UserControl.Resources>
    
@@ -51,10 +78,8 @@
            <DockPanel Grid.ColumnSpan="2">
                <StackPanel DockPanel.Dock="Right" Style="{StaticResource ButtonGroup}">
                    <Button Style="{StaticResource AddBtn}" x:Name="addBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource EditBtn}" x:Name="editBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource RfhBtn}" x:Name="rfhBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource DelBtn}" x:Name="delBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource AddBtn}" x:Name="addServoBtn" Click="Button_Click"/>
                    <Button Style="{StaticResource RfhBtn}" x:Name="rfhServoBtn" Click="Button_Click"/>
                </StackPanel>
                <TextBlock Style="{StaticResource TitleBox}" Text="{DynamicResource svo.title}"/>
            </DockPanel>
@@ -102,9 +127,6 @@
                                                        </Setter.Value>
                                                    </Setter>
                                                </DataTrigger>
                                                <Trigger Property="IsChecked" Value="True">
                                                    <Setter Property="Background" Value="Red"/>
                                                </Trigger>
                                            </Style.Triggers>
                                        </Style>
                                    </ToggleButton.Style>
@@ -131,7 +153,8 @@
                                      IsReadOnly="False"
                                      SelectionMode="Single"
                                      BorderThickness="0"
                                      ItemsSource="{Binding Datas}">
                                      SelectedItem="{Binding SelectedServo}"
                                      ItemsSource="{Binding Servos}">
                                <DataGrid.Columns>
                                    <DataGridTemplateColumn Header="#" IsReadOnly="True" CanUserResize="False">
                                        <DataGridTemplateColumn.CellTemplate>
@@ -166,7 +189,6 @@
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                        </Grid>
@@ -203,136 +225,37 @@
                        </Grid.RowDefinitions>
                        <DockPanel>
                            <StackPanel Style="{StaticResource ButtonGroup}">
                                <TextBlock Style="{StaticResource TitleBox}"
                            <StackPanel Style="{StaticResource ButtonGroup}" HorizontalAlignment="Left">
                                <!--<TextBlock Style="{StaticResource TitleBox}"
                                           FontSize="{StaticResource ContentFontSize2}" 
                                           Text="{DynamicResource svo.product}"/>
                                <ComboBox x:Name="productInput" Style="{StaticResource FormComboxStyle}" MinWidth="180" />
                                           Text="{DynamicResource svo.product.model}"/>
                                <ComboBox x:Name="productInput"
                                          IsEnabled="{Binding HasSelectedServo}"
                                          SelectedItem="{Binding SelectedProduct}"
                                          ItemsSource="{Binding ServoProducts}"
                                          DisplayMemberPath="Model"
                                          Style="{StaticResource FormComboxStyle}" MinWidth="180" />
                                <Button Style="{StaticResource AddBtn}" Click="Button_Click"/>
                                <Button Style="{StaticResource EditBtn}" Click="Button_Click"/>
                                <Button Style="{StaticResource RfhBtn}" Click="Button_Click"/>
                                <Button Style="{StaticResource DelBtn}" Click="Button_Click"/>
                                <Button Style="{StaticResource AddBtn}" x:Name="addProductBtn" Click="Button_Click"/>
                                <Button Style="{StaticResource EditBtn}" x:Name="editProductBtn" Click="Button_Click"/>
                                <Button Style="{StaticResource RfhBtn}" x:Name="rfhProductBtn" Click="Button_Click"/>
                                <Button Style="{StaticResource DelBtn}" x:Name="delProductBtn" Click="Button_Click"/>-->
                            </StackPanel>
                        </DockPanel>
                        <WrapPanel Grid.Row="1">
                            <GroupBox Header="报警" Padding="10">
                                <StackPanel Style="{StaticResource ButtonGroup}">
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="控制报警"/>
                                        <Label Style="{StaticResource LabelText}" Content="控制报警"/>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="驱动报警"/>
                                        <Label Style="{StaticResource LabelText}" Content="控制报警"/>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="故障驱动"/>
                                        <Label Style="{StaticResource LabelText}" Content="0"/>
                                    </StackPanel>
                                </StackPanel>
                            </GroupBox>
                        <Grid Grid.Row="1" dp:GridHelper.Space="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <GroupBox Header="位置" Padding="10">
                                <StackPanel Style="{StaticResource ButtonGroup}">
                                    <StackPanel>
                                        <Label Style="{StaticResource BDesc}" Content="当前位置"/>
                                        <Label Style="{StaticResource LabelText}" Content="0"/>
                                    </StackPanel>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                                    <StackPanel>
                                        <Label Style="{StaticResource BDesc}" Content="当前速度"/>
                                        <Label Style="{StaticResource LabelText}" Content="0"/>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource BDesc}" Content="加速度"/>
                                        <Label Style="{StaticResource LabelText}" Content="0"/>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource BDesc}" Content="减速度"/>
                                        <Label Style="{StaticResource LabelText}" Content="0"/>
                                    </StackPanel>
                                </StackPanel>
                            </GroupBox>
                            <GroupBox Header="状态" Padding="10">
                                <StackPanel Style="{StaticResource ButtonGroup}">
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="使能"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="准备好"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="运行中"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="故障"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="轴报警"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel>
                                        <Label Style="{StaticResource YDesc}" Content="代码"/>
                                        <Label Style="{StaticResource LabelText}">
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                </StackPanel>
                            </GroupBox>
                            <GroupBox Header="限位传感器" Padding="10">
                                <StackPanel Style="{StaticResource ButtonGroup}" Orientation="Vertical">
                                    <StackPanel Orientation="Horizontal">
                                        <Label Style="{StaticResource YDesc}" Content="使能"/>
                                        <Label Style="{StaticResource LabelText}" BorderThickness="0,1,1,1" >
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal">
                                        <Label Style="{StaticResource YDesc}" Content="准备好"/>
                                        <Label Style="{StaticResource LabelText}" BorderThickness="0,1,1,1" >
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal">
                                        <Label Style="{StaticResource YDesc}" Content="运行中"/>
                                        <Label Style="{StaticResource LabelText}" BorderThickness="0,1,1,1" >
                                            <Ellipse Height="30" Width="30" Fill="{StaticResource Normal}" />
                                        </Label>
                                    </StackPanel>
                                </StackPanel>
                            </GroupBox>
                            <GroupBox Header="寸动" Padding="10">
                                <StackPanel Style="{StaticResource ButtonGroup}">
                                    <Button Style="{StaticResource PrimaryButton}">寸动</Button>
                                    <Label Style="{StaticResource LabelText}" BorderThickness="1" Content="准备好"/>
                                    <Button Style="{StaticResource PrimaryButton}">正向</Button>
                                </StackPanel>
                            </GroupBox>
                            <GroupBox Header="操作" Padding="10">
                            <GroupBox Header="{DynamicResource App.Opt}" Padding="10">
                                <Grid dp:GridHelper.Space="10">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
@@ -340,32 +263,251 @@
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Button Style="{StaticResource PrimaryButton}">调试模式</Button>
                                    <UniformGrid Grid.Row="1" Columns="2">
                                        <Button Style="{StaticResource PrimaryButton}"
                                                Margin="0,0,5,0">调试模式</Button>
                                        <Button Style="{StaticResource PrimaryButton}"
                                                Margin="5,0,0,0">调试模式</Button>
                                    </UniformGrid>
                                    <Button Grid.Row="2" Style="{StaticResource PrimaryButton}">初始化</Button>
                                    <Button Grid.Row="3" Style="{StaticResource PrimaryButton}">停止</Button>
                                    <UniformGrid Grid.Row="4" Columns="3">
                                        <Button Style="{StaticResource PrimaryButton}">调试模式</Button>
                                        <Label Style="{StaticResource LabelText}"
                                               Margin="10,0,10,0"
                                               BorderThickness="1" Content="准备好"/>
                                        <Button Style="{StaticResource PrimaryButton}">调试模式</Button>
                                    </UniformGrid>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition/>
                                        </Grid.ColumnDefinitions>
                                        <Label
                                            Style="{StaticResource BDesc}" MinWidth="80" Padding="0"
                                            Content="{DynamicResource svo.product.model}"/>
                                        <ComboBox Grid.Column="1"  x:Name="productInput"
IsEnabled="{Binding HasSelectedServo}"
SelectedValue="{Binding SelectedProduct}"
ItemsSource="{Binding ServoProducts}"
SelectedValuePath="ProgramCode"
DisplayMemberPath="Model"
                                                  BorderThickness="0,1,1,1"
                                    FontSize="14"
                                    BorderBrush="Black"
Style="{StaticResource FormComboxStyle}" MinWidth="180" />
                                </Grid>
                                
                                    <Button Grid.Row="1" Style="{StaticResource PrimaryButton}"
                                            Content="{DynamicResource svo.debugMode}"/>
                                    <UniformGrid Grid.Row="2" Columns="2">
                                        <Button Margin="0,0,5,0" Tag="Enable" Click="Servo_Click">
                                            <Button.Style>
                                                <Style TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
                                                    <Setter Property="Content" Value="{DynamicResource svo.enable}"/>
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding Enable}" Value="1">
                                                            <Setter Property="Content" Value="{DynamicResource svo.disable}"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Button.Style>
                                        </Button>
                                        <Button Style="{StaticResource PrimaryButton}"
 Margin="5,0,0,0" Content="{DynamicResource svo.reset}" Tag="Reset" Click="Servo_Click"/>
                                    </UniformGrid>
                                    <Button Grid.Row="3" Style="{StaticResource PrimaryButton}"
                                            Content="{DynamicResource svo.init}"
                                            Tag="Initialization" Click="Servo_Click"/>
                                    <Button Grid.Row="4" Style="{StaticResource PrimaryButton}"
                                            Content="{DynamicResource svo.stop}"
                                            Tag="Stop" Click="Servo_Click"/>
                                    <UniformGrid Grid.Row="5" Columns="3">
                                        <Button Style="{StaticResource PrimaryButton}"
                                                Content="{DynamicResource svo.JOG+}"
                                                Tag="JoGadd" Click="Servo_Click"/>
                                        <Label Style="{StaticResource LabelText}" MinWidth="90"
Margin="10,0,10,0"
BorderThickness="1" MouseLeftButtonUp="Label_MouseLeftButtonUp" Tag="JogVelocity" Content="{Binding JogVelocity}"/>
                                        <Button Style="{StaticResource PrimaryButton}"
                                                Content="{DynamicResource svo.JOG-}"
                                                Tag="JOGsub" Click="Servo_Click"/>
                                    </UniformGrid>
                                </Grid>
                            </GroupBox>
                            <StackPanel Grid.Column="1">
                                <GroupBox Header="{DynamicResource svo.position}">
                                    <Grid dp:GridHelper.Space="10">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition/>
                                            <ColumnDefinition/>
                                            <ColumnDefinition/>
                                            <ColumnDefinition/>
                                        </Grid.ColumnDefinitions>
                                        <StackPanel>
                                            <Label Style="{StaticResource BDesc}"
                                               Content="{DynamicResource svo.currentPosition}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding CurrentPosition}"/>
                                        </StackPanel>
                                        <StackPanel Grid.Column="1">
                                            <Label Style="{StaticResource BDesc}"
                                               Content="{DynamicResource svo.currentSpeed}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding CurrentSpeed}"/>
                                        </StackPanel>
                                        <StackPanel Grid.Column="2">
                                            <Label Style="{StaticResource BDesc}"
                                               Content="{DynamicResource svo.OverAcc}"/>
                                            <Label Style="{StaticResource LabelText}"
                                                   MouseLeftButtonUp="Label_MouseLeftButtonUp"
                                                   Tag="OverAcc"
                                                   Content="{Binding OverAcc}"/>
                                        </StackPanel>
                                        <StackPanel Grid.Column="3">
                                            <Label Style="{StaticResource BDesc}"
                                                   Content="{DynamicResource svo.OverDec}"/>
                                            <Label Style="{StaticResource LabelText}"
                                                   MouseLeftButtonUp="Label_MouseLeftButtonUp"
                                                   Tag="OverDec"
                                                   Content="{Binding OverDec}"/>
                                        </StackPanel>
                                        <StackPanel Grid.Row="1">
                                            <Label Style="{StaticResource BDesc}"
                                               Content="{DynamicResource svo.HMIPosition}"/>
                                            <Label Style="{StaticResource LabelText}"
                                                   MouseLeftButtonUp="Label_MouseLeftButtonUp"
                                                   Tag="HMIPosition" Content="{Binding HMIPosition}"/>
                                        </StackPanel>
                                        <StackPanel Grid.Row="1" Grid.Column="1">
                                            <Label Style="{StaticResource BDesc}"
                                               Content="{DynamicResource svo.HMISpeed}"/>
                                            <Label Style="{StaticResource LabelText}"
                                                   MouseLeftButtonUp="Label_MouseLeftButtonUp"
                                                   Tag="HMISpeed"
                                                   Content="{Binding HMISpeed}"/>
                                        </StackPanel>
                                        <Button Grid.Row="1" Grid.Column="2"
                                            Grid.ColumnSpan="2"
                                            Style="{StaticResource PrimaryButton}"
                                            Tag="AbsExecute"
                                            Click="Servo_Click"
                                            Content="{DynamicResource svo.absExecute}"/>
                                    </Grid>
                            </GroupBox>
                                <GroupBox Header="{DynamicResource svo.inching}">
                                    <DockPanel>
                                        <Button DockPanel.Dock="Left"
                                                Margin="0,0,10,0"
                                                Style="{StaticResource PrimaryButton}"
                                                Tag="Inch" Click="Servo_Click"
                                                Content="{DynamicResource svo.inching}"/>
                                        <Button DockPanel.Dock="Right"
                                                Tag="Dir" Click="Servo_Click">
                                            <Button.Style>
                                                <Style TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
                                                    <Setter Property="Content" Value="{DynamicResource svo.forward}"/>
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding Dir}" Value="1">
                                                            <Setter Property="Content" Value="{DynamicResource svo.backward}"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Button.Style>
                                        </Button>
                                        <Label
                                             Margin="0,0,10,0"
                                            Style="{StaticResource LabelText}"
                                            MouseLeftButtonUp="Label_MouseLeftButtonUp"
                                            Tag="InchDistance"
                                            BorderThickness="1" Content="{Binding InchDistance}"/>
                                    </DockPanel>
                                </GroupBox>
                            </StackPanel>
                        </WrapPanel>
                            <StackPanel Grid.Column="2" HorizontalAlignment="Center">
                                <GroupBox Header="{DynamicResource svo.alarm}">
                                    <StackPanel Style="{StaticResource ButtonGroup}">
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                   Content="{DynamicResource svo.controlAlarm}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding AlarmCode}"/>
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                   Content="{DynamicResource svo.driverAlarm}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding WarnCode}"/>
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                   Content="{DynamicResource svo.faultDriven}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding FaultCode}"/>
                                        </StackPanel>
                                    </StackPanel>
                                </GroupBox>
                                <GroupBox Header="{DynamicResource svo.limitSensor}">
                                    <StackPanel Style="{StaticResource ButtonGroup}">
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.limit+}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding PositiveLimit}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.limit0}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding HomeSwitch}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.limit-}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding NegativeLimit}" />
                                        </StackPanel>
                                    </StackPanel>
                                </GroupBox>
                            </StackPanel>
                            <StackPanel Grid.Row="1" Grid.ColumnSpan="2">
                                <GroupBox Header="{DynamicResource svo.status}">
                                    <StackPanel Style="{StaticResource ButtonGroup}" HorizontalAlignment="Center">
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.enable}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding AxisEnabled}"/>
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.isReady}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding ReadyOK}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.isRunning}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding Running}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
           Content="{DynamicResource svo.reOriginOk}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding Homed}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.fault}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding AxisError}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.axisAlarm}"/>
                                            <Ellipse Style="{StaticResource LightBall}" DataContext="{Binding AxisWarn}" />
                                        </StackPanel>
                                        <StackPanel>
                                            <Label Style="{StaticResource YDesc}"
                                                   Content="{DynamicResource svo.code}"/>
                                            <Label Style="{StaticResource ReadLabel}" Content="{Binding PosCode}"/>
                                        </StackPanel>
                                    </StackPanel>
                                </GroupBox>
                            </StackPanel>
                        </Grid>
                    </Grid>
                </Border>
            </DockPanel>
        </Grid>
    </Border>
</UserControl>
</hb:PluginControl>
Plugin.ServoManage/ServoManage.xaml.cs
@@ -1,39 +1,724 @@
using HMI.Base;
using HMI.Core.Setting;
using HMI.Core.Util;
using HMI.ParameterManage.Entity;
using HMI.ParameterManage.Util;
using HMI.UI.Util;
using Plugin.ServoManage.Entity;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Threading;
using System.Timers;
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 Plugin.ServoManage
{
    [AttributeUsage(AttributeTargets.Property)]
    public class IsStatusAttribute : Attribute
    {
    }
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class ServoManage: UserControl
    public partial class ServoManage : PluginControl
    {
        public static string FilePath { get; private set; }
        public static string ProductFilePath { get; private set; }
        private ObservableCollection<ServoData> servos;
        public ObservableCollection<ServoData> Servos
        {
            get => servos;
            set
            {
                Set(ref servos, value);
            }
        }
        private ServoData selectedServo;
        public ServoData SelectedServo
        {
            get => selectedServo;
            set
            {
                Set(ref selectedServo, value);
                Set("HasSelectedServo");
                RefreshServoStatus();
            }
        }
        public bool HasSelectedServo
        {
            get => SelectedServo != null;
        }
        private string selectedProduct;
        [IsStatus]
        public string SelectedProduct
        {
            get => selectedProduct;
            set
            {
                if (value != selectedProduct)
                {
                    Set(ref selectedProduct, value);
                    if (SelectedServo != null)
                    {
                        SetBitValue($"{SelectedServo.Name}_sRecipeCode", value);
                    }
                }
            }
        }
        private ObservableCollection<ServoProductData> servoProducts;
        public ObservableCollection<ServoProductData> ServoProducts
        {
            get => servoProducts;
            set
            {
                Set(ref servoProducts, value);
            }
        }
        /// <summary>
        /// 实例化服务器接口函数
        /// </summary>
        private OpcInterface.OpcInterface lTSCADAApi = new OpcInterface.OpcInterface();
        private bool isActived = false;
        private System.Timers.Timer motorMonitorTimer;
        private string enable;
        [IsStatus]
        public string Enable
        {
            get => enable;
            set
            {
                Set(ref enable, value);
            }
        }
        private string currentPosition;
        [IsStatus]
        public string CurrentPosition
        {
            get => $"{currentPosition}{SelectedServo?.Unit}";
            set
            {
                Set(ref currentPosition, value);
            }
        }
        private string currentSpeed;
        [IsStatus]
        public string CurrentSpeed
        {
            get => $"{currentSpeed}{SelectedServo?.Unit}/s";
            set
            {
                Set(ref currentSpeed, value);
            }
        }
        private string overAcc;
        [IsStatus]
        public string OverAcc
        {
            get => $"{overAcc}{SelectedServo?.Unit}/s²";
            set
            {
                Set(ref overAcc, value);
            }
        }
        private string overDec;
        [IsStatus]
        public string OverDec
        {
            get => $"{overDec}{SelectedServo?.Unit}/s²";
            set
            {
                Set(ref overDec, value);
            }
        }
        private string hmiPosition;
        [IsStatus]
        public string HMIPosition
        {
            get => $"{hmiPosition}{SelectedServo?.Unit}";
            set
            {
                Set(ref hmiPosition, value);
            }
        }
        private string hmiSpeed;
        [IsStatus]
        public string HMISpeed
        {
            get => $"{hmiSpeed}{SelectedServo?.Unit}/s";
            set
            {
                Set(ref hmiSpeed, value);
            }
        }
        private string jogVelocity;
        [IsStatus]
        public string JogVelocity
        {
            get => $"{jogVelocity}%";
            set
            {
                Set(ref jogVelocity, value);
            }
        }
        private string inchDistance;
        [IsStatus]
        public string InchDistance
        {
            get => $"{inchDistance}{SelectedServo?.Unit}";
            set
            {
                Set(ref inchDistance, value);
            }
        }
        private string dir;
        [IsStatus]
        public string Dir
        {
            get => dir;
            set
            {
                Set(ref dir, value);
            }
        }
        private string alarmCode = "0";
        [IsStatus]
        public string AlarmCode
        {
            get => alarmCode;
            set
            {
                Set(ref alarmCode, value);
            }
        }
        private string warnCode = "0";
        [IsStatus]
        public string WarnCode
        {
            get => warnCode;
            set
            {
                Set(ref warnCode, value);
            }
        }
        private string faultCode = "0";
        [IsStatus]
        public string FaultCode
        {
            get => faultCode;
            set
            {
                Set(ref faultCode, value);
            }
        }
        private string positiveLimit;
        [IsStatus]
        public string PositiveLimit
        {
            get => positiveLimit;
            set
            {
                Set(ref positiveLimit, value);
            }
        }
        private string homeSwitch;
        [IsStatus]
        public string HomeSwitch
        {
            get => homeSwitch;
            set
            {
                Set(ref homeSwitch, value);
            }
        }
        private string negativeLimit;
        [IsStatus]
        public string NegativeLimit
        {
            get => negativeLimit;
            set
            {
                Set(ref negativeLimit, value);
            }
        }
        private string axisEnabled;
        [IsStatus]
        public string AxisEnabled
        {
            get => axisEnabled;
            set
            {
                Set(ref axisEnabled, value);
            }
        }
        private string readyOK;
        [IsStatus]
        public string ReadyOK
        {
            get => readyOK;
            set
            {
                Set(ref readyOK, value);
            }
        }
        private string running;
        [IsStatus]
        public string Running
        {
            get => running;
            set
            {
                Set(ref running, value);
            }
        }
        private string homed;
        [IsStatus]
        public string Homed
        {
            get => homed;
            set
            {
                Set(ref homed, value);
            }
        }
        private string axisError;
        [IsStatus]
        public string AxisError
        {
            get => axisError;
            set
            {
                Set(ref axisError, value);
            }
        }
        private string axisWarn;
        [IsStatus]
        public string AxisWarn
        {
            get => axisWarn;
            set
            {
                Set(ref axisWarn, value);
            }
        }
        private string posCode = "0";
        [IsStatus]
        public string PosCode
        {
            get => posCode;
            set
            {
                Set(ref posCode, value);
            }
        }
        public ServoManage()
        {
            DataContext = this;
            motorMonitorTimer = new System.Timers.Timer();
            motorMonitorTimer.Elapsed += MotorMonitorTimer_Elapsed;
            InitializeComponent();
        }
        private void MotorMonitorTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.motorMonitorTimer.Enabled = false;
            try
            {
                RefreshServoStatus();
                this.motorMonitorTimer.Enabled = true;
            }
            catch (Exception ex)
            {
                this.motorMonitorTimer.Enabled = true;
                return;
            }
        }
        public override void SetBaseFolder(string folder)
        {
            FilePath = Path.Combine(folder, "Servo.data");
            ProductFilePath = Path.Combine(folder, "ServoProduct.data");
            base.SetBaseFolder(folder);
        }
        public override void Active()
        {
            base.Active();
            if (!isActived)
            {
                try
                {
                    if (SystemSetting.Instance.PlcEnabled)
                    {
                        if (lTSCADAApi.Connect2("127.0.0.1", 6543, 18888, out string errMsg))
                        {
                            this.motorMonitorTimer.Interval = 100;
                            this.motorMonitorTimer.Start();
                            isActived = true;
                        }
                        else
                        {
                            MsgBoxHelper2.Error(errMsg);
                        }
                    }
                    else
                    {
                        isActived = true;
                    }
                }
                catch (Exception ex)
                {
                    log.Error("Active Failed.", ex);
                    MsgBoxHelper2.Error(ex.Message);
                }
            }
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            LoadData();
            LoadProductData();
            this.Loaded -= UserControl_Loaded;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            ServoData data = btn.DataContext as ServoData;
            switch (btn.Name)
            {
                case "addServoBtn":
                    OpenServoModal(null);
                    break;
                case "editServoBtn":
                    OpenServoModal(data);
                    break;
                case "delServoBtn":
                    TryDeleteServo(data);
                    break;
                case "rfhServoBtn":
                    LoadData();
                    break;
                case "addProductBtn":
                    OpenProductModal(null);
                    break;
                default:
                    break;
            }
        }
        #region Servo
        private void LoadData()
        {
            try
            {
                ObservableCollection<ServoData> data = new ObservableCollection<ServoData>();
                if (File.Exists(FilePath))
                {
                    data = XmlHelper.DeserializeFromXml<ObservableCollection<ServoData>>(FilePath);
                }
                Servos = data;
            }
            catch (Exception ex)
            {
                log.Error("Load Servo Data Failed.", ex);
                ToastHelper.Error(this.lang("App.LoadFailed"));
            }
        }
        private void OpenServoModal(ServoData data)
        {
            bool isUpdate = data != null;
            try
            {
                ServoModal modal = new ServoModal
                {
                    Title = isUpdate ? this.lang("App.Edit") : this.lang("App.Add"),
                    Owner = Window.GetWindow(this)
                };
                if (modal.Open(data ?? new ServoData(), Servos) == true)
                {
                    LoadData();
                }
            }
            catch (Exception ex)
            {
                log.Error($"Add Or Edit Data Failed.", ex);
                var title = isUpdate ? this.lang("App.EditFailed") : this.lang("App.AddFailed");
                MsgBoxHelper2.Error($"{title}: {ex.Message}");
            }
        }
        private void TryDeleteServo(ServoData data)
        {
            try
            {
                if (MsgBoxHelper2.WarnChoose(this.lang("HMI.MakeSureDeleteSingle", data.Name)) == MessageBoxResult.OK)
                {
                    int index = Servos.IndexOf(data);
                    if (index > 0)
                    {
                        var temp = XmlHelper.DeepClone(Servos);
                        temp.RemoveAt(index);
                        XmlHelper.SerializeToXml(FilePath, temp);
                    }
                    LoadData();
                }
            }
            catch (Exception ex)
            {
                log.Error($"Delete Servo Failed.", ex);
                MsgBoxHelper2.Error($"{this.lang("App.DeleteFailed")}: {ex.Message}");
            }
        }
        #endregion
        #region product
        public ObservableCollection<ServoProductData> ReadCommonProducts()
        {
            ObservableCollection<ServoProductData> datas = new ObservableCollection<ServoProductData>();
            List<ProductData> products = ParameterManager.GetProducts<List<ProductData>>();
            if (products != null && products.Count > 0)
            {
                foreach (var product in products)
                {
                    var parameter = ParameterManager.GetParametersByProductName(product.Name)
                         ?.FirstOrDefault(p => p.Name == "ProgramCode");
                    if (parameter != null)
                    {
                        datas.Add(new ServoProductData
                        {
                            Model = product.Name,
                            ProgramCode = parameter.Value,
                        });
                    }
                }
            }
            return datas;
        }
        private void LoadProductData()
        {
            try
            {
                //ObservableCollection<ServoProductData> datas = new ObservableCollection<ServoProductData>();
                //if (File.Exists(FilePath))
                //{
                //    datas = XmlHelper.DeserializeFromXml<ObservableCollection<ServoProductData>>(ProductFilePath);
                //}
                ServoProducts = ReadCommonProducts();
            }
            catch (Exception ex)
            {
                log.Error("Load Servo Product Data Failed.", ex);
                ToastHelper.Error(this.lang("App.LoadFailed"));
            }
        }
        private void OpenProductModal(ServoProductData data)
        {
            bool isUpdate = data != null;
            try
            {
                ServoProductModal modal = new ServoProductModal
                {
                    Title = isUpdate ? this.lang("App.Edit") : this.lang("App.Add"),
                    Owner = Window.GetWindow(this)
                };
                if (modal.Open(data ?? new ServoProductData(), ServoProducts) == true)
                {
                    LoadProductData();
                }
            }
            catch (Exception ex)
            {
                log.Error($"Add Or Edit Product Data Failed.", ex);
                var title = isUpdate ? this.lang("App.EditFailed") : this.lang("App.AddFailed");
                MsgBoxHelper2.Error($"{title}: {ex.Message}");
            }
        }
        #endregion
        private void RefreshServoStatus()
        {
            Dispatcher.Invoke(() =>
            {
                if (SelectedServo == null) return;
                PropertyInfo[] properties = this.GetType().GetProperties();
                foreach (var prop in properties)
                {
                    if (!Attribute.IsDefined(prop, typeof(IsStatusAttribute)))
                    {
                        continue;
                    }
                    if (prop.Name == "SelectedProduct")
                    {
                        var data = GetBitValue($"{SelectedServo.Name}_sRecipeCode");
                        SelectedProduct = data;
                    }
                    else
                    {
                        var data = GetBitValue($"{SelectedServo.Name}_{prop.Name}");
                        prop.SetValue(this, data);
                    }
                }
            });
        }
        /// <summary>
        /// 设置DB地址bool值
        /// </summary>
        /// <param name="subbuttonX">子按钮</param>
        /// <param name="address">地址</param>
        /// <param name="bol">值</param>
        private void SetBitValue(string tag, string val)
        {
            if (!lTSCADAApi.DoFctWriteSingle(tag, val, out string errMsg))
            {
                log.Error($"Set Bit Value Failed.{errMsg}");
                MsgBoxHelper2.Error(errMsg);
            }
        }
        /// <summary>
        /// 通过当前标签读取值
        /// </summary>
        /// <param name="tag">标签</param>
        /// <returns>返回值</returns>
        private string GetBitValue(string tag)
        {
            if (lTSCADAApi.DoFctReadSingle(tag, out string res, out string err))
            {
                return res;
            }
            else
            {
                return "";
            }
        }
        private void Servo_Click(object sender, RoutedEventArgs e)
        {
            if (SelectedServo == null)
            {
                ToastHelper.Warning(this.lang("svo.selectAServo"));
                return;
            }
            Button btn = sender as Button;
            try
            {
                motorMonitorTimer.Enabled = false;
                switch (btn.Tag)
                {
                    case "Enable":
                        EnableDoClick(btn.Tag.ToString());
                        break;
                    case "Dir":
                        EnableDoClick(btn.Tag.ToString());
                        break;
                    default:
                        DoSignClick(btn.Tag?.ToString());
                        break;
                }
            }
            catch (Exception ex)
            {
                log.Error($"Servo Opt Failed, BtnName is {btn.Name}", ex);
                MsgBoxHelper2.Error(ex.Message);
            }
            finally
            {
                motorMonitorTimer.Enabled = true;
            }
        }
        private void DoSignClick(string tag)
        {
            if (!string.IsNullOrEmpty(tag))
            {
                SetBitValue($"{SelectedServo?.Name}_{tag}", "true");
                Thread.Sleep(50);
                SetBitValue($"{SelectedServo?.Name}_{tag}", "false");
            }
        }
        /// <summary>
        /// 使能/断使能 按钮
        /// </summary>
        /// <param name="btnName"></param>
        private void EnableDoClick(string btnName)
        {
            bool val = GetBitValue($"{SelectedServo?.Name}_{btnName}") == "1";
            SetBitValue($"{SelectedServo?.Name}_{btnName}", $"{(!val ? 1 : 0)}");
        }
        private void Label_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (SelectedServo == null)
            {
                ToastHelper.Warning(this.lang("svo.selectAServo"));
                return;
            }
            Label label = sender as Label;
            var tag = label.Tag.ToString();
            NumberPanel np = new NumberPanel()
            {
                Title = this.lang($"svo.{tag}"),
                Owner = Window.GetWindow(this)
            };
            string value = label.Content.ToString();
            if (value.Contains("%"))
            {
                value = value.Replace("%", "");
            }
            else if (SelectedServo != null)
            {
                value = value.Split(new string[] { SelectedServo.Unit }, StringSplitOptions.None)[0];
            }
            if (np.Open(value) == true)
            {
                SetBitValue($"{SelectedServo?.Name}_{tag}", np.Data?.ToString());
            }
        }
    }
}
Plugin.ServoManage/ServoModal.xaml
New file
@@ -0,0 +1,37 @@
<pu:WindowX x:Class="Plugin.ServoManage.ServoModal"
            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:Plugin.ServoManage"
            xmlns:pw="https://opensource.panuon.com/wpf"
            xmlns:pu="https://opensource.panuon.com/wpf-ui"
            xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
            xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
            mc:Ignorable="d"
            Title="Form"
            SizeToContent="Height"
            Width="600"
            WindowStartupLocation="CenterOwner"
            Style="{StaticResource ModalWindow}">
    <Grid Margin="10">
        <StackPanel x:Name="formPanel">
            <pu:FormGroup x:Name="FgName" Style="{StaticResource InputFormGroupStyle}"
                          Header="{DynamicResource svo.name}"
                          dp:FormGroupHelper.IsRequired="True"
                          dp:FormGroupHelper.ValidateMethod="ValidateName"
                          GroupName="MyFormGroup">
                <TextBox x:Name="TbName" Style="{StaticResource EditorTextBoxStyle}" />
            </pu:FormGroup>
            <pu:FormGroup x:Name="FgUnit" Style="{StaticResource InputFormGroupStyle}"
                         Header="{DynamicResource svo.unit}"
                         dp:FormGroupHelper.IsRequired="True" GroupName="MyFormGroup">
                <ComboBox x:Name="CbUnit" Style="{StaticResource FormComboxStyle}" SelectedValuePath="Content">
                    <ComboBoxItem>mm</ComboBoxItem>
                    <ComboBoxItem>°</ComboBoxItem>
                </ComboBox>
            </pu:FormGroup>
        </StackPanel>
    </Grid>
</pu:WindowX>
Plugin.ServoManage/ServoModal.xaml.cs
New file
@@ -0,0 +1,126 @@
using HMI.Core.Util;
using HMI.UI.DpUtil;
using HMI.UI.Util;
using Panuon.WPF.UI;
using Plugin.ServoManage.Entity;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace Plugin.ServoManage
{
    /// <summary>
    /// ModalWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ServoModal : WindowX
    {
        public ServoModal()
        {
            this.DataContext = this;
            InitializeComponent();
        }
        public ServoData Data { get; set; }
        private ObservableCollection<ServoData> Datasource;
        private bool _isProcessing;
        protected override void OnClosing(CancelEventArgs e)
        {
            //Press Continue Button
            if (DialogResult == true)
            {
                if (_isProcessing)
                {
                    e.Cancel = true;
                    return;
                }
                var okButton = WindowXModalDialog.GetOKButton(this);
                try
                {
                    _isProcessing = true;
                    ButtonHelper.SetIsPending(okButton, true);
                    if (!ValidateForm())
                    {
                        e.Cancel = true;
                        return;
                    }
                    SaveOrUpdateData();
                }
                catch (Exception ex)
                {
                    ToastHelper.Error(this, $"Error!{ex.Message}");
                    e.Cancel = true;
                    return;
                }
                finally
                {
                    _isProcessing = false;
                    ButtonHelper.SetIsPending(okButton, false);
                }
            }
            base.OnClosing(e);
        }
        private bool ValidateName(object value, out string err)
        {
            err = null;
            var data = Datasource?.FirstOrDefault(d => d.Name == value.ToString());
            if (data != null && data != Data)
            {
                err = string.Format(LangUtil.Get("App.MustBeUnique"), LangUtil.Get("svo.name"));
                return false;
            }
            return true;
        }
        private bool ValidateForm()
        {
            bool flag = FormGroupHelper.ValidateForm(formPanel);
            if (flag)
            {
                Data.Name = TbName.Text;
                Data.Unit = CbUnit.Text;
            }
            return flag;
        }
        public bool? Open(ServoData data, ObservableCollection<ServoData> datasource)
        {
            Datasource = datasource;
            Data = data;
            TbName.Text = Data.Name;
            CbUnit.SelectedValue = Data.Unit;
            return this.ShowDialog();
        }
        private void SaveOrUpdateData()
        {
            int index = Datasource.IndexOf(Data);
            if (index < 0)
            {
                InsertData(Data);
            }
            else
            {
                UpdateData(index, Data);
            }
        }
        public void InsertData(ServoData data)
        {
            Datasource.Add(data);
            XmlHelper.SerializeToXml(ServoManage.FilePath, Datasource);
        }
        public void UpdateData(int index, ServoData data)
        {
            var temp = XmlHelper.DeepClone(Datasource);
            temp[index] = data;
            XmlHelper.SerializeToXml(ServoManage.FilePath, Datasource);
        }
    }
}
Plugin.ServoManage/ServoProductModal.xaml
New file
@@ -0,0 +1,34 @@
<pu:WindowX x:Class="Plugin.ServoManage.ServoProductModal"
            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:Plugin.ServoManage"
            xmlns:pw="https://opensource.panuon.com/wpf"
            xmlns:pu="https://opensource.panuon.com/wpf-ui"
            xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
            xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
            mc:Ignorable="d"
            Title="Form"
            SizeToContent="Height"
            Width="600"
            WindowStartupLocation="CenterOwner"
            Style="{StaticResource ModalWindow}">
    <Grid Margin="10">
        <StackPanel x:Name="formPanel">
            <pu:FormGroup x:Name="FgModel" Style="{StaticResource InputFormGroupStyle}"
                          Header="{DynamicResource svo.product.model}"
                         dp:FormGroupHelper.ValidateMethod="ValidateModel"
                          dp:FormGroupHelper.IsRequired="True" GroupName="MyFormGroup">
                <TextBox x:Name="TbModel" Style="{StaticResource EditorTextBoxStyle}" />
            </pu:FormGroup>
            <pu:FormGroup x:Name="FgProgramCode" Style="{StaticResource InputFormGroupStyle}"
                         dp:FormGroupHelper.ValidateMethod="ValidateProgramCode"
                         Header="{DynamicResource svo.product.programCode}"
                         dp:FormGroupHelper.IsRequired="True" GroupName="MyFormGroup">
                <pu:NumberInput x:Name="NiProgramCode" Style="{StaticResource FormNumberInput}" />
            </pu:FormGroup>
        </StackPanel>
    </Grid>
</pu:WindowX>
Plugin.ServoManage/ServoProductModal.xaml.cs
New file
@@ -0,0 +1,138 @@
using HMI.Core.Util;
using HMI.UI.DpUtil;
using HMI.UI.Util;
using Panuon.WPF.UI;
using Plugin.ServoManage.Entity;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace Plugin.ServoManage
{
    /// <summary>
    /// ModalWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ServoProductModal : WindowX
    {
        public ServoProductModal()
        {
            this.DataContext = this;
            InitializeComponent();
        }
        public ServoProductData Data { get; set; }
        private ObservableCollection<ServoProductData> Datasource;
        private bool _isProcessing;
        protected override void OnClosing(CancelEventArgs e)
        {
            //Press Continue Button
            if (DialogResult == true)
            {
                if (_isProcessing)
                {
                    e.Cancel = true;
                    return;
                }
                var okButton = WindowXModalDialog.GetOKButton(this);
                try
                {
                    _isProcessing = true;
                    ButtonHelper.SetIsPending(okButton, true);
                    if (!ValidateForm())
                    {
                        e.Cancel = true;
                        return;
                    }
                    SaveOrUpdateData();
                }
                catch (Exception ex)
                {
                    ToastHelper.Error(this, $"Error!{ex.Message}");
                    e.Cancel = true;
                    return;
                }
                finally
                {
                    _isProcessing = false;
                    ButtonHelper.SetIsPending(okButton, false);
                }
            }
            base.OnClosing(e);
        }
        private bool ValidateModel(object value, out string err)
        {
            err = null;
            var data = Datasource?.FirstOrDefault(d => d.Model == value.ToString());
            if (data != null && data != Data)
            {
                err = string.Format(LangUtil.Get("App.MustBeUnique"), LangUtil.Get("svo.product.model"));
                return false;
            }
            return true;
        }
        private bool ValidateProgramCode(object value, out string err)
        {
            err = null;
            var data = Datasource?.FirstOrDefault(d => d.ProgramCode == value.ToString());
            if (data != null && data != Data)
            {
                err = string.Format(LangUtil.Get("App.MustBeUnique"), LangUtil.Get("svo.product.programCode"));
                return false;
            }
            return true;
        }
        private bool ValidateForm()
        {
            bool flag = FormGroupHelper.ValidateForm(formPanel);
            if (flag)
            {
                Data.Model = TbModel.Text;
                Data.ProgramCode = NiProgramCode.Value?.ToString();
            }
            return flag;
        }
        public bool? Open(ServoProductData data, ObservableCollection<ServoProductData> datasource)
        {
            Datasource = datasource ?? new ObservableCollection<ServoProductData>();
            Data = data;
            TbModel.Text = Data.Model;
            NiProgramCode.Value = int.Parse(Data.ProgramCode ?? "0");
            return this.ShowDialog();
        }
        private void SaveOrUpdateData()
        {
            int index = Datasource.IndexOf(Data);
            if (index < 0)
            {
                InsertData(Data);
            }
            else
            {
                UpdateData(index, Data);
            }
        }
        public void InsertData(ServoProductData data)
        {
            Datasource.Add(data);
            XmlHelper.SerializeToXml(ServoManage.ProductFilePath, Datasource);
        }
        public void UpdateData(int index, ServoProductData data)
        {
            var temp = XmlHelper.DeepClone(Datasource);
            temp[index] = data;
            XmlHelper.SerializeToXml(ServoManage.ProductFilePath, Datasource);
        }
    }
}
Plugin.ServoManage/ServoSetting.xaml
New file
@@ -0,0 +1,10 @@
<UserControl x:Class="Plugin.ServoManage.ServoSetting"
             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:Plugin.ServoManage"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
</UserControl>
Plugin.ServoManage/ServoSetting.xaml.cs
New file
@@ -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 Plugin.ServoManage
{
    /// <summary>
    /// ServoSetting.xaml 的交互逻辑
    /// </summary>
    public partial class ServoSetting : UserControl
    {
        public ServoSetting()
        {
            InitializeComponent();
        }
    }
}
Plugin.ServoManage/packages.config
@@ -2,5 +2,5 @@
<packages>
  <package id="log4net" version="3.0.4" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
</packages>
Plugin.TestResult/Plugin.TestResult.csproj
@@ -99,8 +99,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="ScottPlot, Version=5.0.47.0, Culture=neutral, PublicKeyToken=86698dc10387c39e, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\ScottPlot.5.0.47\lib\net462\ScottPlot.dll</HintPath>
Plugin.TestResult/packages.config
@@ -8,7 +8,7 @@
  <package id="OpenTK" version="3.3.1" targetFramework="net472" />
  <package id="OpenTK.GLWpfControl" version="3.3.0" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="ScottPlot" version="5.0.47" targetFramework="net472" />
  <package id="ScottPlot.WPF" version="5.0.47" targetFramework="net472" />
  <package id="SkiaSharp" version="2.88.9" targetFramework="net472" />
Plugin.TsExecution/Plugin.TsExecution.csproj
@@ -74,8 +74,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="ScottPlot, Version=5.0.54.0, Culture=neutral, PublicKeyToken=86698dc10387c39e, processorArchitecture=MSIL">
      <HintPath>..\WPFProject\packages\ScottPlot.5.0.54\lib\net462\ScottPlot.dll</HintPath>
Plugin.TsExecution/TsExecution.xaml
@@ -22,12 +22,21 @@
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>
        <WindowsFormsHost x:Name="host" Visibility="Collapsed"></WindowsFormsHost>
        <Border>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <UniformGrid x:Name="panel" Columns="2" dp:UniformGridHelper.InnerBorder="1" 
                         dp:UniformGridHelper.InnerBorderBrush="#3a3a3a">
            </UniformGrid>
        </Border>
            <Border Grid.Row="1" Visibility="{Binding AlarmVisiable,Converter={StaticResource vbConverter}}"
                     Height="50" Background="Red"/>
        </Grid>
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
Plugin.TsExecution/TsExecution.xaml.cs
@@ -106,6 +106,16 @@
        private Pie pie;
        private string CountIniPath;
        private bool alarmVisiable;
        public bool AlarmVisiable
        {
            get => alarmVisiable;
            set
            {
                Set(ref alarmVisiable, value);
            }
        }
        public TsExecution()
        {
            DataContext = this;
Plugin.TsExecution/packages.config
@@ -8,7 +8,7 @@
  <package id="OpenTK" version="3.3.1" targetFramework="net472" />
  <package id="OpenTK.GLWpfControl" version="3.3.0" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="ScottPlot" version="5.0.54" targetFramework="net472" />
  <package id="ScottPlot.WPF" version="5.0.54" targetFramework="net472" />
  <package id="SkiaSharp" version="2.88.9" targetFramework="net472" />
WPFProject/App.config
WPFProject/Lang/en-US/ServoManage.json
New file
@@ -0,0 +1,45 @@
{
  "svo.title": "Servo manage",
  "svo.list": "Servo list",
  "svo.name": "Name",
  "svo.unit": "Unit",
  "svo.debugMode": "Debug mode",
  "svo.enable": "Enable",
  "svo.disable": "Disable",
  "svo.reset": "Reset",
  "svo.init": "Init",
  "svo.stop": "Stop",
  "svo.JOG+": "JOG+",
  "svo.JogVelocity": "JOG",
  "svo.JOG-": "JOG-",
  "svo.position": "Position",
  "svo.currentPosition": "Cur Position",
  "svo.currentSpeed": "Cur Speed",
  "svo.OverAcc": "Acc",
  "svo.OverDec": "Decc",
  "svo.HMIPosition": "HMI Position",
  "svo.HMISpeed": "HMI Speed",
  "svo.absExecute": "Abs Execute",
  "svo.inching": "Inch",
  "svo.InchDistance": "Inch",
  "svo.forward": "Forward",
  "svo.backward": "Backward",
  "svo.limitSensor": "Limit sensor",
  "svo.limit+": "Positive limit",
  "svo.limit0": "Home",
  "svo.limit-": "Negative limit",
  "svo.isReady": "Ready",
  "svo.isRunning": "Running",
  "svo.alarm": "Alarm",
  "svo.controlAlarm": "Control Alarm",
  "svo.driverAlarm": "Driver Alarm",
  "svo.faultDriven": "Fault Driven",
  "svo.status": "Status",
  "svo.reOriginOk": "Homed",
  "svo.fault": "Fault",
  "svo.axisAlarm": "Axis Alarm",
  "svo.code": "Code",
  "svo.product.model": "Model",
  "svo.product.programCode": "Program code",
  "svo.selectAServo": "Please select a servo"
}
WPFProject/Lang/zh-CN/ServoManage.json
@@ -2,5 +2,44 @@
  "svo.title": "伺服管理",
  "svo.list": "伺服列表",
  "svo.name": "名称",
  "svo.product": "产品型号",
  "svo.unit": "单位",
  "svo.debugMode": "调试模式",
  "svo.enable": "使能",
  "svo.disable": "断使能",
  "svo.reset": "复位",
  "svo.init": "初始化",
  "svo.stop": "停止",
  "svo.JOG+": "JOG+",
  "svo.JogVelocity": "JOG",
  "svo.JOG-": "JOG-",
  "svo.position": "位置",
  "svo.currentPosition": "当前位置",
  "svo.currentSpeed": "当前速度",
  "svo.OverAcc": "加速度",
  "svo.OverDec": "减速度",
  "svo.HMIPosition": "写入位置",
  "svo.HMISpeed": "写入速度",
  "svo.absExecute": "绝对执行",
  "svo.inching": "寸动",
  "svo.InchDistance": "寸动",
  "svo.forward": "正向",
  "svo.backward": "反向",
  "svo.limitSensor": "限位传感器",
  "svo.limit+": "正限位",
  "svo.limit0": "原点",
  "svo.limit-": "负限位",
  "svo.isReady": "准备好",
  "svo.isRunning": "运行中",
  "svo.alarm": "报警",
  "svo.controlAlarm": "控制报警",
  "svo.driverAlarm": "驱动报警",
  "svo.faultDriven": "故障驱动",
  "svo.status": "状态",
  "svo.reOriginOk": "回原OK",
  "svo.fault": "故障",
  "svo.axisAlarm": "轴报警",
  "svo.code": "代码",
  "svo.product.model": "产品型号",
  "svo.product.programCode": "程序号",
  "svo.selectAServo": "请先选择要执行的伺服"
}
WPFProject/PanuonWindow.xaml
@@ -18,6 +18,7 @@
            xmlns:hc="clr-namespace:HMI.Core;assembly=HMI.Core"
            Closed="window_Closed"
            Topmost="False"
            Title="TestPlatform"
            pu:WindowXCaption.Background="Transparent"
            pu:WindowXCaption.Height="80"
            IsOverlayerVisible="True"
WPFProject/WPFProject.csproj
@@ -125,8 +125,8 @@
    <Reference Include="Panuon.WPF, Version=1.1.2.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\Panuon.WPF.1.1.3\lib\net472\Panuon.WPF.dll</HintPath>
    </Reference>
    <Reference Include="Panuon.WPF.UI, Version=1.2.4.8, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\Panuon.WPF.UI.1.2.4.9\lib\net472\Panuon.WPF.UI.dll</HintPath>
    <Reference Include="Panuon.WPF.UI, Version=1.3.0.2, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\Panuon.WPF.UI.1.3.0.2\lib\net472\Panuon.WPF.UI.dll</HintPath>
    </Reference>
    <Reference Include="PresentationFramework.Aero" />
    <Reference Include="System" />
@@ -494,6 +494,9 @@
    <Content Include="Lang\zh-CN\ServoManage.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="Lang\en-US\ServoManage.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <None Include="packages.config" />
    <None Include="Properties\app.manifest" />
    <None Include="Properties\Settings.settings">
WPFProject/WPFProject.sln
@@ -41,6 +41,10 @@
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plugin.ServoManage", "..\Plugin.ServoManage\Plugin.ServoManage.csproj", "{1853E00F-6865-4BC6-974B-6A5E1C00BAFE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpcInterface", "..\..\HMI.Old\OPCInterface\OpcInterface\OpcInterface.csproj", "{E1464149-2C0A-499D-AB90-0C72E6ED1C53}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plugin.DOControl", "..\Plugin.DOControl\Plugin.DOControl.csproj", "{306A83DC-A7DB-4057-BAA7-477D8756F5D9}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
@@ -201,6 +205,22 @@
        {1853E00F-6865-4BC6-974B-6A5E1C00BAFE}.Release|Any CPU.Build.0 = Release|Any CPU
        {1853E00F-6865-4BC6-974B-6A5E1C00BAFE}.Release|x64.ActiveCfg = Release|Any CPU
        {1853E00F-6865-4BC6-974B-6A5E1C00BAFE}.Release|x64.Build.0 = Release|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Debug|x64.ActiveCfg = Debug|x64
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Debug|x64.Build.0 = Debug|x64
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Release|Any CPU.Build.0 = Release|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Release|x64.ActiveCfg = Release|Any CPU
        {E1464149-2C0A-499D-AB90-0C72E6ED1C53}.Release|x64.Build.0 = Release|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Debug|x64.ActiveCfg = Debug|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Debug|x64.Build.0 = Debug|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Release|Any CPU.Build.0 = Release|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Release|x64.ActiveCfg = Release|Any CPU
        {306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Release|x64.Build.0 = Release|Any CPU
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
WPFProject/packages.config
@@ -7,7 +7,7 @@
  <package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.39" targetFramework="net472" />
  <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
  <package id="Panuon.WPF" version="1.1.3" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.2.4.9" targetFramework="net472" />
  <package id="Panuon.WPF.UI" version="1.3.0.2" targetFramework="net472" />
  <package id="System.IO" version="4.3.0" targetFramework="net472" />
  <package id="System.Net.Http" version="4.3.4" targetFramework="net472" />
  <package id="System.Runtime" version="4.3.0" targetFramework="net472" />