using Cowain.Bake.BLL; using Cowain.Bake.Common; using Cowain.Bake.Common.Core; using Cowain.Bake.Common.Enums; using Cowain.Bake.Common.Interface; using Cowain.Bake.Common.Models; using Cowain.Bake.Communication.Interface; using Cowain.Bake.Main.Common; using Cowain.Bake.Main.Models; using Cowain.Bake.Main.Station; using Cowain.Bake.Main.Views; using Cowain.Bake.Model; using Cowain.Bake.Model.Models; using Prism.Commands; using Prism.Events; using Prism.Mvvm; using Prism.Regions; using Prism.Services.Dialogs; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Effects; using System.Windows.Shapes; using Unity; using JSON = Newtonsoft.Json.JsonConvert; namespace Cowain.Bake.Main.ViewModels { public partial class EquipmentMonitorViewModel : BindableBase { readonly IUnityContainer _unityContainer; IRegionManager _regionManager; public Canvas mainCanvas; public Canvas pathCanvas; public EAgvMoveStatus? lastAgvStatus = null ; readonly CmdFactories cmdFactories; public FrameworkElement frameworkElement; public TranslateTransform machineAnimation; readonly Dictionary contextMenuDic = new Dictionary(); private readonly Dictionary buttonDic = new Dictionary(); //全部 private readonly Dictionary dicStationStatus = new Dictionary(); private readonly Dictionary dicSizeLocal = new Dictionary(); //扫码独立 132个元素 private readonly Dictionary dicStatusColor = new Dictionary(); private readonly List _taskTypes = null; private readonly List _stationList; private readonly List _exCavityInfo; double _trackPositionY = 0; public double _localScreenWidth; public double _localScreenHeight; private int stepIndex; public int StepIndex { get => stepIndex; set => SetProperty(ref stepIndex, value); } private double handMachineYLocation; public double HandMachineYLocation { get => handMachineYLocation; set => SetProperty(ref handMachineYLocation, value); } private string palletCode; public string PalletCode { get => palletCode; set => SetProperty(ref palletCode, value); } private string rgvPalletCode; public string RgvPalletCode { get => rgvPalletCode; set => SetProperty(ref rgvPalletCode, value); } private string cavitySourceName; public string CavitySourceName { get => cavitySourceName; set => SetProperty(ref cavitySourceName, value); } private string taskStatusName; public string TaskStatusName { get => taskStatusName; set => SetProperty(ref taskStatusName, value); } private string taskTypeName; public string TaskTypeName { get => taskTypeName; set => SetProperty(ref taskTypeName, value); } private string cavityTargetName; public string CavityTargetName { get => cavityTargetName; set => SetProperty(ref cavityTargetName, value); } private DateTime startTime; public DateTime StartTime { get => startTime; set => SetProperty(ref startTime, value); } private string _imageSource; public string ImageSource { get => _imageSource; //set => SetProperty(ref imageSource, value); set { if (Application.Current.Dispatcher.CheckAccess()) // 检查是否在 UI 线程 { SetProperty(ref _imageSource, value); // 直接更新 } else { Application.Current.Dispatcher.Invoke(() => { SetProperty(ref _imageSource, value); // 切换到 UI 线程更新 }); } } } public ConcurrentDictionary CacheStoveData { set; get; } = new ConcurrentDictionary(); private SubscriptionToken _subscriptionToken; private readonly IEventAggregator _eventAggregator; private readonly IDialogService _dialogService; public EquipmentMonitorViewModel(IUnityContainer container, IRegionManager regionManager ,IEventAggregator eventAggregator, IDialogService dialogService) { _unityContainer = container; _regionManager = regionManager; _dialogService = dialogService; cmdFactories = _unityContainer.Resolve(); _taskTypes = _unityContainer.Resolve().GetAll(); _stationList = _unityContainer.Resolve().GetAll(); //工站信息 _exCavityInfo = _unityContainer.Resolve().GetExAll(). OrderBy(p => p.Number).ThenBy(x => x.Column).ToList(); //工站详细信息 SetAgvImage((int)EAgvMoveStatus.Wait); StepIndex = 0; _eventAggregator = eventAggregator; _subscriptionToken = _eventAggregator.GetEvent() //Unsubscribe: 取消订阅(如在组件销毁时) .Subscribe(OnStoveData, ThreadOption.UIThread); //事件触发时执行的方法,ThreadOption.UIThread,(默认):在发布事件的线程执行 } // 事件处理方法(接收传递的数据) private void OnStoveData(Dictionary models) { CacheStoveData.Clear(); foreach (var kvp in models) { CacheStoveData.TryAdd(kvp.Key, kvp.Value); } } public void SetAgvImage(int status) { if (lastAgvStatus == (EAgvMoveStatus)status) { return; } lastAgvStatus = (EAgvMoveStatus)status; if ((int)EAgvMoveStatus.Wait == status) { ImageSource = MyAgvPath.Wait; } else if((int)EAgvMoveStatus.Error == status) { ImageSource = MyAgvPath.Error; } else { ImageSource = MyAgvPath.Normal; } } public void Init() { GenBrushColor(); GenPopupMenu(); DrawMainWindow(); Task.Run(() => RefreshStoveStatus()); Task.Run(() => RefreshStoveInfo()); Task.Run(() => RefreshAgv()); GetDeviceUnEnable(); } private void GetDeviceUnEnable() { var devices = _unityContainer.Resolve().GetUnEnableAll(); foreach(var item in devices) { CommonCoreHelper.Instance.BlockStatusColor.Add(item); } } private void GenBrushColor() { //dicStatusColor.Add((int)EPalletStatus.Init, Brushes.White); dicStatusColor.Add((int)EPalletStatus.Loading, Brushes.Bisque); dicStatusColor.Add((int)EPalletStatus.Advisable, Brushes.Purple); dicStatusColor.Add((int)EPalletStatus.Bake, Brushes.DarkOrange); dicStatusColor.Add((int)EPalletStatus.BakeOver, Brushes.Green); dicStatusColor.Add((int)EPalletStatus.WaitTest, Brushes.Gold); dicStatusColor.Add((int)EPalletStatus.TestOK, Brushes.PaleGreen); dicStatusColor.Add((int)EPalletStatus.TestNG, Brushes.DeepPink); dicStatusColor.Add((int)EPalletStatus.Blank, Brushes.LightSteelBlue); dicStatusColor.Add((int)EPalletStatus.BlankOver, Brushes.White); dicStatusColor.Add((int)EPalletStatus.Maintain, Brushes.Tan); } void ClearDispTask() { TaskStatusName = ""; CavitySourceName = ""; CavityTargetName = ""; PalletCode = ""; TaskTypeName = ""; RgvPalletCode = ""; ClearAgvPath(); } /// /// 机器人相关信息刷新 /// private void RefreshAgv() { var machinMove = new Action(toLocation => { MachineMoveAnimation(toLocation); }); var task = _unityContainer.Resolve().UnexecuteTask(); //从数据库捞任务 if (null != task) { //task.StepId:表示正在执行的步 var actions = _unityContainer.Resolve().GetPreviousActions(task.StepId); foreach (var item in actions) //为了刷新界面, 要恢复之前的步信息 { TTaskRecord newRecord = new TTaskRecord(); newRecord = JSON.DeserializeObject(JSON.SerializeObject(task)); newRecord.StepId = item.StepId; CommonCoreHelper.Instance.BlockTask.Add(newRecord); } } while (true) { if (Global.AppExit) { return; } //画路径,界面文字信息,机器人位置 TTaskRecord item = CommonCoreHelper.Instance.BlockTask.Take(); //获取并移除元素,当集合为空时会阻塞 LogHelper.Instance.Warn($"{item.Id}-----------------------------item.StepId:{item.StepId}"); if (item.StepId == (int)ETaskStep.None) //删除任务时,界面要清除 { ClearDispTask(); StepIndex = 0; continue; } SizeAndLocationModel localSoure = dicSizeLocal[item.Source]; SizeAndLocationModel localTarget = dicSizeLocal[item.Target]; TaskStatusName = ((ETaskStep)item.StepId).GetDescription(); if (item.StepId == (int)ETaskStep.Unexecuted) //新任务:界面文字信息, 画路径,为1却执行不到 { RefreshRgvWindows(item); } else if(item.StepId == (int)ETaskStep.MoveFrom) //机器人位置:Form的动画 { if (string.IsNullOrEmpty(PalletCode)) { RefreshRgvWindows(item); } StartTime = item.BuildTime; } else if (item.StepId == (int)ETaskStep.Pick) //正在取盘,还没有取完,所以机器人的托盘号发在下一步 { machineAnimation.Dispatcher.BeginInvoke(machinMove, localSoure.Left);//Form的动画 } else if(item.StepId == (int)ETaskStep.MoveTo) //机器人位置:To的动画 { TPalletInfo pallet = _unityContainer.Resolve().GetPalletInfo(item.PalletId); RgvPalletCode = pallet.PalletCode; } else if (item.StepId == (int)ETaskStep.Place) // { machineAnimation.Dispatcher.BeginInvoke(machinMove, localTarget.Left);//To的动画 } else if (item.StepId == (int)ETaskStep.Finish) { ClearDispTask(); } StepIndex = _unityContainer.Resolve().GetAction(item.StepId).Id - 2; } } private void RefreshRgvWindows(TTaskRecord item) { LogHelper.Instance.Warn($"--{item.Id}-----------------------------item.StepId:{item.StepId}"); CavityInfoModel cavitySource = _exCavityInfo.Where(x => x.Id == item.Source).FirstOrDefault(); //取位置 CavityInfoModel cavityTarget = _exCavityInfo.Where(x => x.Id == item.Target).FirstOrDefault(); //放位置 TTaskType taskType = _taskTypes.Where(x => x.Id == item.TaskTypeId).FirstOrDefault(); //任务类型 TaskTypeName = (null == taskType) ? "手动任务!" : taskType.Name;//手动任务会为空 CavitySourceName = cavitySource.CavityName; CavityTargetName = cavityTarget.CavityName; TPalletInfo pallet = _unityContainer.Resolve().GetPalletInfo(item.PalletId); PalletCode = pallet.PalletCode; DrawAgvPath(item); //画路径 } private void MachineMoveAnimation(double toX) { DoubleAnimation x = new DoubleAnimation(); x.To = toX; Duration duration = new Duration(TimeSpan.FromMilliseconds(5000)); x.Duration = duration; machineAnimation.BeginAnimation(TranslateTransform.XProperty, x); } /// /// 连接PLC状态 /// private void RefreshStoveStatus() { while (true) { TDeviceConfig config = CommonCoreHelper.Instance.BlockStatusColor.Take(); // var stations = _unityContainer.Resolve().GetStaions(config.Id); if (Global.AppExit) { return; } if (null == stations) continue; foreach (var station in stations) { if (!dicStationStatus.ContainsKey(station.Id)) //这里会导致机器人退出 { continue; } if (!config.Enable) //因为这个只是通讯 (!station.Enable) { SetStationColor(station.Id, Colors.Gray); continue; } if (config.IsConnect) { SetStationColor(station.Id, Colors.Green); } else { SetStationColor(station.Id, Colors.Red); } } } } private void SetStationColor(int stationId, Color color) { if (null == Application.Current || null == Application.Current.Dispatcher) { return; } Application.Current.Dispatcher.Invoke(() => { dicStationStatus[stationId].Fill = new SolidColorBrush(color); }); } private void RefreshStoveInfo() { bool trigContent = false; string lastButtonHashValue = ""; string lastToolTipHashValue = "" ; List cavityInfos = null; while (true) { trigContent = false; CommonCoreHelper.Instance.MainViewAutoEvent.WaitOne(5000); //没有信息,也二秒刷新一下界面; 有消息,马上能刷 cavityInfos = _unityContainer.Resolve().GetAllExInfo().Where(x=>x.Type != (int)EStationType.AGV).ToList(); string buttonHashValue = JSON.SerializeObject(cavityInfos) ; string toolTipHashValue = JSON.SerializeObject(CacheStoveData); Application.Current.Dispatcher.Invoke(() => { if (!string.Equals(lastButtonHashValue, buttonHashValue)) { trigContent = true; lastButtonHashValue = buttonHashValue; foreach (var item in cavityInfos) { var button = buttonDic[item.CavityName]; if (!item.Enable || !item.CavityEnable) { button.Background = new SolidColorBrush(Colors.Gray); button.Content = "禁用" + item.PalletCode; button.ToolTip = null; continue; } else if (item.Lock) { button.Background = new SolidColorBrush(Colors.Gray); button.Content = "锁定" + item.PalletCode; button.ToolTip = null; continue; } if (dicStatusColor.TryGetValue(item.PalletStatus ?? 0, out SolidColorBrush colorValue)) { button.Background = colorValue; } else //没有夹具,item.PalletStatus为0 { button.Background = new SolidColorBrush(Colors.White); } button.Content = item.PalletCode; //button.ToolTip = ConcatToolTip(item); if (IsCurrentStation(item)) { continue; } if (item.IsLoad && 0 == item.PalletId) { button.Background = new SolidColorBrush(Colors.Red); button.Content = "有信号|无记忆"; } else if (!item.IsLoad && 0 != item.PalletId) { button.Background = new SolidColorBrush(Colors.Red); button.Content = "无信号|有记忆"; } } } if (!string.Equals(lastToolTipHashValue, toolTipHashValue) || trigContent) //温度变化,刷新 { lastToolTipHashValue = toolTipHashValue; foreach (var item in cavityInfos) { var button = buttonDic[item.CavityName]; button.ToolTip = ConcatToolTip(item); } } }); } } public bool IsCurrentStation(ExCavityInfoModel cavityInfo) { TTaskRecord taskRecord = _unityContainer.Resolve().UnexecuteTask(); if (null == taskRecord) { return false; } if (taskRecord.Source == cavityInfo.Id || taskRecord.Target == cavityInfo.Id) { return true; } return false; } private TextBlock ConcatToolTip(ExCavityInfoModel item) { StringBuilder sb = new StringBuilder(200); sb.AppendLine($"工站名称:{item.CavityName}"); if (!string.IsNullOrEmpty(item.PalletCode)) { sb.AppendLine($"托盘条码:{item.PalletCode}"); sb.AppendLine($"电池数量:{item.BatteryQty ?? 0}"); if (item.Type == (int)EStationType.Loading) { sb.AppendLine($"上料开始时间:{item.LoadingBegingTime}"); } if (null != item.LoadingOverTime) { sb.AppendLine($"上料结束时间:{item.LoadingOverTime}"); } if (null != item.BakingBeginTime) { sb.AppendLine($"开始烘烤:{item.BakingBeginTime}"); } var datas = JSON.DeserializeObject>(JSON.SerializeObject(CacheStoveData)); //深拷贝 if (datas.TryGetValue(item.Id, out StoveDataModel data)) { if (null != data) { sb.AppendLine($"温度:{string.Join(",", Math.Round(data.Temps.Average(), 2))}"); sb.AppendLine($"真空值:{string.Join(",", data.Vacuum)}"); if ((int)EPalletStatus.Bake == item.PalletStatus) //烘烤中,才有工作时长 { sb.AppendLine($"烘烤时长:{data.WorkTime / 60}小时{data.WorkTime % 60}分钟"); sb.AppendLine($"预计结束烘烤:{DateTime.Now.AddMinutes(data.TotalWorkTime - data.WorkTime).ToString("yyyy-MM-dd HH:mm")}"); } } } if (null != item.BakingOverTime) { sb.AppendLine($"结束烘烤:{item.BakingOverTime}"); } } sb.Length -= Environment.NewLine.Length; return new TextBlock { Text = sb.ToString(), Foreground = Brushes.White, Background = Brushes.Blue, TextWrapping = TextWrapping.Wrap }; } private void GenPopupMenu() { foreach (var item in _exCavityInfo) { ContextMenu menu = new ContextMenu(); menu.Width = 180; if (item.Type == (int)EStationType.AGV) { GenMenuItem("删除当前任务", DeleteCurrentTask_Click, menu); } else { GenMenuItem("机器人调度", RobotMove_Click, menu); if (item.Type == (int)EStationType.Stove) { GenMenuItem("腔体解锁", DispatchUnlock_Click, menu); GenMenuItem("初始化", Init_Click, menu); GenMenuItem("发送配方", SendBakingParam_Click, menu); GenMenuItem("开始烘烤", StartBaking_Click, menu); //GenMenuItem("结束烘烤", EndBaking_Click, menu); GenMenuItem("开门", OpenDoor_Click, menu); GenMenuItem("关门", CloseDoor_Click, menu); } GenMenuItem("禁用", Disenable_Click, menu); GenMenuItem("可用", Enable_Click, menu); GenMenuItem("请求取盘", ReqPick_Click, menu); GenMenuItem("请求放盘", ReqPlace_Click, menu); } contextMenuDic.Add(item.CavityName, menu); } } private void SendBakingParam_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel cavityInfo = _exCavityInfo.Where(x => x.CavityName == stationName).FirstOrDefault(); //不会刷新 if (MessageBoxResult.OK != HandyControl.Controls.MessageBox.Ask("确认执行发送烘烤配方参数!", "操作提示")) { return; } TDeviceConfig conf = _unityContainer.Resolve().GetConfig(cavityInfo.StationId); IPLCDevice plc = _unityContainer.Resolve(conf.Name); //if (plc == null || !plc.IsConnect) //{ // LogHelper.Instance.Error($"连接PLC失败!plc:{plc.Name}", true); // return; //} ExCavityInfoModel detail = _unityContainer.Resolve().GetAllExInfo().Where( x => x.Id == cavityInfo.Id && !string.IsNullOrEmpty(x.JobNum)).FirstOrDefault(); //这个腔体的夹具信息 StoveProcessParam processParam = _unityContainer.Resolve(); if (null == detail) { LogHelper.Instance.Error($"{stationName}的夹具没有绑定工单,不能下发烘烤配方!", true); return; } if (!processParam.SendStoveProcessParam(plc, detail)) { LogHelper.Instance.Error($"{stationName}工站发送配方失败", true); return; } LogHelper.Instance.Info($"【{stationName}】工站发送配方成功", true); } private void StartBaking_Click(object sender, RoutedEventArgs e) { bool[] bakeEnable = new bool[Global.STOVE_MAX_LAYERS]; MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel cavityInfo = _exCavityInfo.Where(x => x.CavityName == stationName).FirstOrDefault(); if (MessageBoxResult.OK != HandyControl.Controls.MessageBox.Ask("确认执行开始烘烤", "操作提示")) { return; } TDeviceConfig conf = _unityContainer.Resolve().GetConfig(cavityInfo.StationId); IPLCDevice plc = _unityContainer.Resolve(conf.Name); if (plc == null || !plc.IsConnect) { LogHelper.Instance.Error($"连接PLC失败!plc:{plc.Name}", true); return; } List details = _unityContainer.Resolve().GetAllExInfo().Where( x => x.StationId == cavityInfo.StationId).ToList(); //这个腔体的夹具信息 //待烘烤的夹具 details = details.Where(x => x.PalletStatus == (int)EPalletStatus.Advisable || x.PalletStatus == (int)EPalletStatus.TestNG).ToList(); if (0 == details.Count) { LogHelper.Instance.Warn($"烤箱夹具没有状态为【{EPalletStatus.Advisable.GetDescription()},{EPalletStatus.TestNG.GetDescription()}】,不具备烘烤条件!", true); return; } foreach(var item in details) { bakeEnable[item.Layer] = true; } cmdFactories.StartBaking(plc , cavityInfo.StationId, bakeEnable, true); int updateResult = _unityContainer.Resolve().UpdateStartBakingInfo(details); //托盘绑定烤箱位置,状态,时间 if (updateResult <= 0) { LogHelper.Instance.Warn($"修改烤箱{cavityInfo.StationId},状态失败!"); } } //private void EndBaking_Click(object sender, RoutedEventArgs e) //{ // MenuItem menuItem = (MenuItem)sender; // ContextMenu popupMenu = (ContextMenu)menuItem.Parent; // string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; // CavityInfoModel sd = _exCavityInfo.Where(x => x.CavityName == stationName).FirstOrDefault(); // if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认执行结束烘烤", "操作提示")) // { // //cmdFactories.EndBaking(sd.StationId); // } //} private void OpenDoor_Click(object sender, RoutedEventArgs e) { if (SettingProvider.Instance.DispMode == EDispatchMode.Auto) { LogHelper.Instance.Error("自动状态不能开关门!", true); return; } MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel sd = _exCavityInfo.Where(x=>x.CavityName == stationName).FirstOrDefault(); if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认开门", "操作提示")) { cmdFactories.OpenDoor(sd.StationId, sd.Layer); } } private void RobotMove_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string buttonName = ((FrameworkElement)popupMenu.PlacementTarget).Name; var task = _unityContainer.Resolve().UnexecuteTask(); if (null != task) { if (!DeleteTask(task, buttonName)) { return; } } Views.ManualTask f = new Views.ManualTask(buttonName, _unityContainer); f.ShowDialog(); } bool DeleteTask(TTaskRecord task,string stationName) { if (MessageBoxResult.Cancel == HandyControl.Controls.MessageBox.Ask("是否删除未执行完成的任务?", "操作提示")) { return false; } _unityContainer.Resolve().UpdateUnBinding(stationName); _unityContainer.Resolve().DeleteTask(task.Id); task.StepId = (int)ETaskStep.None; CommonCoreHelper.Instance.BlockTask.Add(task); return true; } private void DeleteCurrentTask_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string buttonName = ((FrameworkElement)popupMenu.PlacementTarget).Name; var task = _unityContainer.Resolve().UnexecuteTask(); if (null == task) { HandyControl.Controls.MessageBox.Info("当前没有未执行完成的任务", "操作提示"); return; } DeleteTask(task, buttonName); } private void DispatchUnlock_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string cavityName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel sd = _exCavityInfo.Where(x => x.CavityName == cavityName).FirstOrDefault(); if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认解除调度锁定吗?", "操作提示")) { _unityContainer.Resolve().UnLockStation(sd.StationId, (sbyte)sd.Layer, sd.Column); CommonCoreHelper.Instance.MainViewAutoEvent.Set(); } } private void Init_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel sd = _exCavityInfo.Where(x => x.CavityName == stationName).FirstOrDefault(); if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认初始化?", "操作提示")) { cmdFactories.InitStove(sd.StationId, sd.Layer); } } private void DrawStation() { foreach (var item in _exCavityInfo) { if (item.PosX == (int)EWindowsRowType.Mid) { DrawTrack(); } else { var station = _stationList.Where(x => x.Id == item.StationId).FirstOrDefault(); SizeAndLocationModel drawingInfo = GetDrawingLayout(station, item.Layer, item.Column); dicSizeLocal[item.Id] = drawingInfo; //保存控件位置信息 DrawCanvasButton(item, drawingInfo); } } } private void SetAgvButton(string name) { Button btn = (Button)mainCanvas.FindName(name); btn.ContextMenu = contextMenuDic[name]; btn.Click += ShowDtl_Click; } private void DrawStationTitle() { foreach (var item in _stationList.OrderBy(x => x.Id)) { if (item.PosX != (int)EWindowsRowType.Mid) { var drawingInfos = GetDrawingPointTitle(item); DrawCanvasLabelButton(item, drawingInfos); //画工站控件标题 DrawCanvasStationStatus(item, drawingInfos);//画工站圆圈,状态 } } } private double GetWindowsLastInterval() { int maxY = _stationList.Max(s => s.PosY); //最多有多少列 var stationMaxY = _stationList.Where(s => s.PosY == maxY).FirstOrDefault(); int widthSpace = _stationList.Where(x => x.PosX == stationMaxY.PosX).Sum(s => s.LeftMargin); //算出列数最多的一行的间隔 return (widthSpace / maxY); //给最右边的间隔分配宽度 } /// /// 画机器人走的的路径 /// private void DrawAgvPath(TTaskRecord task) { var sourceInfo = _exCavityInfo.Where(x => x.Id == task.Source).FirstOrDefault(); var targetInfo = _exCavityInfo.Where(x => x.Id == task.Target).FirstOrDefault(); pathCanvas.Dispatcher.BeginInvoke(new Action(delegate { pathCanvas.Children.Clear(); CalcFromToPoint(sourceInfo, targetInfo); //by lsm 画机器人走的路径坐标线 })); } private void ClearAgvPath() { pathCanvas.Dispatcher.BeginInvoke(new Action(delegate { pathCanvas.Children.Clear(); })); } #region 画机器人路径 private void CalcFromToPoint(CavityInfoModel sourceInfo, CavityInfoModel targetInfo) { Point pointFrom = GetButtonCenter(sourceInfo.Id); Point pointTo = GetButtonCenter(targetInfo.Id); Point point1 = new Point { X = pointFrom.X, Y = _trackPositionY + 9.5 }; Point point2 = new Point { X = pointTo.X, Y = _trackPositionY + 9.5 }; DrawPath(pointFrom, point1, point2, pointTo); } private Point GetButtonCenter(int cavityId) { var data = dicSizeLocal[cavityId]; double width = data.Width; double height = data.Height; double left = data.Left; double top = data.Top; return new Point { X = (left + width / 2), Y = (top + height / 2) }; } private void DrawPath(Point point01, Point point02, Point point03, Point point04) { Polyline polyline = new Polyline() { Stroke = Brushes.Green, StrokeThickness = 3, FillRule = FillRule.EvenOdd }; polyline.Points.Add(point01); polyline.Points.Add(point02); polyline.Points.Add(point03); polyline.Points.Add(point04); pathCanvas.Children.Add(polyline); DrawTriangle(point02, point02.Y > point01.Y ? Direction.Down : Direction.Up); DrawTriangle(point03, point02.X < point03.X ? Direction.Right : Direction.Left); if (Math.Abs(point02.X - point03.X) > 40) { int i = 1; while (point02.X + 30 * i < point03.X) { DrawTriangle(new Point(point02.X + 30 * i, point03.Y), Direction.Right); i++; } i = 1; while (point02.X - 30 * i > point03.X) { DrawTriangle(new Point(point02.X - 30 * i, point03.Y), Direction.Left); i++; } } DrawTriangle(point04, point03.Y < point04.Y ? Direction.Down : Direction.Up); } private void DrawTriangle(Point point, Direction direction) { double length = 6; int thickness = 3; Polyline polyline = new Polyline { Stroke = Brushes.Yellow, StrokeThickness = thickness, FillRule = FillRule.EvenOdd }; PointCollection points = new PointCollection(); switch (direction) { case Direction.Right: points.Add(new Point(point.X - length, point.Y - length)); points.Add(point); points.Add(new Point(point.X - length, point.Y + length)); break; case Direction.Left: points.Add(new Point(point.X + length, point.Y - length)); points.Add(point); points.Add(new Point(point.X + length, point.Y + length)); break; case Direction.Down: points.Add(new Point(point.X - length, point.Y - length)); points.Add(point); points.Add(new Point(point.X + length, point.Y - length)); break; case Direction.Up: points.Add(new Point(point.X - length, point.Y + length)); points.Add(point); points.Add(new Point(point.X + length, point.Y + length)); break; } polyline.Points = points; pathCanvas.Children.Add(polyline); } #endregion private void DrawTrack() { double spacing = 15; var agv = _exCavityInfo.Where(x => x.PosX == (int)EWindowsRowType.Mid).FirstOrDefault(); SetAgvButton(agv.CavityName); //设置下拉框 SizeAndLocationModel drawingInfo = GetDrawingLayout(agv, agv.Layer, agv.Column); double startX = drawingInfo.Left; double endX = _localScreenWidth - GetWindowsLastInterval(); double topY = drawingInfo.Top + 20; double bottomY = drawingInfo.Top + drawingInfo.Height - 20; _trackPositionY = drawingInfo.Top + drawingInfo.Height / 2 - 10; //HandMachineYLocation = drawingInfo.Top; //机器人的Y坐标(有偏差,如何修正),控制高73 HandMachineYLocation = _trackPositionY + 9 - 73 / 2; //控制高73:为图片的高度,界面写死了 Path path = new Path { Stroke = Brushes.Black, StrokeThickness = 2 }; // 1. 绘制两条平行轨道 path.Data = Geometry.Parse($"M {startX},{topY} L {endX},{topY}"); path.Data = Geometry.Parse($"{path.Data} M {startX},{bottomY} L {endX},{bottomY}"); // 2. 绘制轨枕(竖线) for (double x = startX; x <= endX; x += spacing) { path.Data = Geometry.Parse($"{path.Data} M {x},{topY - 5} L {x},{bottomY + 5}"); //如果不需要突出来,-5可以去掉 } mainCanvas.Children.Add(path); } private void DrawMainWindow() { DrawStation(); DrawStationTitle(); DrawLegend(); //DrawTrack(); //DrawAgvPath(); // } private void DrawLegend() { TStation station = _stationList.Find(x => x.Type == (int)EStationType.ManualPlat); //在【人工夹具平台】上面。 var cavity = _exCavityInfo.Find(x => x.StationId == station.Id); var drawingInfo = dicSizeLocal[cavity.Id]; var legendEntries = new[] { new LegendEntry { Status = "OKStatus", Left = drawingInfo.Left , Top = 100d, Color = Colors.Green, Description = "正常" }, new LegendEntry { Status = "NGStatus", Left = drawingInfo.Left, Top = 120d, Color = Colors.Red, Description = "中断" }, new LegendEntry { Status = "DisableStatus", Left = drawingInfo.Left, Top = 139d, Color = Colors.Gray, Description = "禁用" } }; foreach (var entry in legendEntries) { DrawLegendEntry(entry); } } private void DrawLegendEntry(LegendEntry entry) { var drawingInfo = new SizeAndLocationModel { Left = entry.Left, Top = entry.Top, Width = 10d, Height = 10d }; DrawCanvasStationStatusWithLalel(entry.Status, new List { drawingInfo }, entry.Color, entry.Description); } private void DrawCanvasStationStatusWithLalel(string name, List drawingInfoModels, Color color, string labelName) { foreach (var item in drawingInfoModels) { var arrow = CreateArrow(name, item, color); mainCanvas.Children.Add(arrow); var label = CreateLabel(labelName, item); mainCanvas.Children.Add(label); } } private Label CreateLabel(string labelName, SizeAndLocationModel drawingInfo) { double x = (drawingInfo.Left + 20) ; double y = (drawingInfo.Top + 13) ; var label = new Label { Content = labelName, Background = new SolidColorBrush(TransparentColor), BorderThickness = BorderThickness, FontSize = 16, }; label.SetValue(Window.LeftProperty, x); label.SetValue(Window.TopProperty, y - 13); return label; } private const double ArrowRadius = 7; private static readonly Color TransparentColor = Colors.Transparent; private static readonly Thickness BorderThickness = new Thickness(0); private System.Windows.Shapes.Path CreateArrow(string name, SizeAndLocationModel drawingInfo, Color color) { var arrow = new System.Windows.Shapes.Path { Name = name + "状态", Fill = new SolidColorBrush(color) }; double x = (drawingInfo.Left + 20); double y = (drawingInfo.Top + 13); var figure = new PathFigure { IsClosed = true, StartPoint = new Point(x, y) }; figure.Segments.Add(new ArcSegment(new Point(x, y + ArrowRadius / 2), new Size(ArrowRadius, ArrowRadius), 1, true, SweepDirection.Counterclockwise, true)); var geometry = new PathGeometry { Figures = { figure } }; arrow.Data = geometry; return arrow; } private LinearGradientBrush CreateLinearGradientBrush() { var brush = new LinearGradientBrush { StartPoint = new Point(0, 0.5), EndPoint = new Point(1, 0.5), GradientStops = GradientStops }; return brush; } private static readonly GradientStopCollection GradientStops = new GradientStopCollection { new GradientStop(Colors.White, 0.0), new GradientStop(Colors.MediumSlateBlue, 0.3), new GradientStop(Colors.MediumSlateBlue, 0.7), new GradientStop(Colors.White, 1.0) }; /// /// 绘制画布工站标签名称图标 /// /// 标签名称 /// 工站位置 private void DrawCanvasLabelButton(TStation station, SizeAndLocationModel drawingInfo) { var button = new Button { Name = $"{station.Name}", Content = $"{station.Desc}", FontSize = 10, Width = drawingInfo.Width, Height = drawingInfo.Height , Foreground = new SolidColorBrush(Colors.White), Background = CreateLinearGradientBrush() }; button.SetValue(Window.LeftProperty, drawingInfo.Left); button.SetValue(Window.TopProperty, drawingInfo.Top); mainCanvas.Children.Add(button); } /// /// 绘制画布工站每行每列电池信息图标 /// /// /// private void DrawCanvasButton(CavityInfoModel cavityInfo, SizeAndLocationModel drawingInfo) { int number = 0; Button button = new Button { Name = cavityInfo.CavityName, Width = drawingInfo.Width , Height = drawingInfo.Height, Background = new SolidColorBrush(Colors.White), Foreground = new SolidColorBrush(Colors.Black), Style = frameworkElement.FindResource("MyButton") as Style, ContextMenu = contextMenuDic[cavityInfo.CavityName], }; button.Click += ShowDtl_Click; button.SetValue(Window.LeftProperty, drawingInfo.Left); button.SetValue(Window.TopProperty, drawingInfo.Top); ToolTipService.SetShowDuration(button, 20_000); ToolTipService.SetHorizontalOffset(button, 0); ToolTipService.SetVerticalOffset(button, 0); // 2. 构建Button的自定义模板(核心:左侧显示"1") if (cavityInfo.Type == (int)EStationType.Stove) { number = cavityInfo.Layer; } else { number = cavityInfo.Column; } ControlTemplate buttonTemplate = CreateButtonTemplateWithLeftNumber(number); //ControlTemplate buttonTemplate = SetButtonTemplateWithCursor(); button.Template = buttonTemplate; //button.OverridesDefaultStyle = true; mainCanvas.Children.Add(button); buttonDic.Add(button.Name, button); } public ControlTemplate SetButtonTemplateWithCursor() { // 2. 构造模板根:Border FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border)); border.Name = "root"; border.SetValue(Border.BackgroundProperty, Brushes.LightGray); border.SetValue(Border.BorderBrushProperty, Brushes.Gray); border.SetValue(Border.BorderThicknessProperty, new Thickness(1)); border.SetValue(Border.CornerRadiusProperty, new CornerRadius(2)); // 3. 构造内容区:ContentPresenter FrameworkElementFactory presenter = new FrameworkElementFactory(typeof(ContentPresenter)); presenter.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center); presenter.SetValue(ContentPresenter.VerticalAlignmentProperty, VerticalAlignment.Center); border.AppendChild(presenter); // 4. 把模板树装进 ControlTemplate ControlTemplate template = new ControlTemplate(typeof(Button)); template.VisualTree = border; // 5. 准备两个触发器:鼠标进入/离开 Trigger overTrigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true }; overTrigger.Setters.Add(new Setter(Control.CursorProperty, Cursors.Hand)); overTrigger.Setters.Add(new Setter(Border.BackgroundProperty, Brushes.DodgerBlue) { TargetName = "root" }); Trigger leaveTrigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = false }; leaveTrigger.Setters.Add(new Setter(System.Windows.Controls.Control.CursorProperty, Cursors.Arrow)); leaveTrigger.Setters.Add(new Setter(Border.BackgroundProperty, Brushes.LightGray) { TargetName = "root" }); template.Triggers.Add(overTrigger); template.Triggers.Add(leaveTrigger); return template; } private ControlTemplate CreateButtonTemplateWithLeftNumber(int layer) { // 1. 创建模板,指定目标类型为Button ControlTemplate template = new ControlTemplate(typeof(Button)); // 2. 创建Grid作为模板的根元素(分两列布局) FrameworkElementFactory gridFactory = new FrameworkElementFactory(typeof(Grid)); gridFactory.SetValue(Grid.SnapsToDevicePixelsProperty, true); //// 绑定Grid的Background到Button的Background属性 gridFactory.SetBinding(Grid.BackgroundProperty, new System.Windows.Data.Binding("Background") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); // 3. 定义Grid的两列:左列固定宽度,右列自适应 // 左列(显示"1") FrameworkElementFactory col1 = new FrameworkElementFactory(typeof(ColumnDefinition)); col1.SetValue(ColumnDefinition.WidthProperty, new GridLength(16)); // 右列(显示Content) FrameworkElementFactory col2 = new FrameworkElementFactory(typeof(ColumnDefinition)); col2.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star)); gridFactory.AppendChild(col1); gridFactory.AppendChild(col2); // 4. 创建左侧显示"1"的TextBlock FrameworkElementFactory numberText = new FrameworkElementFactory(typeof(TextBlock)); numberText.SetValue(TextBlock.TextProperty, layer.ToString()); numberText.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Left); numberText.SetValue(TextBlock.VerticalAlignmentProperty, VerticalAlignment.Center); numberText.SetValue(TextBlock.FontSizeProperty, 14.0); numberText.SetValue(TextBlock.ForegroundProperty, Brushes.Blue); numberText.SetValue(Grid.ColumnProperty, 0); // 放在第一列 gridFactory.AppendChild(numberText); // 5. 创建ContentPresenter,显示Button原有Content(放在第二列) FrameworkElementFactory contentPresenter = new FrameworkElementFactory(typeof(ContentPresenter)); contentPresenter.SetValue(Grid.ColumnProperty, 1); // 绑定ContentPresenter的对齐方式和内边距到Button的原有属性 contentPresenter.SetBinding(ContentPresenter.HorizontalAlignmentProperty, new System.Windows.Data.Binding("HorizontalContentAlignment") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); contentPresenter.SetBinding(ContentPresenter.VerticalAlignmentProperty, new System.Windows.Data.Binding("VerticalContentAlignment") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); contentPresenter.SetBinding(ContentPresenter.MarginProperty, new System.Windows.Data.Binding("Padding") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); gridFactory.AppendChild(contentPresenter); // 6. 添加边框,保留Button的边框样式(可选) FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border)); border.Name = "border"; border.SetValue(Grid.ColumnSpanProperty, 2); // 跨两列 border.SetBinding(Border.BorderBrushProperty, new System.Windows.Data.Binding("BorderBrush") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); border.SetBinding(Border.BorderThicknessProperty, new System.Windows.Data.Binding("BorderThickness") { RelativeSource = System.Windows.Data.RelativeSource.TemplatedParent }); border.SetValue(Border.BackgroundProperty, Brushes.Transparent); gridFactory.AppendChild(border); template.Triggers.Add(CreateTriggers()); // 7. 将Grid设为模板的视觉树根 template.VisualTree = gridFactory; return template; } #region Trigger CreateTriggers() { var mouseOverTrigger = new Trigger { Property = Button.IsMouseOverProperty, Value = true }; //mouseOverTrigger.Setters.Add(new Setter(Control.CursorProperty, Cursors.Hand)); // 悬停时修改背景 //mouseOverTrigger.Setters.Add(new Setter //{ // TargetName = "border", // Property = Border.BackgroundProperty, // Value = Brushes.DodgerBlue //}); // 悬停时修改边框 mouseOverTrigger.Setters.Add(new Setter { TargetName = "border", Property = Border.BorderBrushProperty, Value = Brushes.Blue //.DeepSkyBlue }); // 悬停时修改文字颜色(直接改Button的Foreground,ContentPresenter会继承) //mouseOverTrigger.Setters.Add(new Setter //{ // Property = Button.ForegroundProperty, // Value = Brushes.Red //}); //// 可选:悬停添加阴影 mouseOverTrigger.Setters.Add(new Setter { TargetName = "border", Property = Border.EffectProperty, Value = new DropShadowEffect { BlurRadius = 15, Color = Color.FromRgb(255, 0, 0), Opacity = 10.6 } }); return mouseOverTrigger; } #endregion /// /// 绘制工站通信状态图标 /// /// /// /// private void DrawCanvasStationStatus(TStation station, SizeAndLocationModel item) //index=0开始 { System.Windows.Shapes.Path x_Arrow = new System.Windows.Shapes.Path();//x轴箭头 x_Arrow.Name = $"{station.Name}状态"; x_Arrow.Fill = new SolidColorBrush(Colors.Red); //station.Enable ? Colors.Red : Colors.Gray PathFigure x_Figure = new PathFigure(); x_Figure.IsClosed = true; double x = (item.Left + 20) ; double y = (item.Top + 13); double r = 7;//圆的半径 x_Figure.StartPoint = new Point(x, y);//路径的起点 x_Figure.Segments.Add(new ArcSegment(new Point(x, y + r / 2), new Size(r, r), 1, true, SweepDirection.Counterclockwise, true)); PathGeometry x_Geometry = new PathGeometry(); x_Geometry.Figures.Add(x_Figure); x_Arrow.Data = x_Geometry; mainCanvas.Children.Add(x_Arrow); dicStationStatus.Add(station.Id, x_Arrow); } #region 左键/右键 单击事件 /// /// 左键单击 /// /// /// private void ShowDtl_Click(object sender, RoutedEventArgs e) { string buttonName = (sender as Button).Name; Views.CavityDtlView dlg = new Views.CavityDtlView(buttonName, _unityContainer); dlg.ShowDialog(); //var p = new DialogParameters(); //p.Add("StatinName", buttonName); //_dialogService.ShowDialog(nameof(CavityDtlView), p, r => { /*回调*/ }); } /// /// 右键禁用 /// /// /// private void Disenable_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认" + stationName + "禁用?", "操作提示")) { _unityContainer.Resolve().ChangeStationStatus(stationName, 0); CommonCoreHelper.Instance.MainViewAutoEvent.Set(); HandyControl.Controls.Growl.Info(stationName + " 已经禁用。"); } } private void CloseDoor_Click(object sender, RoutedEventArgs e) { if (SettingProvider.Instance.DispMode == EDispatchMode.Auto) { LogHelper.Instance.Error("自动状态不能开关门!", true); return; } MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; CavityInfoModel sd = _exCavityInfo.Where(x => x.CavityName == stationName).FirstOrDefault(); if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认关门?", "操作提示")) { cmdFactories.CloseDoor(sd.StationId, sd.Layer); } } private void DeleteTask_Click(object sender, RoutedEventArgs e) { if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认要删除当前任务?", "操作提示")) { if (0 >= _unityContainer.Resolve().DeleteUnexecuteTask()) { LogHelper.Instance.Error($"当前没有可执行的任务或当前任务删除失败", true); } else { LogHelper.Instance.Info($"当前任务已删除", true); } } } /// /// 右键可用 /// /// /// private void Enable_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认" + stationName + "可用?", "操作提示")) { _unityContainer.Resolve().ChangeStationStatus(stationName, 1); CommonCoreHelper.Instance.MainViewAutoEvent.Set(); HandyControl.Controls.Growl.Info(stationName + " 已经可用。"); } } private void ReqPick_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认" + stationName + "请求取盘?", "操作提示")) { _unityContainer.Resolve().UpdateStationReq(stationName, (sbyte)ECavityStatus.RequestPick); CommonCoreHelper.Instance.MainViewAutoEvent.Set(); HandyControl.Controls.Growl.Info(stationName + " 已经请求取盘。"); } } private void ReqPlace_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = (MenuItem)sender; ContextMenu popupMenu = (ContextMenu)menuItem.Parent; string stationName = ((FrameworkElement)popupMenu.PlacementTarget).Name; if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("确认" + stationName + "请求放盘?", "操作提示")) { _unityContainer.Resolve().UpdateStationReq(stationName, (sbyte)ECavityStatus.RequestPlace); CommonCoreHelper.Instance.MainViewAutoEvent.Set(); HandyControl.Controls.Growl.Info(stationName + " 已经请求放盘。"); } } private void GenMenuItem(string menuText, RoutedEventHandler click, ContextMenu contextMenu) { MenuItem menu = new MenuItem(); menu.Header = menuText; menu.Foreground = new SolidColorBrush(Colors.Purple); menu.Click += click; contextMenu.Items.Add(menu); } #endregion #region 内部方法 /// /// 获取工站长度 /// /// 工站当前行号staionDetail.PosX, staionDetail.PosX == (int)EWindowsRowType.Mid /// private double GetDrawPointWidth() { int maxY = _stationList.Max(s => s.PosY); //一起有多少列 var stationMaxY = _stationList.Where(s => s.PosY == maxY).FirstOrDefault() ; int widthSpace = _stationList.Where(x=>x.PosX == stationMaxY.PosX).Sum(s => s.LeftMargin); //算出列数最多的一行的间隔 widthSpace += (widthSpace / maxY); //给最右边的间隔分配宽度 return (_localScreenWidth - widthSpace) / maxY; //_localScreenWidth - widthSpace:减去左右之间的间隔 } /// /// 获取工站明细左边距 /// /// 工站当前行号 /// 工站当前列位置 int stationPosX, int stationPosY, double widthPoint /// 工站明细宽度 /// private double GetDrawPointLeft(TStation staionDetail, double controlWidth, int cavityColunm ) { int leftCavityCols = 0; double leftPoints = 0; int widthSpace = 0; if (SettingProvider.Instance.StoveDispDirection == EIsReverseOrder.Positive) { widthSpace = _stationList.Where(x => x.PosY <= staionDetail.PosY && x.PosX == staionDetail.PosX).Sum(s => s.LeftMargin); } else { widthSpace = _stationList.Where(x => x.PosY >= staionDetail.PosY && x.PosX == staionDetail.PosX).Sum(s => s.LeftMargin); } if (staionDetail.PosX == (int)EWindowsRowType.Mid) { leftPoints = staionDetail.LeftMargin; } else if (staionDetail.PosX == (int)EWindowsRowType.Upper) { if (staionDetail.Type == (int)EStationType.Loading || staionDetail.Type == (int)EStationType.UnLoading) { leftCavityCols = ((SettingProvider.Instance.IsReverseOrder == EIsReverseOrder.Positive) ? cavityColunm : (1 == cavityColunm ? 2 : 1) - 1); leftPoints = widthSpace + GetLeftStationWidth(staionDetail, controlWidth) + controlWidth * leftCavityCols; } else { leftPoints = widthSpace + GetLeftStationWidth(staionDetail, controlWidth) + controlWidth * (cavityColunm - 1); } } else if (staionDetail.PosX == (int)EWindowsRowType.Lower) { if (staionDetail.Type == (int)EStationType.Loading || staionDetail.Type == (int)EStationType.UnLoading) { leftCavityCols = ((SettingProvider.Instance.IsReverseOrder == EIsReverseOrder.Positive) ? cavityColunm : (1 == cavityColunm ? 2 : 1) - 1); leftPoints = widthSpace + GetLeftStationWidth(staionDetail, controlWidth) + controlWidth * leftCavityCols; } else { leftPoints = widthSpace + GetLeftStationWidth(staionDetail, controlWidth) + controlWidth * (cavityColunm - 1); } } return leftPoints; } private double GetLeftStationWidth(TStation staionDetail, double controlWidth) { double w = 0; List stations = null; if (SettingProvider.Instance.StoveDispDirection == EIsReverseOrder.Positive) { stations = _stationList.Where(x => x.PosX == staionDetail.PosX && x.PosY < staionDetail.PosY).ToList(); } else { stations = _stationList.Where(x => x.PosX == staionDetail.PosX && x.PosY > staionDetail.PosY).ToList(); } if (0 == stations.Count) //表示左边没有控件 { return w; } foreach (var item in stations) { w += item.Columns * controlWidth; } return w; } /// /// 获取工站明细高度 /// /// 每个工站包含工站明细数量 /// private double GetDrawPointHeight(int PosX) { //double screenHeightAvg = 0; //if (staionDetail.PosX == (int)EWindowsRowType.Upper) //{ // screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.UpperHeight; //} //else if (staionDetail.PosX == (int)EWindowsRowType.Mid) //{ // screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.MidHeight; //} //else //{ // screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.LowerHeight; //} //return screenHeightAvg / staionDetail.Layers; double screenHeightAvg = 0; int Layer = 0; if (PosX == (int)EWindowsRowType.Mid) { Layer = 1; screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.MidHeight; } else { Layer = _stationList.Max(s => s.Layers); //一起有多少列 var stationLayers = _stationList.Where(s => s.Layers == Layer).FirstOrDefault(); if (stationLayers.PosX == (int)EWindowsRowType.Upper) { screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.UpperHeight; } else { screenHeightAvg = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.LowerHeight; } } return screenHeightAvg / Layer; } /// /// 获取工站明细上边距 /// /// 工站当前行号 /// 工站明细编号 /// 工站明细层高 /// 最大层高数量 /// private double GetDrawPointTop(TStation staionDetail, double height, int Layer) { double topPoints = 0; if (staionDetail.PosX == (int)EWindowsRowType.Mid) { topPoints = _localScreenHeight / MainRowDefinition.TotalHeight * (MainRowDefinition.UpperHeight + MainRowDefinition.UpperSpacing) //控件的第一行 + (staionDetail.Layers - Layer) * height; } else if (staionDetail.PosX == (int)EWindowsRowType.Upper) { int totalRows = _stationList.Where(x => x.PosX == staionDetail.PosX).Max(x => x.Layers); topPoints = _localScreenHeight / MainRowDefinition.TotalHeight * MainRowDefinition.UpperSpacing + (totalRows - Layer) * height; //+ (staionDetail.Layers - Layer) * height; } else if (staionDetail.PosX == (int)EWindowsRowType.Lower) { topPoints = _localScreenHeight / MainRowDefinition.TotalHeight * (MainRowDefinition.UpperHeight + MainRowDefinition.UpperSpacing + MainRowDefinition.MidHeight) + (staionDetail.Layers - Layer) * height; } return topPoints; } /// /// 获取工站标签上边距 /// /// 工站 /// 工站标签高度 /// private SizeAndLocationModel GetDrawingPointTitle(TStation station) { int? cavitylId = 0; double drawingInfoTop = 0; SizeAndLocationModel drawingInfo = new SizeAndLocationModel(); if (SettingProvider.Instance.IsReverseOrder == EIsReverseOrder.Positive) { cavitylId = _exCavityInfo.OrderBy(p => p.Column).FirstOrDefault(s => s.StationId == station.Id)?.Id; } else { cavitylId = _exCavityInfo.OrderByDescending(p => p.Column).FirstOrDefault(s => s.StationId == station.Id)?.Id; } drawingInfo = dicSizeLocal[cavitylId ?? 0]; if (station.PosX == (int)EWindowsRowType.Lower) { drawingInfoTop = drawingInfo.Top + drawingInfo.Height; } else { drawingInfoTop = drawingInfo.Top - (drawingInfo.Height * (station.Layers - 1)) - Global.WINDOWS_CONTROLS_HEAD_HIGHT; } return new SizeAndLocationModel { Width = drawingInfo.Width * station.Columns, Left = drawingInfo.Left, Top = drawingInfoTop, Height = Global.WINDOWS_CONTROLS_HEAD_HIGHT }; } public DelegateCommand ReSendCommand => new DelegateCommand((x) => { short stepId = short.Parse((string)x); var SelectTaskRecord = _unityContainer.Resolve().UnexecuteTask(); if (null == SelectTaskRecord || 0 == SelectTaskRecord.Id || 0 == SelectTaskRecord.Target) { HandyControl.Controls.MessageBox.Warning("当前没有未完成的任务!", "警告"); return; } if ((int)ETaskStatus.ExecutionCompleted == SelectTaskRecord.Status) { HandyControl.Controls.MessageBox.Warning("已经完成的任务不能再发送!", "警告"); return; } if (System.Windows.MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask($"你确定重新发送【{((ETaskStep)stepId).GetDescription()}】指令到PLC?", "发送指令")) { if (_unityContainer.Resolve().ManualTaskCmd(SelectTaskRecord, stepId)) { HandyControl.Controls.MessageBox.Info("发送成功"); } else { HandyControl.Controls.MessageBox.Fatal("发送失败,请重新发送!", "警示"); } } }); /// /// 获取一行一列的位置 /// /// /// private SizeAndLocationModel GetDrawingLayout(TStation staionDetail, int layer, int colunm) { SizeAndLocationModel drawingInfo = new SizeAndLocationModel(); drawingInfo.Width = GetDrawPointWidth(); drawingInfo.Height = GetDrawPointHeight(staionDetail.PosX); drawingInfo.Left = GetDrawPointLeft(staionDetail, drawingInfo.Width, colunm); drawingInfo.Top = GetDrawPointTop(staionDetail, drawingInfo.Height, layer); return drawingInfo; } #endregion } }