diff --git a/BPA.WeimoCube.sln b/BPA.WeimoCube.sln index cbf975c..a8f7b83 100644 --- a/BPA.WeimoCube.sln +++ b/BPA.WeimoCube.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.9.34607.119 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPA.WeimoCube", "BPA.WeimoCube\BPA.WeimoCube.csproj", "{2BB3F0FF-6FBD-45EC-9111-DA96D58DDC72}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPA.WeimoCube", "BPA.WeimoCube\BPA.WeimoCube.csproj", "{2BB3F0FF-6FBD-45EC-9111-DA96D58DDC72}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommcationLibray", "CommcationLibray\CommcationLibray.csproj", "{19E2F031-486A-40C2-9EC5-9158F90F74FD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {2BB3F0FF-6FBD-45EC-9111-DA96D58DDC72}.Debug|Any CPU.Build.0 = Debug|Any CPU {2BB3F0FF-6FBD-45EC-9111-DA96D58DDC72}.Release|Any CPU.ActiveCfg = Release|Any CPU {2BB3F0FF-6FBD-45EC-9111-DA96D58DDC72}.Release|Any CPU.Build.0 = Release|Any CPU + {19E2F031-486A-40C2-9EC5-9158F90F74FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19E2F031-486A-40C2-9EC5-9158F90F74FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19E2F031-486A-40C2-9EC5-9158F90F74FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19E2F031-486A-40C2-9EC5-9158F90F74FD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BPA.WeimoCube/App.xaml b/BPA.WeimoCube/App.xaml index 624cd45..b08636f 100644 --- a/BPA.WeimoCube/App.xaml +++ b/BPA.WeimoCube/App.xaml @@ -2,8 +2,11 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:BPA.WeimoCube" - StartupUri="MainWindow.xaml"> - - - + xmlns:vm="clr-namespace:BPA.WeimoCube.ViewModels" + StartupUri="Views/MainWindow.xaml"> + + + + + diff --git a/BPA.WeimoCube/Assets/Fonts/digital_display.ttf b/BPA.WeimoCube/Assets/Fonts/digital_display.ttf new file mode 100644 index 0000000..a006032 Binary files /dev/null and b/BPA.WeimoCube/Assets/Fonts/digital_display.ttf differ diff --git a/BPA.WeimoCube/Assets/Fonts/iconfont.ttf b/BPA.WeimoCube/Assets/Fonts/iconfont.ttf new file mode 100644 index 0000000..eb3e545 Binary files /dev/null and b/BPA.WeimoCube/Assets/Fonts/iconfont.ttf differ diff --git a/BPA.WeimoCube/Assets/Images/logo.png b/BPA.WeimoCube/Assets/Images/logo.png new file mode 100644 index 0000000..ce78871 Binary files /dev/null and b/BPA.WeimoCube/Assets/Images/logo.png differ diff --git a/BPA.WeimoCube/Assets/Styles/ComboBoxStyles.xaml b/BPA.WeimoCube/Assets/Styles/ComboBoxStyles.xaml new file mode 100644 index 0000000..56ef060 --- /dev/null +++ b/BPA.WeimoCube/Assets/Styles/ComboBoxStyles.xaml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BPA.WeimoCube/BPA.WeimoCube.csproj b/BPA.WeimoCube/BPA.WeimoCube.csproj index 18b9a12..ca14e23 100644 --- a/BPA.WeimoCube/BPA.WeimoCube.csproj +++ b/BPA.WeimoCube/BPA.WeimoCube.csproj @@ -6,6 +6,30 @@ enable enable true + True + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BPA.WeimoCube/Common/Command.cs b/BPA.WeimoCube/Common/Command.cs new file mode 100644 index 0000000..1c0718b --- /dev/null +++ b/BPA.WeimoCube/Common/Command.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace BPA.WeimoCube.Common +{ + /// + /// 绑定事件 + /// + public class Command : ICommand + { + public event EventHandler? CanExecuteChanged; + + public bool CanExecute(object? parameter) + { + if (DoCanExecute == null) return true; + return DoCanExecute.Invoke(parameter); + } + + public void Execute(object? parameter) + { + DoExecute?.Invoke(parameter); + } + + public Action DoExecute { get; set; } + public Func DoCanExecute { get; set; } + + public Command(Action doExecute,Func doCanExecute) { + DoExecute=doExecute; + DoCanExecute=doCanExecute; + } + + public Command(Action doExecute) : this(doExecute, null) { } + } +} diff --git a/BPA.WeimoCube/Common/Config.cs b/BPA.WeimoCube/Common/Config.cs new file mode 100644 index 0000000..b6a075e --- /dev/null +++ b/BPA.WeimoCube/Common/Config.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Markup; + +namespace BPA.WeimoCube.Common +{ + /// + /// 配置ip和端口实体 + /// + public class Config + {/// + /// ip地址 + /// + public string ModbusTcpIP { get; set; } + /// + /// 端口号 + /// + public int ModbusTcpPort { get; set; } + /// + /// 文件保存路径 + /// + public string LogPath { get; set; } + /// + /// 读取数据长度 + /// + public ushort ReadDataLength { get; set; } + /// + /// 写入数据长度 + /// + public int WriteDataLength { get; set; } + /// + /// 配方编号地址 + /// + public string RecipeNumberAddress { get; set; } + + /// + /// 配方编号数据类型id + /// + public int RecipeDataID { get; set; } + /// + /// 配方编号数据格式Id + /// + public int DataFormulasID { get; set; } + /// + /// 显示订单编号地址 + /// + public string DisplayOrderNumberAddress { get; set; } + + /// + /// 显示订单编号数据类型ID + /// + public int OrderNumberTypeID { get; set; } + /// + /// 显示订单编号数据格式ID + /// + public int OrderNumberDataFormat { get; set; } + /// + /// 写入编号地址 + /// + public string WriteNumberAddress { get; set; } + /// + /// 启动配料地址 + /// + public string StartIngredientAddress { get; set; } + /// + /// 配料完成地址 + /// + public string IngredientCompletionAddress { get; set; } + /// + /// 设备状态地址 + /// + public string DeviceStatusAddress { get; set; } + /// + /// 信息错误地址 + /// + public string InformationErrorAddress { get; set; } + + } +} diff --git a/BPA.WeimoCube/Common/LogProvider.cs b/BPA.WeimoCube/Common/LogProvider.cs new file mode 100644 index 0000000..2657521 --- /dev/null +++ b/BPA.WeimoCube/Common/LogProvider.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.Common +{ + /// + /// 日志操作类 + /// + public class LogProvider + { + public string LogPath { get; set; } + private readonly object _lock = new object(); + + StringBuilder logStr = new StringBuilder(); + int count = 0; + + public LogProvider(string log_path) + { + LogPath = log_path; + } + + public void WriteLog( + string msg, + bool isRecord, + bool isError = false, + [CallerLineNumber] int line = 0, + [CallerMemberName] string methodName = "", + [CallerFilePath] string filePath = "") + { + if (!isRecord) return; + + WriteLog(new Log + { + Time = DateTime.Now, + LogType = isError ? LogType.ERROR : LogType.LOG, + Message = msg, + + ErrorFile = filePath, + ErroMethod = methodName, + ErrorLineNum = line, + }); + } + + private void WriteLog(Log log) + { + lock (_lock) + { + count++; + logStr.Append(log.ToString()); + + if (count >= 100) + { + SaveLog(); + + count = 0; + logStr.Clear(); + } + } + } + + public void Dispose() + { + SaveLog(); + } + + private void SaveLog() + { + string fileName = DateTime.Now.ToString("yyyyMMdd") + ".log"; + string filePath = Path.Combine(this.LogPath, fileName); + + // 清除3天前日志 + string delFile = DateTime.Now.AddDays(-3).ToString("yyyyMMdd") + ".log"; + string delFilePath = Path.Combine(this.LogPath, fileName); + if (File.Exists(delFilePath)) + File.Delete(delFilePath); + + File.AppendAllText(filePath, logStr.ToString()); + } + } + + internal class Log + { + public DateTime Time { get; set; } + public string Message { get; set; } + public LogType LogType { get; set; } + + public string ErrorFile { get; set; } + public string ErroMethod { get; set; } + public int ErrorLineNum { get; set; } + + public override string ToString() + { + if (this.LogType == LogType.LOG) + return $"{Time.ToString("yyyy-MM-dd HH:mm:ss")} [{LogType.ToString()}] {Message}\r\n"; + + if (this.LogType == LogType.ERROR) + return $"{Time.ToString("yyyy-MM-dd HH:mm:ss")} [{LogType.ToString()}] {Message}\r\n" + + $"\t异常文件:{ErrorFile}\r\n" + + $"\t异常位置:{ErroMethod} [Line:{ErrorLineNum}]\r\n"; + + return base.ToString(); + } + } + + internal enum LogType + { + LOG, ERROR + } +} diff --git a/BPA.WeimoCube/Common/MessageShow.cs b/BPA.WeimoCube/Common/MessageShow.cs new file mode 100644 index 0000000..c67c6cb --- /dev/null +++ b/BPA.WeimoCube/Common/MessageShow.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace BPA.WeimoCube.Common +{ + /// + /// 公共消息弹窗类 + /// + public class MessageShow + { + public static void GetMessage(string mes) + { + MessageBox.Show(mes); + } + } +} diff --git a/BPA.WeimoCube/Common/NotifyBase.cs b/BPA.WeimoCube/Common/NotifyBase.cs new file mode 100644 index 0000000..af6a7d8 --- /dev/null +++ b/BPA.WeimoCube/Common/NotifyBase.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.Common +{ + /// + /// 双向绑定 + /// + public class NotifyBase : INotifyPropertyChanged + { + public event PropertyChangedEventHandler? PropertyChanged; + + public void RaisePropertyChanged(string propName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); + } + + #region 属性设置 + public void Set(ref T field, T value, [CallerMemberName] string propName = "") + { + if (!field.Equals(value)) + { + field = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); + } + } + #endregion + } +} diff --git a/BPA.WeimoCube/Common/PanDuanGongJ.cs b/BPA.WeimoCube/Common/PanDuanGongJ.cs new file mode 100644 index 0000000..eb376ea --- /dev/null +++ b/BPA.WeimoCube/Common/PanDuanGongJ.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; + +namespace BPA.WeimoCube.Common +{ + /// + /// 判断工具类 + /// + public class PanDuanGongJ + { + /// + /// 判断端口号是否正确 + /// + /// + /// + public static bool IsIPPort(string port) + { + + bool isPort = false; + int portNum; + //将字符串转化为整数 + isPort = Int32.TryParse(port, out portNum); + + if (isPort && portNum >= 0 && portNum <= 65535) + { + isPort = true; + } + else + { + isPort = false; + } + return isPort; + } + + /// + /// 判断ip是否合法 + /// + /// + public static bool IsIPGf(string IP) + { + bool isIp = false; + string regexStrIPV4 = (@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"); + if (Regex.IsMatch(IP, regexStrIPV4) && IP != "0.0.0.0") + { + isIp=true; + } + else + { + isIp=false; + } + return isIp; + } + } +} diff --git a/BPA.WeimoCube/CommunicationClassLibrary/CommunicationLibrary.cs b/BPA.WeimoCube/CommunicationClassLibrary/CommunicationLibrary.cs new file mode 100644 index 0000000..6b2441e --- /dev/null +++ b/BPA.WeimoCube/CommunicationClassLibrary/CommunicationLibrary.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.CommunicationClassLibrary +{ + //通讯基类 + class CommunicationLibrary + { + } +} diff --git a/BPA.WeimoCube/MainWindow.xaml b/BPA.WeimoCube/MainWindow.xaml deleted file mode 100644 index 5adea80..0000000 --- a/BPA.WeimoCube/MainWindow.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/BPA.WeimoCube/MainWindow.xaml.cs b/BPA.WeimoCube/MainWindow.xaml.cs deleted file mode 100644 index 3446db0..0000000 --- a/BPA.WeimoCube/MainWindow.xaml.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text; -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 BPA.WeimoCube -{ - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window - { - public MainWindow() - { - InitializeComponent(); - } - } -} \ No newline at end of file diff --git a/BPA.WeimoCube/Model/FormulaAttList.cs b/BPA.WeimoCube/Model/FormulaAttList.cs new file mode 100644 index 0000000..f9937dc --- /dev/null +++ b/BPA.WeimoCube/Model/FormulaAttList.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.Model +{ + /// + /// 配方集合 + /// + public class FormulaAttList + { + public List FormulaList { get; set; }=new List(); + } +} diff --git a/BPA.WeimoCube/Model/FormulaAttachment.cs b/BPA.WeimoCube/Model/FormulaAttachment.cs new file mode 100644 index 0000000..7c0c089 --- /dev/null +++ b/BPA.WeimoCube/Model/FormulaAttachment.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace BPA.WeimoCube.Model +{ + /// + /// 配方附件 + /// + public class FormulaAttachment + { + /// + /// 配方编号 属性 + /// + public string FormulaNumber { get; set; } + /// + /// 配方名称 + /// + public string FormulaName { get; set; } + /// + /// 备用 + /// + public string spare { get; set; } + + /// + /// 序号 + /// + public int SerialNumber { get; set; } + } +} diff --git a/BPA.WeimoCube/Model/MainWModel.cs b/BPA.WeimoCube/Model/MainWModel.cs new file mode 100644 index 0000000..e92d2c4 --- /dev/null +++ b/BPA.WeimoCube/Model/MainWModel.cs @@ -0,0 +1,353 @@ +using GalaSoft.MvvmLight; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.Model +{ + /// + /// 主窗口实体模型 + /// + public class MainWModel : ObservableObject + { + public event PropertyChangedEventHandler? PropertyChanged; + private string _ip; + /// + /// ip地址 + /// + public string Ip + { + get { return _ip; } + set + { + Set(ref _ip, value); + } + } + private string _port; + /// + /// 端口 + /// + public string Port + { + get { return _port; } + set { Set(ref _port, value); } + } + + private string _RecipeNumberAddress; + /// + /// 配方编号地址 + /// + public string RecipeNumberAddress { get { return _RecipeNumberAddress; } set { Set(ref _RecipeNumberAddress, value); } } + + private string _DisplayOrderNumberAddress; + /// + /// 显示订单编号地址 + /// + public string DisplayOrderNumberAddress { get { return _DisplayOrderNumberAddress; } set { Set(ref _DisplayOrderNumberAddress, value); } } + + private string _WriteNumberAddress; + /// + /// 写入编号地址 + /// + public string WriteNumberAddress { get { return _WriteNumberAddress; } set { Set(ref _WriteNumberAddress, value); } } + + private string _StartIngredientAddress; + /// + /// 启动配料地址 + /// + public string StartIngredientAddress { get { return _StartIngredientAddress; } set { Set(ref _StartIngredientAddress, value); } } + + private string _IngredientCompletionAddress; + /// + /// 配料完成地址 + /// + public string IngredientCompletionAddress { get { return _IngredientCompletionAddress; } set { Set(ref _IngredientCompletionAddress, value); } } + + private string _DeviceStatusAddress; + /// + /// 设备状态地址 + /// + public string DeviceStatusAddress { get { return _DeviceStatusAddress; } set { Set(ref _DeviceStatusAddress, value); } } + + private string _InformationErrorAddress; + /// + /// 信息错误地址 + /// + public string InformationErrorAddress { get { return _InformationErrorAddress; } set { Set(ref _InformationErrorAddress, value); } } + + + + private bool _TCPCRWIsEnabled = true; + /// + /// 连接ModbusTcp是否启用 + /// + public bool TCPCRWIsEnabled + { + get { return _TCPCRWIsEnabled; } + set { Set(ref _TCPCRWIsEnabled, value); } + } + + private bool _TCPDRWIsEnabled = false; + /// + /// 断开连接按钮是否启用 + /// + public bool TCPDRWIsEnabled + { + get { return _TCPDRWIsEnabled; } + set { Set(ref _TCPDRWIsEnabled, value); } + } + + + private bool _isStart =true; + /// + /// 是否监控 + /// + public bool IsStart + { + get { return _isStart; } + set + { + Set(ref _isStart, value); + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsStart")); + if (!value) + { + this.ShowMessage("监控未开始,请打开监控开关",false); + this.ConnectionStatus = value; + } + + } + } + + private bool _ConnectionStatus; + /// + /// 连接状态 + /// + public bool ConnectionStatus + { + get { return _ConnectionStatus; } + set { Set(ref _ConnectionStatus, value); } + } + + private int _WriteDataLength; + /// + /// 写入数据长度 + /// + public int WriteDataLength + { + get { return _WriteDataLength; } + set {Set(ref _WriteDataLength , value); } + } + + private ushort _ReadDataLength; + /// + /// 读取数据长度 + /// + public ushort ReadDataLength + { + get { return _ReadDataLength; } + set {Set(ref _ReadDataLength , value); } + } + + + + private object _CurrentOrderNumber; + /// + /// 当前订单编号 + /// 可以用于显示当前的订单编号 + /// + public object CurrentOrderNumber + { + get { return _CurrentOrderNumber; } + set { Set(ref _CurrentOrderNumber, value); } + } + + + private object _FormulaNumber ; + /// + /// 配方编号 + /// 需要调用的配方编号(编号来源见附件) + /// + public object FormulaNumber + { + get { return _FormulaNumber; } + set { Set(ref _FormulaNumber, value); } + } + + private bool _DetermineWriteNumber; + /// + /// 确定写入编号 + /// 确认配方数据,并下发到配料机 + /// + public bool DetermineWriteNumber + { + get { return _DetermineWriteNumber; } + set { Set(ref _DetermineWriteNumber, value); } + } + + private bool _StartingIngredients; + /// + /// 启动配料 + /// 根据当前选择配方启动配料(当前模式不需要使用该功能,预留) + /// + public bool StartingIngredients + { + get { return _StartingIngredients; } + set { Set(ref _StartingIngredients, value); } + } + + private bool _IngredientsCompleted; + /// + /// 配料完成 + /// 启动配料后,待动作完成该值为True,再次执行配料请求为False + /// + public bool IngredientsCompleted + { + get { return _IngredientsCompleted; } + set { Set(ref _IngredientsCompleted, value); } + } + + private bool _DeviceStatus; + /// + /// 设备状态 + /// 上电为False,推送了订单为True + /// + public bool DeviceStatus + { + get { return _DeviceStatus; } + set { Set(ref _DeviceStatus, value); } + } + + private string _TopDianState; + /// + /// 设备上电状态显示 + /// + public string TopDianState + { + get { return _TopDianState; } + set { Set(ref _TopDianState, value); } + } + + private string _OrderPushState; + /// + /// 订单推送状态显示 + /// + public string OrderPushState + { + get { return _OrderPushState; } + set { Set(ref _OrderPushState, value); } + } + + private bool _InformationError; + /// + /// 信息错误 + /// 点击了取消配料,该标志位为True.上位机收到信息后主动置False + /// + public bool InformationError + { + get { return _InformationError; } + set { Set(ref _InformationError, value); } + } + + + private bool _isLog; + /// + /// 打开日志 + /// + public bool IsLog + { + get { return _isLog; } + set + { + Set(ref _isLog, value); + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsLog")); + } + } + + private int _blurRadius = 0; + /// + /// 主界面的 模糊半径 + /// + public int BlurRadius + { + get { return _blurRadius; } + set + { + + Set(ref _blurRadius, value); + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("BlurRadius")); + } + } + + private DateTime _currentDate; + /// + /// 当前时间 + /// + public DateTime CurrentDate + { + get { return _currentDate; } + set + { + //_currentDate = value; + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentDate")); + Set(ref _currentDate, value); + + } + } + + + private string _message; + /// + /// 错误信息 + /// + public string Message + { + get { return _message; } + set + { + //_message = value; + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Message")); + Set(ref _message, value); + + } + } + private string _msgColor = "#90EE90"; + /// + /// 错误信息颜色 + /// + public string MsgColor + { + get { return _msgColor; } + set + { + //_msgColor = value; + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MsgColor")); + Set(ref _msgColor, value); + + } + } + + private string _logPath; + /// + /// 保存日志路径 + /// + public string LogPath + { + get { return _logPath; } + set + { + Set(ref _logPath, value); + //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LogPath")); + } + } + + public void ShowMessage(string message, bool state = true) + { + this.Message = message; + this.MsgColor = state ? "#90EE90" : "#FF4500"; + } + + } +} diff --git a/BPA.WeimoCube/Model/RecipeNumberDataType.cs b/BPA.WeimoCube/Model/RecipeNumberDataType.cs new file mode 100644 index 0000000..6ea145d --- /dev/null +++ b/BPA.WeimoCube/Model/RecipeNumberDataType.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.Model +{ + /// + /// 配方编号数据类型 下拉框实体 + /// + public class RecipeNumberDataType + { + /// + /// id + /// + public int ID { get; set; } + /// + /// 数据类型名称显示 + /// + public string DataName { get; set; } + } + + /// + /// 数据格式 下拉框实体 + /// + public class FormulaNumberDataFormat + { + /// + /// id + /// + public int FormatID { get; set; } + /// + /// 数据格式名称显示 + /// + public string DataFormatName { get; set; } + } + + + public enum DirectionType : int + { + Byte = 0, + Int = 1, + Uint = 2, + Short = 3, + Ushort = 4, + Float = 5, + String = 6, + Bool = 7, + Double=8, + } + +} diff --git a/BPA.WeimoCube/ViewModels/MainWindowViewModel.cs b/BPA.WeimoCube/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..b963a7a --- /dev/null +++ b/BPA.WeimoCube/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,854 @@ +using BPA.Helper; +using BPA.WeimoCube.Common; +using BPA.WeimoCube.Model; +using CommcationLibray; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using Microsoft.Win32; +using S7.Net.Types; +using SharpCompress.Common; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.IO.Ports; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using ThingsGateway.Foundation.Core; +using ThingsGateway.Foundation.Extension; + +namespace BPA.WeimoCube.ViewModels +{ + /// + /// 主实体视图模型 + /// + public class MainWindowViewModel : ObservableObject + { + #region 属性 + //配方附件 + public ObservableCollection formulaAttachment { get; set; } = new ObservableCollection(); + /// + /// 数据类型 + /// + public ObservableCollection dataTypes { get; set; } = new ObservableCollection(); + /// + /// 数据格式 + /// + public ObservableCollection formulas { get; set; } = new ObservableCollection(); + + private List tasks = new List(); + private CancellationTokenSource cts = new CancellationTokenSource(); + private ModbusTCP modbus = new ModbusTCP(); + /// + /// 实例主窗口实体类 + /// + public MainWModel MainWModel { get; set; } = new MainWModel(); + /// + /// 日志操作类 + /// + private LogProvider LogProvider; + + /// + /// 连接ModbusTcp 事件 + /// + public RelayCommand ConnectMTCPCommand { get; set; } + /// + /// 定义设置事件 + /// + public RelayCommand ConfigCommand { get; set; } + /// + /// 定义关闭设置配置事件 + /// + public RelayCommand ConfigCloseCommand { get; set; } + /// + /// 定义开打文件夹事件 + /// + public RelayCommand LogPathSelectCommand { get; set; } + /// + /// 打开日志事件 + /// + public RelayCommand OpenLogPathCommand { get; set; } + /// + /// 定义写入编号事件 + /// + public RelayCommand WriteNumberCommand { get; set; } + /// + /// 定义确定写入编号事件 + /// + public RelayCommand DetermineWriteNumberCommand { get; set; } + /// + /// 定义启动配料事件 + /// + public RelayCommand StartingIngredientsCommand { get; set; } + /// + /// 定义打开配料附件事件 + /// + public RelayCommand OpenIngredientAttachmentCommand { get; set; } + /// + /// 附件列表行点击事件 + /// + public RelayCommand DoubleClickCommand { get; set; } + /// + /// 定义退出事件 + /// + public RelayCommand CloseCommand { get; set; } + + /// + /// 订单推送 标志位 + /// 0表示已推送 + /// 1表示已完成 + /// + private int OrderPushStatus = 0; + /// + /// 确定写入编号的记录 ,如果当前订单还没操作 不能进行第二次写入 + /// + private bool DetermineWriteStatus = false; + /// + /// 设备状态 为false 可以继续派发下一个订单 + /// + private bool DeviceStatus; + /// + /// 是否取消订单 + /// + private bool WhetherCancel; + + private RecipeNumberDataType _dataType; + /// + /// 数据类型下拉值初始显示 + /// + public RecipeNumberDataType DataType + { + get => _dataType; + set { Set(ref _dataType, value); } + } + + private FormulaNumberDataFormat _dataFormulas; + /// + /// 数据格式下拉值初始显示 + /// + public FormulaNumberDataFormat DataFormulas + { + get { return _dataFormulas; } + set { Set(ref _dataFormulas, value); } + } + + private RecipeNumberDataType _OrderNumberType; + /// + /// 数据类型下拉值初始显示 + /// + public RecipeNumberDataType OrderNumberType + { + get => _OrderNumberType; + set { Set(ref _OrderNumberType, value); } + } + + private FormulaNumberDataFormat _OrderNumberData; + /// + /// 数据格式下拉值初始显示 + /// + public FormulaNumberDataFormat OrderNumberData + { + get { return _OrderNumberData; } + set { Set(ref _OrderNumberData, value); } + } + + + #endregion + + public MainWindowViewModel() + { + var task = Task.Run(async () => + { + while (!cts.IsCancellationRequested) + { + MainWModel.CurrentDate = System.DateTime.Now; + await Task.Delay(new TimeSpan(1, 0, 0)); + } + }, cts.Token); + tasks.Add(task); + LogProvider = new LogProvider(MainWModel.LogPath); + + this.RaisePropertyChanged("MainWModel"); + ConnectMTCPCommand = new RelayCommand(new Action(DoConnectModbusTcpCommand)); + ConfigCommand = new RelayCommand(new Action(Config)); + ConfigCloseCommand = new RelayCommand(new Action(ConfigClose)); + LogPathSelectCommand = new RelayCommand(new Action(LogPathSelect)); + OpenLogPathCommand = new RelayCommand(new Action(OpenLogFolder)); + WriteNumberCommand = new RelayCommand(new Action(WriteNumber)); + + DetermineWriteNumberCommand = new RelayCommand(new Action(DetermineWriteNumber)); + StartingIngredientsCommand = new RelayCommand(new Action(StartingIngredients)); + OpenIngredientAttachmentCommand = new RelayCommand(new Action(OpenIngredientAttachment)); + + DoubleClickCommand = new RelayCommand(param => RowClick(param), param => true); + + CloseCommand = new RelayCommand(new Action(Close)); + + this.SetRecipeNumberTypeData(); + this.SetFormulaNumberDataFormat(); + this.ChuShiHuaConfigData(); + this.GetFormulaData(); + this.StartMointor(); + //MainWModel.IsStart = true; + } + /// + /// 附件列表行点击事件 + /// + /// + private void RowClick(object parameter) + { + var selectedItem = (FormulaAttachment)parameter; + try + { + MainWModel.FormulaNumber = (short)Convert.ToInt32(selectedItem.FormulaNumber); + } + catch (Exception ex) + { + MessageError($"配方编号类型转换失败!!! 失败信息:{ex.Message} + {selectedItem.ToString()}"); + } + + } + + /// + /// 初始化配置文件数据 + /// + private void ChuShiHuaConfigData() + { + // 配置数据的初始化 + try + { + string json = File.ReadAllText("config.json"); + Config config = System.Text.Json.JsonSerializer.Deserialize(json); + MainWModel.Ip = config.ModbusTcpIP; + MainWModel.Port = config.ModbusTcpPort.ToString(); + MainWModel.LogPath = config.LogPath; + + MainWModel.RecipeNumberAddress = config.RecipeNumberAddress; + MainWModel.DisplayOrderNumberAddress = config.DisplayOrderNumberAddress; + MainWModel.WriteNumberAddress = config.WriteNumberAddress; + MainWModel.StartIngredientAddress = config.StartIngredientAddress; + MainWModel.IngredientCompletionAddress = config.IngredientCompletionAddress; + MainWModel.DeviceStatusAddress = config.DeviceStatusAddress; + MainWModel.InformationErrorAddress = config.InformationErrorAddress; + + MainWModel.ReadDataLength = config.ReadDataLength; + MainWModel.WriteDataLength = config.WriteDataLength; + + DataType = dataTypes.First(m => m.ID == config.RecipeDataID);//绑定到下拉框显示的值 + DataFormulas = formulas.First(m => m.FormatID == config.DataFormulasID); + + OrderNumberType = dataTypes.First(m => m.ID == config.OrderNumberTypeID);//绑定到下拉框显示的值 + OrderNumberData = formulas.First(m => m.FormatID == config.OrderNumberDataFormat); + } + catch (Exception ex) + { + MainWModel.ShowMessage("初始化参数加载失败," + ex.Message, false); + //return; + } + } + + /// + /// 初始数据类型 + /// + private void SetRecipeNumberTypeData() + { + dataTypes.Clear(); + int i = 0; + foreach (DirectionType type in Enum.GetValues(typeof(DirectionType))) + { + dataTypes.Add(new RecipeNumberDataType + { + ID = i, + DataName = type.ToString() + }); + i++; + } + } + + /// + /// 初始数据格式 + /// + private void SetFormulaNumberDataFormat() + { + formulas.Clear(); + int i = 0; + foreach (BPADataFormat item in Enum.GetValues(typeof(BPADataFormat))) + { + formulas.Add(new FormulaNumberDataFormat + { + FormatID = i, + DataFormatName = item.ToString() + }); + i++; + } + } + + /// + /// 初始化配方数据 + /// + private void GetFormulaData() + { + try + { + formulaAttachment.Clear();//先清除集合 + string jsons = File.ReadAllText("Formula.json"); + FormulaAttList configs = System.Text.Json.JsonSerializer.Deserialize(jsons); + configs.FormulaList.ForEach(s => + { + formulaAttachment.Add(new FormulaAttachment + { + FormulaName = s.FormulaName, + FormulaNumber = s.FormulaNumber, + SerialNumber = s.SerialNumber, + spare = s.spare, + }); + }); + } + catch (Exception ex) + { + + MainWModel.ShowMessage("初始化配方数据加载失败," + ex.Message, false); + } + + } + + /// + /// 打开配料附件配置文件 + /// + /// + private void OpenIngredientAttachment(object text) + { + //D:\黑波罗科技\BPA.WeimoCube\BPA.WeimoCube\bin\Debug\net6.0-windows + string PeiLaoPath = System.IO.Directory.GetCurrentDirectory(); + if (Directory.Exists(PeiLaoPath)) + { + Process.Start("explorer.exe", PeiLaoPath); + } + } + + /// + /// 打开日志文件 + /// + private void OpenLogFolder(object text) + { + if (Directory.Exists(MainWModel.LogPath)) + { + Process.Start("explorer.exe", MainWModel.LogPath); + } + } + + /// + /// 打开文件夹 + /// + /// + private void LogPathSelect(object text) + { + OpenFileDialog openFileDialog = new OpenFileDialog(); + //过滤文件类型 + //openFileDialog.Filter = "文档(*.txt)|*.txt|所有文件(*.*)|*.*"; + //允许多选 + openFileDialog.Multiselect = true; + if (openFileDialog.ShowDialog() == true) + { + string paths = Path.GetDirectoryName(openFileDialog.FileName); + //FileName 完整路径:相对路径+文件名+后缀 + //文件内容读取 + MainWModel.LogPath = paths; + LogProvider.LogPath = MainWModel.LogPath; + //string[] names = openFileDialog.FileNames; + } + + } + + /// + /// 点击设置 + /// + /// + private void Config(object text) + { + //MainWModel.IsStart = false; + MainWModel.BlurRadius = 10; + } + /// + /// 隐藏设置界面 + /// + private void ConfigClose(object text) + { + MainWModel.BlurRadius = 0; + + // 数据保存的动作 + try + { + Config config = new Config(); + config.ModbusTcpIP = MainWModel.Ip; + config.ModbusTcpPort = Convert.ToInt32(MainWModel.Port); + config.LogPath = MainWModel.LogPath; + config.RecipeNumberAddress = MainWModel.RecipeNumberAddress; + config.DisplayOrderNumberAddress = MainWModel.DisplayOrderNumberAddress; + config.WriteNumberAddress = MainWModel.WriteNumberAddress; + config.StartIngredientAddress = MainWModel.StartIngredientAddress; + config.IngredientCompletionAddress = MainWModel.IngredientCompletionAddress; + config.DeviceStatusAddress = MainWModel.DeviceStatusAddress; + config.InformationErrorAddress = MainWModel.InformationErrorAddress; + config.RecipeDataID = DataType.ID; + config.DataFormulasID = DataFormulas.FormatID; + config.OrderNumberTypeID = OrderNumberType.ID; + config.OrderNumberDataFormat = OrderNumberData.FormatID; + + config.ReadDataLength = MainWModel.ReadDataLength; + config.WriteDataLength= MainWModel.WriteDataLength; + // Framework Nuget:安装 Newtonsoft.Json 库,参照472版本的程序 + var json = System.Text.Json.JsonSerializer.Serialize(config); + File.WriteAllText("config.json", json); + + LogProvider.WriteLog("配置文件修改完成", MainWModel.IsLog); + } + catch (Exception ex) + { + LogProvider.WriteLog("写配置文件失败!" + ex.Message, MainWModel.IsLog, isError: true); + MainWModel.ShowMessage("写配置文件失败!" + ex.Message, false); + } + + } + + /// + /// 实现 连接modbusTcp 按钮事件 + /// + /// + private void DoConnectModbusTcpCommand(object text) + { + + //if (TiJiaoPanDuan()) + //{ + // modbus.ConnectModbusTcp(MainWModel.Ip, Convert.ToInt32(MainWModel.Port)); + // MainWModel.TCPDRWIsEnabled = true; + //} + } + + /// + /// 开启监听 + /// + private void StartMointor() + { + + bool connctionSoss = false; + var task = Task.Factory.StartNew(async () => + { + while (!cts.IsCancellationRequested) + { + //Debug.WriteLine("开启监听"); + var state = new CommcationLibray.Result(); + await Task.Delay(400); + if (!MainWModel.IsStart) continue; + if (MainWModel.ConnectionStatus) continue; + if (TiJiaoPanDuan()) + { + try + { + if (!connctionSoss) + MainWModel.ShowMessage("连接中......."); + + Application.Current.Dispatcher.Invoke(new Action(async () => + { + state = await modbus.ConnectModbusTcp(MainWModel.Ip, Convert.ToInt32(MainWModel.Port)); + }), System.Windows.Threading.DispatcherPriority.SystemIdle, null); + + + await Task.Delay(500); + + if (!state.State) + { + MainWModel.ShowMessage("连接失败", false); + MainWModel.ConnectionStatus = state.State; + connctionSoss = false; + } + else + { + connctionSoss = true; + MainWModel.ConnectionStatus = state.State; + MainWModel.ShowMessage("连接成功"); + this.GetInformationError(); + this.GetDeviceStatus(); + } + + } + catch (Exception ex) + { + MessageError($"连接失败!!! 失败信息:{ex.Message}"); + } + } + } + }, cts.Token); + tasks.Add(task); + } + + + /// + /// 点击了取消配料,该标志位为True.上位机收到信息后主动置False + /// + private void GetInformationError() + { + var task = Task.Factory.StartNew(async () => + { + while (!cts.IsCancellationRequested) + { + await Task.Delay(400); + try + { + if (!IsState()) return; + var Result = new CommcationLibray.Result(); + Result = modbus.ReadCancelIngredients(MainWModel.InformationErrorAddress); + if (!Result.State) + { + MessageError($"获取取消配料数据失败!!! 失败信息:{Result.Exception}"); + } + else + { + //为1说明点击了取消配料 + if ((bool)Result.Datas) + { + this.WhetherCancel = true; + this.WriteInformationError(); + MainWModel.OrderPushState = $"订单->{MainWModel.CurrentOrderNumber}已取消!"; + MessageBox.Show($"当前订单-> {MainWModel.CurrentOrderNumber} 已取消!"); + } + } + } + catch (Exception ex) + { + MessageError($"获取取消配料数据失败!!! 失败信息:{ex.Message}"); + } + } + }, cts.Token); + tasks.Add(task); + } + + /// + /// 循环获取设备状态 + /// + private void GetDeviceStatus() + { + var task = Task.Factory.StartNew(async () => + { + while (!cts.IsCancellationRequested) + { + await Task.Delay(400); + try + { + if (!IsState()) return; + var Result = new CommcationLibray.Result(); + Result = modbus.ReadDeviceStatus(MainWModel.DeviceStatusAddress); + if (!Result.State) + { + MessageError($"获取设备状态数据失败!!! 失败信息:{Result.Exception}"); + } + else + { + this.DeviceStatus = (bool)Result.Datas; + this.StateFanKui((bool)Result.Datas); + } + } + catch (Exception ex) + { + MessageError($"获取设备状态数据失败!!! 失败信息:{ex.Message}"); + } + } + }, cts.Token); + tasks.Add(task); + } + + + /// + /// 点击取消配料时 上位机自动触发 设置值为false + /// + private void WriteInformationError() + { + if (!IsState()) return; + var Result = new CommcationLibray.Result(); + Result = modbus.WriteCancelIngredients(MainWModel.InformationErrorAddress, false); + if (!Result.State) + { + MessageError($"写入读取配料状态失败!!! 失败信息:{Result.Exception}"); + } + } + + + /// + /// 封装读取操作 + /// + /// + private void ReadCaoZuo() + { + try + { + switch (OrderNumberType.ID) + { + case 0: + ReadOrders(); + break; + case 1: + ReadOrders(); + break; + case 2: + ReadOrders(); + break; + case 3: + ReadOrders(); + break; + case 4: + ReadOrders(); + break; + case 5: + ReadOrders(); + break; + case 6: + ReadOrders(); + break; + case 7: + ReadOrders(); + break; + case 8: + ReadOrders(); + break; + } + } + catch (Exception ex) + { + MessageError($"数据转换失败!!! 失败信息:{ex.Message}"); + } + } + + /// + /// 读取订单 + /// + private void ReadOrders() + { + var Result = new CommcationLibray.Result(); + Result = modbus.GetOrders(MainWModel.DisplayOrderNumberAddress,MainWModel.ReadDataLength, (BPADataFormat)OrderNumberData.FormatID );//BPADataFormat.CDAB + if (!Result.State) + { + MessageError($"读取订单失败!!! 失败信息:{Result.Exception}"); + } + else + { + MainWModel.ShowMessage("读取订单成功"); + MainWModel.CurrentOrderNumber = Result.Datas ; + } + + } + + /// + /// 写入编号 + /// + /// + private void WriteNumber(object test) + { + WriteCaoZuo(0); + + } + /// + /// 确定写入编号 + /// + /// + private void DetermineWriteNumber(object test) + { + WriteCaoZuo(1); + } + + /// + /// 封装写入操作 + /// + /// 0 表示写入 ,1表示确定写入 + private void WriteCaoZuo(int type) + { + try + { + if (MainWModel.FormulaNumber == null) + { + MessageError($"请输入配方编号!!!"); + return; + } + switch (DataType.ID) + { + case 0: + WriteCaoZuoDataType(type, Convert.ToByte(MainWModel.FormulaNumber)); + break; + case 1: + WriteCaoZuoDataType(type, Convert.ToInt32(MainWModel.FormulaNumber)); + break; + case 2: + WriteCaoZuoDataType(type, Convert.ToUInt32(MainWModel.FormulaNumber)); + break; + case 3: + WriteCaoZuoDataType(type, (short)Convert.ToInt32(MainWModel.FormulaNumber)); + break; + case 4: + WriteCaoZuoDataType(type, (ushort)Convert.ToInt32(MainWModel.FormulaNumber)); + break; + case 5: + WriteCaoZuoDataType(type, (float)Convert.ToDouble(MainWModel.FormulaNumber)); + break; + case 6: + WriteCaoZuoDataType(type, Convert.ToString(MainWModel.FormulaNumber)); + break; + case 7: + WriteCaoZuoDataType(type, Convert.ToBoolean(Convert.ToInt32(MainWModel.FormulaNumber))); + break; + case 8: + WriteCaoZuoDataType(type, Convert.ToDouble(MainWModel.FormulaNumber)); + break; + } + } + catch (Exception ex) + { + MessageError($"数据转换失败!!! 失败信息:{ex.Message}"); + } + } + + + private void WriteCaoZuoDataType(int type, T values) + { + if (!IsState()) return; + if (!this.DetermineWriteStatus && !this.DeviceStatus) + { + BPADataFormat bPAData = (BPADataFormat)DataFormulas.FormatID; + var Result = new CommcationLibray.Result(); + string error = type == 0 ? "写入" : "确定写入"; + Result = type == 0 ? modbus.WriteRecipeNumber(MainWModel.RecipeNumberAddress, values, MainWModel.WriteDataLength, (BPADataFormat)DataFormulas.FormatID) + : modbus.DetermineWriteNumberCommand(MainWModel.WriteNumberAddress, true); + if (!Result.State) + { + MessageError($"{error}编号失败!!! 失败信息:{Result.Exception}"); + } + else + { + MainWModel.ShowMessage($"{error}编号成功"); + if (type == 0) + this.ReadCaoZuo(); + else + { + this.DetermineWriteStatus = true; + } + } + } + else + { + MessageBox.Show("请等待上次订单完成后再操作!!!"); + } + } + + /// + /// 启动配料 + /// + /// + private void StartingIngredients(object test) + { + + } + + private void StateFanKui(bool state) + { + switch (state) + { + case false: + MainWModel.TopDianState = "空闲中......"; + if (this.DetermineWriteStatus && !this.WhetherCancel) + { + MainWModel.OrderPushState = "已完成"; + } + this.DetermineWriteStatus = false; + this.WhetherCancel = false; + break; + case true: + MainWModel.OrderPushState = "已推送"; + if (this.DetermineWriteStatus) + { + MainWModel.TopDianState = "待操作"; + } + break; + default: + break; + } + } + + /// + /// 错误信息 + /// + /// + private void MessageError(string error) + { + MainWModel.ShowMessage(error, false); + LogProvider.WriteLog(error, MainWModel.IsLog, isError: true); + } + + private bool TiJiaoPanDuan() + { + if (string.IsNullOrEmpty(MainWModel.Ip)) + { + MainWModel.ShowMessage("请输入IP地址!!!", false); + return false; + } + if (string.IsNullOrEmpty(MainWModel.Port)) + { + MainWModel.ShowMessage("请输入端口号!!!", false); + + return false; + } + if (!PanDuanGongJ.IsIPGf(MainWModel.Ip)) + { + MainWModel.ShowMessage("请输入合法的IP地址!!!", false); + + return false; + } + if (!PanDuanGongJ.IsIPPort(MainWModel.Port)) + { + MainWModel.ShowMessage("请输入正确的端口号!!!", false); + + return false; + } + return true; + } + + /// + /// 判断是否打开监听 + /// + /// + private bool IsState() + { + if (!MainWModel.IsStart || !MainWModel.ConnectionStatus) + { + MainWModel.ShowMessage("未连接状态!!!", false); + return false; + } + else + { + return true; + } + } + /// + /// 退出 + /// + /// + private void Close(object text) + { + CancelAllTasksAsync(); + } + + public void CancelAllTasksAsync() + { + cts?.Cancel(); + } + } +} + + + diff --git a/BPA.WeimoCube/ViewModels/ViewModelLocator.cs b/BPA.WeimoCube/ViewModels/ViewModelLocator.cs new file mode 100644 index 0000000..f08b118 --- /dev/null +++ b/BPA.WeimoCube/ViewModels/ViewModelLocator.cs @@ -0,0 +1,26 @@ +using CommonServiceLocator; +using GalaSoft.MvvmLight.Ioc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.WeimoCube.ViewModels +{ + public class ViewModelLocator + { + public ViewModelLocator() + { + // 容器的初始化 + ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); + + // 注册主窗体视图模型 + SimpleIoc.Default.Register(); + + } + + public MainWindowViewModel MainViewModel { get => ServiceLocator.Current.GetInstance(); } + + } +} diff --git a/BPA.WeimoCube/Views/MainWindow.xaml b/BPA.WeimoCube/Views/MainWindow.xaml new file mode 100644 index 0000000..f0e679c --- /dev/null +++ b/BPA.WeimoCube/Views/MainWindow.xaml @@ -0,0 +1,984 @@ + + + + + + + + + + + + ../Assets/Fonts/#iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +