领胜LDS 键盘AOI检测项目
1. 添加操作员输入和界面显示
2. 添加通过输入窗体
3. 添加webservice调用帮助类
4. M071添加MES数据检查和数据上传功能,添加相关界面显示和流程控制
5个文件已添加
11个文件已修改
892 ■■■■■ 已修改文件
M071.sln 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Model/Bro.Common.Model.csproj 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Model/Helper/WebServiceHelper.cs 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/Bro.M071.Process.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Config.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Models.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process.cs 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process_MES.cs 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/Properties/AssemblyInfo.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_MainForm.Designer.cs 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_MainForm.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_MainForm.resx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/Bro.UI.Model.Winform.csproj 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/InputWindow.Designer.cs 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/InputWindow.cs 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/InputWindow.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
M071.sln
@@ -142,6 +142,7 @@
        {741F6491-57C7-479A-B391-09BBA9FBA9DC}.Release|x64.ActiveCfg = Release|Any CPU
        {741F6491-57C7-479A-B391-09BBA9FBA9DC}.Release|x64.Build.0 = Release|Any CPU
        {B536003E-70BA-4701-B8FD-BAFA303AB4E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {B536003E-70BA-4701-B8FD-BAFA303AB4E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {B536003E-70BA-4701-B8FD-BAFA303AB4E2}.Debug|x64.ActiveCfg = Debug|Any CPU
        {B536003E-70BA-4701-B8FD-BAFA303AB4E2}.Debug|x64.Build.0 = Debug|Any CPU
        {B536003E-70BA-4701-B8FD-BAFA303AB4E2}.Debug1|Any CPU.ActiveCfg = Debug|Any CPU
src/Bro.Common.Model/Bro.Common.Model.csproj
@@ -88,6 +88,8 @@
    <Reference Include="System.Core" />
    <Reference Include="System.Design" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Web" />
    <Reference Include="System.Web.Services" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
@@ -130,6 +132,7 @@
    <Compile Include="Helper\TimeOutHelper.cs" />
    <Compile Include="Helper\UIHelper.cs" />
    <Compile Include="Helper\WebApiHelper.cs" />
    <Compile Include="Helper\WebServiceHelper.cs" />
    <Compile Include="Interface\IMenuNode.cs" />
    <Compile Include="Interface\IConfigCtrl.cs" />
    <Compile Include="Interface\ICSVOutput.cs" />
src/Bro.Common.Model/Helper/WebServiceHelper.cs
New file
@@ -0,0 +1,98 @@
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Caching;
using System.Web.Services.Description;
using System.Xml.Serialization;
namespace Bro.Common.Helper
{
    public class WebServiceHelper
    {
        /// <summary>
        /// 生成dll文件保存到本地
        /// </summary>
        /// <param name="url">WebService地址</param>
        /// <param name="className">类名</param>
        /// <param name="methodName">方法名</param>
        /// <param name="filePath">保存dll文件的路径</param>
        public static void CreateWebServiceDLL(string url, string className, string methodName, string filePath)
        {
            // 1. 使用 WebClient 下载 WSDL 信息。
            WebClient web = new WebClient();
            Stream stream = web.OpenRead(url + "?wsdl");
            // 2. 创建和格式化 WSDL 文档。
            ServiceDescription description = ServiceDescription.Read(stream);
            //如果不存在就创建file文件夹
            if (Directory.Exists(filePath) == false)
            {
                Directory.CreateDirectory(filePath);
            }
            if (File.Exists(filePath + className + "_" + methodName + ".dll"))
            {
                //判断缓存是否过期
                var cachevalue = HttpRuntime.Cache.Get(className + "_" + methodName);
                if (cachevalue == null)
                {
                    //缓存过期删除dll
                    File.Delete(filePath + className + "_" + methodName + ".dll");
                }
                else
                {
                    // 如果缓存没有过期直接返回
                    return;
                }
            }
            // 3. 创建客户端代理代理类。
            ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
            // 指定访问协议。
            importer.ProtocolName = "Soap";
            // 生成客户端代理。
            importer.Style = ServiceDescriptionImportStyle.Client;
            importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
            // 添加 WSDL 文档。
            importer.AddServiceDescription(description, null, null);
            // 4. 使用 CodeDom 编译客户端代理类。
            // 为代理类添加命名空间,缺省为全局空间。
            CodeNamespace nmspace = new CodeNamespace();
            CodeCompileUnit unit = new CodeCompileUnit();
            unit.Namespaces.Add(nmspace);
            ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            CompilerParameters parameter = new CompilerParameters();
            parameter.GenerateExecutable = false;
            // 可以指定你所需的任何文件名。
            parameter.OutputAssembly = filePath + className + "_" + methodName + ".dll";
            parameter.ReferencedAssemblies.Add("System.dll");
            parameter.ReferencedAssemblies.Add("System.XML.dll");
            parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
            parameter.ReferencedAssemblies.Add("System.Data.dll");
            // 生成dll文件,并会把WebService信息写入到dll里面
            CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
            if (result.Errors.HasErrors)
            {
                // 显示编译错误信息
                System.Text.StringBuilder sb = new StringBuilder();
                foreach (CompilerError ce in result.Errors)
                {
                    sb.Append(ce.ToString());
                    sb.Append(System.Environment.NewLine);
                }
                throw new Exception(sb.ToString());
            }
            //记录缓存
            var objCache = HttpRuntime.Cache;
            // 缓存信息写入dll文件
            objCache.Insert(className + "_" + methodName, "1", null, DateTime.Now.AddMinutes(5), TimeSpan.Zero, CacheItemPriority.High, null);
        }
    }
}
src/Bro.M071.Process/Bro.M071.Process.csproj
@@ -121,6 +121,7 @@
    <Compile Include="M071Config.cs" />
    <Compile Include="M071Models.cs" />
    <Compile Include="M071Process.cs" />
    <Compile Include="M071Process_MES.cs" />
    <Compile Include="M071Process_MotionCard.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="UI\KeyIndicator.cs" />
@@ -211,5 +212,8 @@
      <Name>Bro.UI.Model.Winform</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <WCFMetadata Include="Connected Services\" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
src/Bro.M071.Process/M071Config.cs
@@ -132,9 +132,41 @@
        [Category("MES设置")]
        [Description("true:数据上传至MES false:数据不上传")]
        [DisplayName("MES上传启用")]
        [ReadOnly(true)]
        public bool IsEnableMESUpload { get; set; } = false;
        [Category("MES设置")]
        [Description("true:检测用户登录 false:不强制用户登录")]
        [DisplayName("用户登录检测")]
        [Browsable(false)]
        public bool IsUserLoginCheck { get; set; } = false;
        [Category("MES设置")]
        [Description("MES上传路径")]
        [DisplayName("MES上传路径")]
        public string MESURL { get; set; } = "";
        [Category("MES设置")]
        [Description("站点编码")]
        [DisplayName("站点编码")]
        public string StationCode { get; set; } = "";
        [Category("MES设置")]
        [Description("Project编码")]
        [DisplayName("Project编码")]
        public string ProjectCode { get; set; } = "";
        [Category("MES设置")]
        [Description("线体编码")]
        [DisplayName("线体编码")]
        public string LineCode { get; set; } = "";
        [Category("MES设置")]
        [Description("验证当前允许新增次数[FALSE=不验证 TRUE=限制两次以下(包含两次)]")]
        [DisplayName("多次验证开关")]
        public bool IsDisableMultipleCheckTimes { get; set; }
        [Category("复位设置")]
        [Description("大复位需要信号持续时间,复位信号持续超出该时间执行大复位,单位:s")]
        [DisplayName("大复位持续信号长度")]
src/Bro.M071.Process/M071Models.cs
@@ -349,6 +349,11 @@
            mUnit.Id = this.Id;
            mUnit.Name = this.Name;
            if (string.IsNullOrWhiteSpace(mUnit.Name))
            {
                mUnit.Name = string.Join("-", KeyUnitCollection.Select(u => u.GetDisplayText()));
            }
            mUnit.IsEnabled = this.IsEnabled;
            mUnit.MeasureType = this.MeasureType;
src/Bro.M071.Process/M071Process.cs
@@ -50,7 +50,6 @@
        string _precision = "f3";
        public override void Open()
        {
            InitialSetting();
@@ -71,6 +70,9 @@
            {
                _precision = "f" + Config.Precision;
            }
            IncomingCheckMethod = InitialMESWebServiceMethod(IncomingCheckMethodName, out IncomingCheckObj);
            DataUploadMethod = InitialMESWebServiceMethod(DataUploadMethodName, out DataUploadObj);
        }
        private void InitialMotionCardBaseAxisAlarm()
@@ -183,8 +185,6 @@
        }
        #endregion
        public string BarCode { get; set; }
        List<ProductionMeasurement> productionList = new List<ProductionMeasurement>();
        [ProcessMethod("", "StartJob", "开始扫描", InvokeType.TestInvoke)]
@@ -195,16 +195,25 @@
                throw new ProcessException(SafetyMsg, null, ExceptionLevel.Fatal);
            }
            string hint = "";
            if (MachineState != MachineState.Ready)
                throw new ProcessException("机台未就绪,请勿开始测量", null, ExceptionLevel.Fatal);
            {
                hint = "机台未就绪,请勿开始测量";
                OnCheckHintUpload?.Invoke(hint, true);
                throw new ProcessException(hint, null, ExceptionLevel.Fatal);
            }
            if (string.IsNullOrWhiteSpace(BarCode))
            {
                hint = "未输入产品条码,请勿开始测量";
                OnClearBarcode?.Invoke();
                throw new ProcessException("未输入产品条码,请勿开始测量");
                OnCheckHintUpload?.Invoke(hint, true);
                throw new ProcessException(hint);
            }
            MachineState = MachineState.Running;
            OnCheckHintUpload?.Invoke(hint, true);
            OnMeasureStart?.Invoke();
            //var measurements = Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().DeepSerializeClone();
@@ -374,7 +383,8 @@
                            {
                                if (m.KeyUnitCollection.Any(k => k.IsDone == false))
                                {
                                    m.Spec.ActualValue = -999;
                                    //m.Spec.ActualValue = -999;
                                    m.Spec.ActualValue = null;
                                }
                                else
                                {
@@ -382,7 +392,8 @@
                                    if (!_halconToolDict.ContainsKey(toolKey))
                                    {
                                        LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法未初始化", "");
                                        m.Spec.ActualValue = -999;
                                        //m.Spec.ActualValue = -999;
                                        m.Spec.ActualValue = null;
                                    }
                                    else
                                    {
@@ -392,7 +403,8 @@
                                        if (array == null || array.Length == 0)
                                        {
                                            LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}未能获取对应检测值", "");
                                            m.Spec.ActualValue = -999;
                                            //m.Spec.ActualValue = -999;
                                            m.Spec.ActualValue = null;
                                        }
                                        else
                                        {
@@ -401,7 +413,8 @@
                                            if (!_halconToolDict[toolKey].RunProcedure(out string error))
                                            {
                                                LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法异常,{error}", "");
                                                m.Spec.ActualValue = -999;
                                                //m.Spec.ActualValue = -999;
                                                m.Spec.ActualValue = null;
                                            }
                                            else
                                            {
@@ -415,7 +428,8 @@
                                //LogAsync(DateTime.Now, $"{m.GetDisplayText()}检测结果", $"{((m.Spec.MeasureResult ?? false) ? "OK" : "NG")}");
                                KeyIndicator indicator = new KeyIndicator(m.Id, m.DisplayLocation);
                                indicator.Text = (m.Spec.ActualValue == null || m.Spec.ActualValue == -999) ? "NA" : m.Spec.ActualValue.Value.ToString(_precision);
                                //indicator.Text = (m.Spec.ActualValue == null || m.Spec.ActualValue == -999) ? "NA" : m.Spec.ActualValue.Value.ToString(_precision);
                                indicator.Text = m.Spec.ActualValue == null ? "NA" : m.Spec.ActualValue.Value.ToString(_precision);
                                indicator.ResultState = m.Spec.MeasureResult;
                                pMeasure.ElementList.Add(indicator);
                                //输出图形基元到界面 
@@ -435,9 +449,27 @@
                }
                pMeasure.EndTime = DateTime.Now;
                bool pResult = pMeasure.Measurements.All(u => u.Spec.MeasureResult == true);
                pMeasure.PResult = pResult ? "OK" : "NG";
                OnUpdateResult?.Invoke(DateTime.Now, pResult ? 1 : 0);
                //bool pResult = pMeasure.Measurements.All(u => u.Spec.MeasureResult == true);
                //pMeasure.PResult = pResult ? "OK" : "NG";
                //OnUpdateResult?.Invoke(DateTime.Now, pResult ? 1 : 0);
                //OnUpdateCT?.Invoke((float)(pMeasure.EndTime.Value - pMeasure.StartTime.Value).TotalSeconds);
                int result = -1;
                if (pMeasure.Measurements.Any(u => u.Spec.MeasureResult == null))
                {
                    pMeasure.PResult = "NA";
                }
                else if (pMeasure.Measurements.Any(u => u.Spec.MeasureResult == false))
                {
                    pMeasure.PResult = "NG";
                    result = 0;
                }
                else
                {
                    pMeasure.PResult = "OK";
                    result = 1;
                }
                OnUpdateResult?.Invoke(DateTime.Now, result);
                OnUpdateCT?.Invoke((float)(pMeasure.EndTime.Value - pMeasure.StartTime.Value).TotalSeconds);
                LogAsync(DateTime.Now, $"{pMeasure.Barcode} 检测完成,结果 {pMeasure.PResult}", "");
@@ -447,9 +479,10 @@
                var measurementUnitResultAndKeyUnitDataSet = GetMeasurementUnitResultAndKeyUnitData(pMeasure);
                //MES输出 todo
                if (Config.IsEnableMESUpload)
                if (pMeasure.PResult != "NA")
                {
                    //MES输出
                    MESCheckDataUpload(pMeasure);
                }
                //Excel报表输出 (单个产品的excel导出)
src/Bro.M071.Process/M071Process_MES.cs
New file
@@ -0,0 +1,239 @@
using Bro.Common.Helper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Bro.M071.Process
{
    public partial class M071Process
    {
        #region MES
        //WebApiHelper _webApiHelper = new WebApiHelper();
        public Action<string, bool> OnCheckHintUpload { get; set; }
        public Action<string> OnOperatorLogin { get; set; }
        #endregion
        private string barcode = "";
        public string BarCode
        {
            get => barcode;
            set
            {
                barcode = value;
                if (!string.IsNullOrWhiteSpace(barcode))
                {
                    if (!CheckIncoming(barcode))
                    {
                        barcode = "";
                    }
                }
            }
        }
        private string operatorCode = "";
        public string OperatorCode
        {
            get => operatorCode;
            set
            {
                operatorCode = value;
                if (!string.IsNullOrWhiteSpace(operatorCode))
                {
                    OnOperatorLogin?.Invoke(operatorCode);
                    OnCheckHintUpload?.Invoke($"操作员登录:{operatorCode}", false);
                }
            }
        }
        #region WebService Method
        MethodInfo incomingCheckMethod = null;
        MethodInfo dataUploadMethod = null;
        const string IncomingCheckMethodName = "CheckFormerData";
        const string DataUploadMethodName = "HighLowKey_DataUpLoad";
        private object IncomingCheckObj = null;
        public MethodInfo IncomingCheckMethod
        {
            get
            {
                if (incomingCheckMethod == null)
                {
                    incomingCheckMethod = InitialMESWebServiceMethod(IncomingCheckMethodName, out IncomingCheckObj);
                }
                return incomingCheckMethod;
            }
            set => incomingCheckMethod = value;
        }
        private object DataUploadObj = null;
        public MethodInfo DataUploadMethod
        {
            get
            {
                if (incomingCheckMethod == null)
                {
                    incomingCheckMethod = InitialMESWebServiceMethod(DataUploadMethodName, out DataUploadObj);
                }
                return incomingCheckMethod;
            }
            set => incomingCheckMethod = value;
        }
        private MethodInfo InitialMESWebServiceMethod(string methodName, out object invokeClass)
        {
            invokeClass = null;
            if (!Config.IsEnableMESUpload)
                return null;
            // 读取配置文件,获取配置信息
            var urlParas = Config.MESURL.Split(new char[] { '/', '.' }, StringSplitOptions.RemoveEmptyEntries);
            string className = urlParas[urlParas.Length - 2];
            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MESAPI");
            if (Directory.Exists(filePath))
            {
                Directory.CreateDirectory(filePath);
            }
            // 调用WebServiceHelper
            WebServiceHelper.CreateWebServiceDLL(Config.MESURL, className, methodName, filePath);
            // 读取dll内容
            byte[] filedata = File.ReadAllBytes(filePath + className + "_" + methodName + ".dll");
            // 加载程序集信息
            Assembly asm = Assembly.Load(filedata);
            Type t = asm.GetType(className);
            // 创建实例
            invokeClass = Activator.CreateInstance(t);
            return t.GetMethod(methodName);
        }
        #endregion
        private bool CheckIncoming(string barcode)
        {
            if (!Config.IsEnableMESUpload)
                return true;
            //dynamic paras = new
            //{
            //    FGcode = barcode,
            //    station = Config.StationCode,
            //};
            //string url = $"{Config.MESURL}CheckFormerData";
            //string paraStr = JsonConvert.SerializeObject(paras);
            //LogAsync(DateTime.Now, $"MES入料检测 {url}", paraStr);
            IncomingCheckMethod = InitialMESWebServiceMethod(IncomingCheckMethodName, out IncomingCheckObj);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //var result = _webApiHelper.dooPost(url, paraStr);
            object[] paras = new object[] { barcode, Config.StationCode };
            var result = IncomingCheckMethod?.Invoke(IncomingCheckObj, paras).ToString();
            var mesReturn = (MESIncomingCheckReturn)int.Parse(result);
            sw.Stop();
            LogAsync(DateTime.Now, $"{barcode}产品条码检测,{result}|{mesReturn.ToString()}", $"耗时:{sw.ElapsedMilliseconds}ms");
            bool isOK = mesReturn == MESIncomingCheckReturn.检测PASS;
            OnCheckHintUpload?.Invoke("条码检测" + mesReturn.ToString(), !isOK);
            return isOK;
        }
        private void MESCheckDataUpload(ProductionMeasurement pMeasure)
        {
            if (!Config.IsEnableMESUpload)
                return;
            //dynamic paras = new
            //{
            //    checkTimes = Config.IsDisableMultipleCheckTimes,
            //    Project = Config.ProjectCode,
            //    FGcode = pMeasure.Barcode,
            //    CheckTime = pMeasure.EndTime.Value.ToString("yyyy-MM-dd HH:mm:ss"),
            //    ProcessCode = Config.StationCode,
            //    Result = pMeasure.PResult == "OK" ? "PASS" : "FAIL",
            //    Line = Config.LineCode,
            //    SlantCheckData = GetMESSlantData(pMeasure),
            //    AlignmentCheckData = GetMESAlignmentData(pMeasure),
            //};
            //string url = $"{Config.MESURL}HighLowKey_DataUpload";
            //string paraStr = JsonConvert.SerializeObject(paras);
            //LogAsync(DateTime.Now, $"MES数据上传 {url}", paraStr);
            DataUploadMethod = InitialMESWebServiceMethod(DataUploadMethodName, out DataUploadObj);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //var result = _webApiHelper.dooPost(url, paraStr);
            DateTime checkTime = pMeasure.EndTime.Value;
            object[] paras = new object[]
            {
                Config.IsDisableMultipleCheckTimes,
                Config.ProjectCode,
                pMeasure.Barcode,
                checkTime.ToString("yyyy-MM-dd HH:mm:ss"),
                Config.StationCode,
                pMeasure.PResult == "OK" ? "PASS" : "FAIL",
                Config.LineCode,
                GetMESSlantData(pMeasure),
                GetMESAlignmentData(pMeasure)
            };
            //LogAsync(DateTime.Now, $"{barcode}产品检测数据上传", JsonConvert.SerializeObject(paras));
            var result = DataUploadMethod?.Invoke(DataUploadObj, paras).ToString();
            var mesReturn = (MESUploadReturn)int.Parse(result);
            sw.Stop();
            LogAsync(DateTime.Now, $"{barcode}产品检测数据上传,{result}|{mesReturn.ToString()}", $"耗时:{sw.ElapsedMilliseconds}ms");
            OnCheckHintUpload?.Invoke("检测数据" + mesReturn.ToString(), mesReturn != MESUploadReturn.上传成功);
        }
        private string GetMESAlignmentData(ProductionMeasurement pMeasure)
        {
            return string.Join(",", pMeasure.Measurements.Where(u => u.MeasureType == "Alignment").Select(u => $"{u.Name}:{u.Spec.ActualValue.Value.ToString(_precision)}"));
        }
        private string GetMESSlantData(ProductionMeasurement pMeasure)
        {
            return string.Join(",", pMeasure.Measurements.Where(u => u.MeasureType == "Slant").Select(u => $"{u.Name}:{u.Spec.ActualValue.Value.ToString(_precision)}"));
        }
    }
    public enum MESIncomingCheckReturn
    {
        上传结果未知 = -3,
        未查询到工序信息 = -2,
        未查询到SN信息 = -1,
        检测FAIL = 0,
        检测PASS = 1,
    }
    public enum MESUploadReturn
    {
        上传结果未知 = -1,
        上传失败 = 0,
        上传成功 = 1,
        工序检测异常 = 2,
        检测次数异常 = 3,
    }
}
src/Bro.M071.Process/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.2.0")]
[assembly: AssemblyFileVersion("1.0.2.0")]
src/Bro.M071.Process/UI/M071_MainForm.Designer.cs
@@ -50,6 +50,9 @@
            this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.propGridKeyIndicator = new System.Windows.Forms.PropertyGrid();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            this.lblOperator = new System.Windows.Forms.Label();
            this.stStripHint = new System.Windows.Forms.StatusStrip();
            this.tsslError = new System.Windows.Forms.ToolStripStatusLabel();
            this.contextMenuStrip1.SuspendLayout();
            this.plImage.SuspendLayout();
            this.tscEditLocation.ContentPanel.SuspendLayout();
@@ -59,6 +62,7 @@
            this.splitContainer1.Panel1.SuspendLayout();
            this.splitContainer1.Panel2.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.stStripHint.SuspendLayout();
            this.SuspendLayout();
            // 
            // contextMenuStrip1
@@ -109,7 +113,7 @@
            this.btnReset.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnReset.Font = new System.Drawing.Font("宋体", 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.btnReset.ForeColor = System.Drawing.Color.DarkGreen;
            this.btnReset.Location = new System.Drawing.Point(531, 8);
            this.btnReset.Location = new System.Drawing.Point(800, 8);
            this.btnReset.Name = "btnReset";
            this.btnReset.Size = new System.Drawing.Size(141, 35);
            this.btnReset.TabIndex = 5;
@@ -125,7 +129,7 @@
            this.btnStartMeasure.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnStartMeasure.Font = new System.Drawing.Font("宋体", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.btnStartMeasure.ForeColor = System.Drawing.Color.DarkGreen;
            this.btnStartMeasure.Location = new System.Drawing.Point(678, 8);
            this.btnStartMeasure.Location = new System.Drawing.Point(947, 8);
            this.btnStartMeasure.Name = "btnStartMeasure";
            this.btnStartMeasure.Size = new System.Drawing.Size(110, 35);
            this.btnStartMeasure.TabIndex = 5;
@@ -137,7 +141,7 @@
            // 
            this.lblCT.AutoSize = true;
            this.lblCT.Font = new System.Drawing.Font("Tahoma", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.lblCT.Location = new System.Drawing.Point(464, 19);
            this.lblCT.Location = new System.Drawing.Point(550, 21);
            this.lblCT.Name = "lblCT";
            this.lblCT.Size = new System.Drawing.Size(35, 14);
            this.lblCT.TabIndex = 4;
@@ -146,7 +150,7 @@
            // txtBarcode
            // 
            this.txtBarcode.Font = new System.Drawing.Font("Tahoma", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.txtBarcode.Location = new System.Drawing.Point(138, 13);
            this.txtBarcode.Location = new System.Drawing.Point(222, 13);
            this.txtBarcode.Name = "txtBarcode";
            this.txtBarcode.Size = new System.Drawing.Size(261, 24);
            this.txtBarcode.TabIndex = 3;
@@ -159,7 +163,7 @@
            this.lblProductionState.BackColor = System.Drawing.Color.Lime;
            this.lblProductionState.Font = new System.Drawing.Font("Tahoma", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.lblProductionState.ForeColor = System.Drawing.Color.DarkGreen;
            this.lblProductionState.Location = new System.Drawing.Point(405, 13);
            this.lblProductionState.Location = new System.Drawing.Point(489, 13);
            this.lblProductionState.Name = "lblProductionState";
            this.lblProductionState.Size = new System.Drawing.Size(39, 24);
            this.lblProductionState.TabIndex = 2;
@@ -171,7 +175,7 @@
            this.lblMachineState.BackColor = System.Drawing.Color.Lime;
            this.lblMachineState.Font = new System.Drawing.Font("Tahoma", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.lblMachineState.ForeColor = System.Drawing.Color.DarkGreen;
            this.lblMachineState.Location = new System.Drawing.Point(22, 12);
            this.lblMachineState.Location = new System.Drawing.Point(137, 13);
            this.lblMachineState.Name = "lblMachineState";
            this.lblMachineState.Size = new System.Drawing.Size(79, 24);
            this.lblMachineState.TabIndex = 2;
@@ -186,7 +190,7 @@
            this.plImage.Controls.Add(this.tscEditLocation);
            this.plImage.Location = new System.Drawing.Point(1, 47);
            this.plImage.Name = "plImage";
            this.plImage.Size = new System.Drawing.Size(796, 304);
            this.plImage.Size = new System.Drawing.Size(1065, 279);
            this.plImage.TabIndex = 1;
            // 
            // tscEditLocation
@@ -195,11 +199,11 @@
            // tscEditLocation.ContentPanel
            // 
            this.tscEditLocation.ContentPanel.Controls.Add(this.tableLayoutPanel1);
            this.tscEditLocation.ContentPanel.Size = new System.Drawing.Size(209, 279);
            this.tscEditLocation.ContentPanel.Size = new System.Drawing.Size(209, 254);
            this.tscEditLocation.Dock = System.Windows.Forms.DockStyle.Right;
            this.tscEditLocation.Location = new System.Drawing.Point(587, 0);
            this.tscEditLocation.Location = new System.Drawing.Point(856, 0);
            this.tscEditLocation.Name = "tscEditLocation";
            this.tscEditLocation.Size = new System.Drawing.Size(209, 304);
            this.tscEditLocation.Size = new System.Drawing.Size(209, 279);
            this.tscEditLocation.TabIndex = 0;
            this.tscEditLocation.Text = "toolStripContainer1";
            this.tscEditLocation.Visible = false;
@@ -218,7 +222,7 @@
            this.tableLayoutPanel1.RowCount = 2;
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
            this.tableLayoutPanel1.Size = new System.Drawing.Size(209, 279);
            this.tableLayoutPanel1.Size = new System.Drawing.Size(209, 254);
            this.tableLayoutPanel1.TabIndex = 0;
            // 
            // btnConfirmEdit
@@ -227,7 +231,7 @@
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.btnConfirmEdit.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnConfirmEdit.Location = new System.Drawing.Point(3, 246);
            this.btnConfirmEdit.Location = new System.Drawing.Point(3, 221);
            this.btnConfirmEdit.Name = "btnConfirmEdit";
            this.btnConfirmEdit.Size = new System.Drawing.Size(98, 30);
            this.btnConfirmEdit.TabIndex = 0;
@@ -241,7 +245,7 @@
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.btnCancelEdit.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnCancelEdit.Location = new System.Drawing.Point(107, 246);
            this.btnCancelEdit.Location = new System.Drawing.Point(107, 221);
            this.btnCancelEdit.Name = "btnCancelEdit";
            this.btnCancelEdit.Size = new System.Drawing.Size(99, 30);
            this.btnCancelEdit.TabIndex = 0;
@@ -264,8 +268,8 @@
            // splitContainer1.Panel2
            // 
            this.splitContainer1.Panel2.Controls.Add(this.propGridKeyIndicator);
            this.splitContainer1.Size = new System.Drawing.Size(203, 237);
            this.splitContainer1.SplitterDistance = 136;
            this.splitContainer1.Size = new System.Drawing.Size(203, 212);
            this.splitContainer1.SplitterDistance = 121;
            this.splitContainer1.TabIndex = 1;
            // 
            // lvMeasures
@@ -280,7 +284,7 @@
            this.lvMeasures.Location = new System.Drawing.Point(0, 0);
            this.lvMeasures.MultiSelect = false;
            this.lvMeasures.Name = "lvMeasures";
            this.lvMeasures.Size = new System.Drawing.Size(203, 136);
            this.lvMeasures.Size = new System.Drawing.Size(203, 121);
            this.lvMeasures.TabIndex = 0;
            this.lvMeasures.UseCompatibleStateImageBehavior = false;
            this.lvMeasures.View = System.Windows.Forms.View.List;
@@ -297,7 +301,7 @@
            this.propGridKeyIndicator.Dock = System.Windows.Forms.DockStyle.Fill;
            this.propGridKeyIndicator.Location = new System.Drawing.Point(0, 0);
            this.propGridKeyIndicator.Name = "propGridKeyIndicator";
            this.propGridKeyIndicator.Size = new System.Drawing.Size(203, 97);
            this.propGridKeyIndicator.Size = new System.Drawing.Size(203, 87);
            this.propGridKeyIndicator.TabIndex = 0;
            this.propGridKeyIndicator.ToolbarVisible = false;
            // 
@@ -306,11 +310,45 @@
            this.timer1.Interval = 3000;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // lblOperator
            //
            this.lblOperator.AutoSize = true;
            this.lblOperator.Cursor = System.Windows.Forms.Cursors.Hand;
            this.lblOperator.Font = new System.Drawing.Font("Tahoma", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World, ((byte)(134)));
            this.lblOperator.Location = new System.Drawing.Point(22, 17);
            this.lblOperator.Name = "lblOperator";
            this.lblOperator.Size = new System.Drawing.Size(78, 17);
            this.lblOperator.TabIndex = 6;
            this.lblOperator.Text = "OPERATOR";
            this.lblOperator.DoubleClick += new System.EventHandler(this.lblOperator_DoubleClick);
            //
            // stStripHint
            //
            this.stStripHint.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.tsslError});
            this.stStripHint.Location = new System.Drawing.Point(0, 329);
            this.stStripHint.Name = "stStripHint";
            this.stStripHint.Size = new System.Drawing.Size(1069, 22);
            this.stStripHint.TabIndex = 7;
            this.stStripHint.Text = "statusStrip1";
            this.stStripHint.Visible = false;
            //
            // tsslError
            //
            this.tsslError.BackColor = System.Drawing.Color.Red;
            this.tsslError.ForeColor = System.Drawing.SystemColors.Control;
            this.tsslError.Margin = new System.Windows.Forms.Padding(10, 3, 0, 2);
            this.tsslError.Name = "tsslError";
            this.tsslError.Size = new System.Drawing.Size(131, 17);
            this.tsslError.Text = "toolStripStatusLabel1";
            //
            // M071_MainForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 351);
            this.ClientSize = new System.Drawing.Size(1069, 351);
            this.Controls.Add(this.stStripHint);
            this.Controls.Add(this.lblOperator);
            this.Controls.Add(this.btnReset);
            this.Controls.Add(this.btnStartMeasure);
            this.Controls.Add(this.lblCT);
@@ -332,6 +370,8 @@
            this.splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
            this.splitContainer1.ResumeLayout(false);
            this.stStripHint.ResumeLayout(false);
            this.stStripHint.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();
@@ -360,5 +400,8 @@
        private System.Windows.Forms.ColumnHeader columnHeader1;
        private System.Windows.Forms.ToolStripMenuItem tsmiRefreshLabels;
        private System.Windows.Forms.Timer timer1;
        private System.Windows.Forms.Label lblOperator;
        private System.Windows.Forms.StatusStrip stStripHint;
        private System.Windows.Forms.ToolStripStatusLabel tsslError;
    }
}
src/Bro.M071.Process/UI/M071_MainForm.cs
@@ -1,6 +1,7 @@
using Bro.Common.Base;
using Bro.Common.Helper;
using Bro.UI.Model.Winform;
using Bro.UI.Model.Winform.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -44,6 +45,8 @@
                   timer1.Enabled = true;
                   btnReset.Text = $"复位(长按{Config.FullResetRequiredDuration}秒大复位)";
                   lblCT.Text = tsslError.Text = "";
               };
        }
@@ -90,6 +93,8 @@
                           item.Tag = u.Id;
                           lvMeasures.Items.Add(item);
                       });
                       lblOperator.Text = string.IsNullOrWhiteSpace(Process_M071.OperatorCode) ? "NotLogin" : Process_M071.OperatorCode;
                   }));
            }
            catch (Exception ex)
@@ -117,6 +122,9 @@
            Process_M071.OnElementUpdated -= Process_M071_OnElementUpdated;
            Process_M071.OnElementUpdated += Process_M071_OnElementUpdated;
            Process_M071.OnCheckHintUpload = OnCheckHintUpload;
            Process_M071.OnOperatorLogin = OnOperatorLogin;
        }
        private void Config_PropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -312,7 +320,7 @@
            if (e.KeyValue == 13)
            {
                txtBarcode.Text = _barcode;
                Process_M071.BarCode = txtBarcode.Text = _barcode;
                _barcode = "";
            }
@@ -324,7 +332,7 @@
        private void txtBarcode_TextChanged(object sender, EventArgs e)
        {
            Process_M071.BarCode = txtBarcode.Text.Trim();
            //Process_M071.BarCode = txtBarcode.Text.Trim();
        }
        private void M071_MainForm_OnClearBarcode()
@@ -409,11 +417,17 @@
                    lblProductionState.ForeColor = Color.White;
                    lblProductionState.Text = "OK";
                }
                else
                else if (result == 0)
                {
                    lblProductionState.BackColor = Color.Red;
                    lblProductionState.ForeColor = Color.White;
                    lblProductionState.Text = "NG";
                }
                else
                {
                    lblProductionState.BackColor = Color.White;
                    lblProductionState.ForeColor = Color.Red;
                    lblProductionState.Text = "NA";
                }
                //btnStartMeasure.Text = "开始测量";
@@ -504,5 +518,44 @@
        {
            cvImage.Refresh();
        }
        private void lblOperator_DoubleClick(object sender, EventArgs e)
        {
            InputWindow inputFrm = new InputWindow("请输入操作员工号");
            if (inputFrm.ShowDialog() == DialogResult.OK)
            {
                Process_M071.OperatorCode = inputFrm.Input;
            }
        }
        private void OnOperatorLogin(string operatorCode)
        {
            this.Invoke(new Action(() =>
            {
                lblOperator.Text = operatorCode;
            }));
        }
        private async void OnCheckHintUpload(string hintMsg, bool isAlarm)
        {
            await Task.Run(() =>
            {
                this.Invoke(new Action(() =>
                {
                    if (!string.IsNullOrWhiteSpace(hintMsg))
                    {
                        stStripHint.Visible = true;
                        tsslError.Text = hintMsg;
                        tsslError.BackColor = isAlarm ? Color.Red : Color.Green;
                    }
                    else
                    {
                        stStripHint.Visible = false;
                        tsslError.Text = "";
                    }
                }));
            });
        }
    }
}
src/Bro.M071.Process/UI/M071_MainForm.resx
@@ -123,4 +123,7 @@
  <metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>182, 17</value>
  </metadata>
  <metadata name="stStripHint.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>272, 17</value>
  </metadata>
</root>
src/Bro.UI.Model.Winform/Bro.UI.Model.Winform.csproj
@@ -140,6 +140,12 @@
    <Compile Include="UI\DockContent\MenuFrmBase.Designer.cs">
      <DependentUpon>MenuFrmBase.cs</DependentUpon>
    </Compile>
    <Compile Include="UI\InputWindow.cs">
      <SubType>Form</SubType>
    </Compile>
    <Compile Include="UI\InputWindow.Designer.cs">
      <DependentUpon>InputWindow.cs</DependentUpon>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Bro.Common.Model\Bro.Common.Model.csproj">
@@ -173,6 +179,9 @@
    <EmbeddedResource Include="UI\DockContent\MenuFrmBase.resx">
      <DependentUpon>MenuFrmBase.cs</DependentUpon>
    </EmbeddedResource>
    <EmbeddedResource Include="UI\InputWindow.resx">
      <DependentUpon>InputWindow.cs</DependentUpon>
    </EmbeddedResource>
  </ItemGroup>
  <ItemGroup>
    <None Include="UI\ROIImg\grid.png" />
src/Bro.UI.Model.Winform/UI/InputWindow.Designer.cs
New file
@@ -0,0 +1,108 @@

namespace Bro.UI.Model.Winform.UI
{
    partial class InputWindow
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.lblTitle = new System.Windows.Forms.Label();
            this.txtInput = new System.Windows.Forms.TextBox();
            this.btnConfirm = new System.Windows.Forms.Button();
            this.btnCancel = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // lblTitle
            //
            this.lblTitle.AutoSize = true;
            this.lblTitle.Location = new System.Drawing.Point(30, 17);
            this.lblTitle.Name = "lblTitle";
            this.lblTitle.Size = new System.Drawing.Size(42, 17);
            this.lblTitle.TabIndex = 0;
            this.lblTitle.Text = "label1";
            //
            // txtInput
            //
            this.txtInput.Location = new System.Drawing.Point(33, 49);
            this.txtInput.Name = "txtInput";
            this.txtInput.Size = new System.Drawing.Size(301, 24);
            this.txtInput.TabIndex = 1;
            this.txtInput.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtInput_KeyPress);
            //
            // btnConfirm
            //
            this.btnConfirm.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(255)))), ((int)(((byte)(128)))));
            this.btnConfirm.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnConfirm.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnConfirm.Location = new System.Drawing.Point(259, 84);
            this.btnConfirm.Name = "btnConfirm";
            this.btnConfirm.Size = new System.Drawing.Size(75, 30);
            this.btnConfirm.TabIndex = 2;
            this.btnConfirm.Text = "确认";
            this.btnConfirm.UseVisualStyleBackColor = false;
            this.btnConfirm.Click += new System.EventHandler(this.btnConfirm_Click);
            //
            // btnCancel
            //
            this.btnCancel.BackColor = System.Drawing.SystemColors.Control;
            this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnCancel.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnCancel.Location = new System.Drawing.Point(178, 84);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(75, 30);
            this.btnCancel.TabIndex = 2;
            this.btnCancel.Text = "取消";
            this.btnCancel.UseVisualStyleBackColor = false;
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            //
            // InputWindow
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(370, 123);
            this.ControlBox = false;
            this.Controls.Add(this.btnCancel);
            this.Controls.Add(this.btnConfirm);
            this.Controls.Add(this.txtInput);
            this.Controls.Add(this.lblTitle);
            this.Font = new System.Drawing.Font("Tahoma", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "InputWindow";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Text = "InputWindow";
            this.ResumeLayout(false);
            this.PerformLayout();
        }
        #endregion
        private System.Windows.Forms.Label lblTitle;
        private System.Windows.Forms.TextBox txtInput;
        private System.Windows.Forms.Button btnConfirm;
        private System.Windows.Forms.Button btnCancel;
    }
}
src/Bro.UI.Model.Winform/UI/InputWindow.cs
New file
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Bro.UI.Model.Winform.UI
{
    public partial class InputWindow : Form
    {
        public InputWindow()
        {
            InitializeComponent();
        }
        public string Title
        {
            set => lblTitle.Text = value;
        }
        public string Input { get; set; }
        public InputWindow(string title)
        {
            InitializeComponent();
            Title = title;
        }
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
        }
        private void btnConfirm_Click(object sender, EventArgs e)
        {
            ConfirmInput();
        }
        private void ConfirmInput()
        {
            Input = txtInput.Text.Trim();
            if (string.IsNullOrWhiteSpace(Input))
            {
                MessageBox.Show("输入不能为空");
                return;
            }
            this.DialogResult = DialogResult.OK;
        }
        private void txtInput_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                ConfirmInput();
            }
        }
    }
}
src/Bro.UI.Model.Winform/UI/InputWindow.resx
New file
@@ -0,0 +1,120 @@
<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
    <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" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </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" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
</root>