using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Log; using Aitex.Core.UI.MVVM; using Aitex.Core.Util; using Aitex.Core.Utilities; using Caliburn.Micro.Core; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.IOCore; using MECF.Framework.Common.Utilities; using OpenSEMI.Ctrlib.Controls; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace MECF.Framework.UI.Client.ClientBase { public class ModuleUiViewModelBase : UiViewModelBase { public string SystemName { get; set; } public override void SubscribeKeys() { SubscribeKeys(this, SystemName); } public override void UpdateSubscribe(Dictionary data, object target, string module = null) { Parallel.ForEach(target.GetType().GetProperties().Where(_hasSubscriptionAttribute), property => { PropertyInfo pi = (PropertyInfo)property; SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = subscription.ModuleKey; key = module == null ? key : string.Format("{0}.{1}", module, key); if (_subscribedKeys.Contains(key) && data.ContainsKey(key)) { try { var convertedValue = Convert.ChangeType(data[key], pi.PropertyType); var originValue = Convert.ChangeType(pi.GetValue(target, null), pi.PropertyType); if (originValue != convertedValue) { pi.SetValue(target, convertedValue, null); } } catch (Exception ex) { LOG.Error("由RT返回的数据更新失败" + key, ex); } } }); Parallel.ForEach(target.GetType().GetFields().Where(_hasSubscriptionAttribute), property => { FieldInfo pi = (FieldInfo)property; SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = module == null ? $"{SystemName}.{subscription.ModuleKey}" : string.Format("{0}.{1}", module, subscription.ModuleKey); if (_subscribedKeys.Contains(key) && data.ContainsKey(key)) { try { var convertedValue = Convert.ChangeType(data[key], pi.FieldType); pi.SetValue(target, convertedValue); } catch (Exception ex) { LOG.Error("由RT返回的数据更新失败" + key, ex); } } }); } protected override void InvokePropertyChanged() { PropertyInfo[] ps = this.GetType().GetProperties(); foreach (PropertyInfo p in ps) { if (!p.GetCustomAttributes(false).Any(attribute => attribute is IgnorePropertyChangeAttribute)) InvokePropertyChanged(p.Name); if (p.PropertyType == typeof(ICommand)) { if (p.GetValue(this, null) is IDelegateCommand cmd) cmd.RaiseCanExecuteChanged(); } } FieldInfo[] fi = this.GetType().GetFields(); foreach (FieldInfo p in fi) { InvokePropertyChanged(p.Name); if (p.FieldType == typeof(ICommand)) { DelegateCommand cmd = p.GetValue(this) as DelegateCommand; if (cmd != null) cmd.RaiseCanExecuteChanged(); } } //Parallel.ForEach(this.GetType().GetProperties(), property => InvokePropertyChanged(property.Name)); } } public class UiViewModelBase : BaseModel { PeriodicJob _timer; protected ConcurrentBag _subscribedKeys = new ConcurrentBag(); protected Func _isSubscriptionAttribute; protected Func _hasSubscriptionAttribute; public ICommand DeviceOperationCommand { get; private set; } public bool SetField(ref T field, T value, string propertyName) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; NotifyOfPropertyChange(propertyName); return true; } [Subscription("PM1.EnableMinics")] public bool EnableMinics { get; set; } public Dictionary StockerToModuleDic { get { var moduleDic = new Dictionary() { { "Stocker11", "Stocker1" }, { "Stocker21", "Stocker2" }, { "Stocker12", "Stocker3" }, { "Stocker22", "Stocker4" }, { "Stocker13", "Stocker5" }, { "Stocker23", "Stocker6" }, { "Stocker14", "Stocker7" }, { "Stocker24", "Stocker8" }, { "Stocker15", "Stocker9" }, { "Stocker25", "Stocker10" }, { "Stocker31", "Stocker11" }, { "Stocker41", "Stocker12" }, { "Stocker32", "Stocker13" }, { "Stocker42", "Stocker14" }, { "Stocker33", "Stocker15" }, { "Stocker43", "Stocker16" }, { "Stocker34", "Stocker17" }, { "Stocker44", "Stocker18" }, { "Stocker35", "Stocker19" }, { "Stocker36", "Stocker20" }, }; return moduleDic; } } public Dictionary ModuleToStockerDic { get { var moduleDic = new Dictionary() { { "Stocker1", "Stocker11" }, { "Stocker2", "Stocker21" }, { "Stocker3", "Stocker12" }, { "Stocker4", "Stocker22" }, { "Stocker5", "Stocker13" }, { "Stocker6", "Stocker23" }, { "Stocker7", "Stocker14" }, { "Stocker8", "Stocker24" }, { "Stocker9", "Stocker15" }, { "Stocker10", "Stocker25" }, { "Stocker11", "Stocker31" }, { "Stocker12", "Stocker41" }, { "Stocker13", "Stocker32" }, { "Stocker14", "Stocker42" }, { "Stocker15", "Stocker33" }, { "Stocker16", "Stocker43" }, { "Stocker17", "Stocker34" }, { "Stocker18", "Stocker44" }, { "Stocker19", "Stocker35" }, { "Stocker20", "Stocker36" }, }; return moduleDic; } } /// /// 是否在退出页面后,仍然在后台更新数据,默认不更新 /// public bool ActiveUpdateData { get; set; } protected override void OnInitialize() { base.OnInitialize(); DeviceOperationCommand = new DelegateCommand(DeviceOperation); SubscribeKeys(); } void DeviceOperation(object param) { //InvokeClient.Instance.Service.DoOperation(OperationName.DeviceOperation.ToString(), (object[])param); } public string GetUnitStatusBackground(string status) { return ModuleStatusBackground.GetStatusBackground(status); } public string GetUnitOnlineColor(bool isOnline) { return isOnline ? "LimeGreen" : "Black"; } /// /// support wafer transfer for slot /// public virtual void OnWaferTransfer(DragDropEventArgs args) { try { WaferMoveManager.Instance.TransferWafer(args.TranferFrom, args.TranferTo); } catch (Exception ex) { LOG.Write(ex); } } /// /// support context menu /// public virtual void OnMouseUp(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { //if (sender is Slot slot) //{ // if (slot.WaferStatus == 0) // { // slot.WaferStatus = 1; // } // else if(slot.WaferStatus == 1) // { // slot.WaferStatus = 0; // } //} } else { if (e.ChangedButton != MouseButton.Right) return; if (sender is Slot slot) { ContextMenu cm = ContextMenuManager.Instance.GetSlotMenus(slot); if (cm != null) { ((FrameworkElement)e.Source).ContextMenu = cm; } return; } if (sender is CarrierContentControl carrier) { ContextMenu cm = ContextMenuManager.Instance.GetCarrierMenus(carrier); if (cm != null) { ((FrameworkElement)e.Source).ContextMenu = cm; } return; } } } public UiViewModelBase() { _timer = new PeriodicJob(1000, this.OnTimer, "UIUpdaterThread - " + GetType().Name); _isSubscriptionAttribute = attribute => attribute is SubscriptionAttribute; _hasSubscriptionAttribute = mi => mi.GetCustomAttributes(false).Any(_isSubscriptionAttribute); } // protected virtual bool OnTimer() { try { Poll(); } catch (Exception ex) { LOG.Error(ex.Message); } return true; } public virtual void EnableTimer(bool enable) { if (enable) _timer.Start(); else _timer.Pause(); } protected virtual void Poll() { if (_subscribedKeys.Count > 0) { Dictionary result = QueryDataClient.Instance.Service.PollData(_subscribedKeys); if (result == null) { LOG.Error("获取RT数据失败"); return; } if (result.Count != _subscribedKeys.Count) { string unknowKeys = string.Empty; foreach (string key in _subscribedKeys) { if (!result.ContainsKey(key)) { unknowKeys += key + "\r\n"; } } //System.Diagnostics.Debug.Assert(false, unknowKeys); } InvokeBeforeUpdateProperty(result); UpdateValue(result); Application.Current?.Dispatcher.Invoke(new Action(() => { InvokePropertyChanged(); InvokeAfterUpdateProperty(result); })); } } public void InvokePropertyChanged(string propertyName) { NotifyOfPropertyChange(propertyName); } public void InvokeAllPropertyChanged() { PropertyInfo[] ps = this.GetType().GetProperties(); foreach (PropertyInfo p in ps) { InvokePropertyChanged(p.Name); if (p.PropertyType == typeof(ICommand)) { DelegateCommand cmd = p.GetValue(this, null) as DelegateCommand; if (cmd != null) cmd.RaiseCanExecuteChanged(); } } } protected virtual void InvokePropertyChanged() { Refresh(); } protected virtual void InvokeBeforeUpdateProperty(Dictionary data) { } protected virtual void InvokeAfterUpdateProperty(Dictionary data) { } protected void UpdateValue(Dictionary data) { if (data == null) return; UpdateSubscribe(data, this); var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute() != null); foreach (var property in properties) { var moduleAttr = property.GetCustomAttribute(); UpdateSubscribe(data, property.GetValue(this), moduleAttr.Module); } } public virtual void SubscribeKeys() { SubscribeKeys(this); } protected void Subscribe(string key) { if (!string.IsNullOrEmpty(key)) { _subscribedKeys.Add(key); } } public void SubscribeKeys(UiViewModelBase target) { SubscribeKeys(target, ""); } public void SubscribeKeys(UiViewModelBase target, string module) { Parallel.ForEach(target.GetType().GetProperties().Where(_hasSubscriptionAttribute), property => { SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = subscription.ModuleKey; if (!string.IsNullOrEmpty(module)) { key = $"{module}.{key}"; subscription.SetModule(module); } if (!_subscribedKeys.Contains(key)) _subscribedKeys.Add(key); }); Parallel.ForEach(target.GetType().GetFields().Where(_hasSubscriptionAttribute), method => { SubscriptionAttribute subscription = method.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = subscription.ModuleKey; if (!string.IsNullOrEmpty(module)) { key = $"{module}.{key}"; subscription.SetModule(module); } if (!_subscribedKeys.Contains(key)) _subscribedKeys.Add(key); }); } public virtual void UpdateSubscribe(Dictionary data, object target, string module = null) { Parallel.ForEach(target.GetType().GetProperties().Where(_hasSubscriptionAttribute), property => { PropertyInfo pi = (PropertyInfo)property; SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = subscription.ModuleKey; key = module == null ? key : string.Format("{0}.{1}", module, key); if (_subscribedKeys.Contains(key) && data.ContainsKey(key)) { try { var convertedValue = Convert.ChangeType(data[key], pi.PropertyType); var originValue = Convert.ChangeType(pi.GetValue(target, null), pi.PropertyType); if (originValue != convertedValue) { pi.SetValue(target, convertedValue, null); } } catch (Exception ex) { LOG.Error("由RT返回的数据更新失败" + key, ex); } } }); Parallel.ForEach(target.GetType().GetFields().Where(_hasSubscriptionAttribute), property => { FieldInfo pi = (FieldInfo)property; SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute; string key = subscription.ModuleKey; if (_subscribedKeys.Contains(key) && data.ContainsKey(key)) { try { var convertedValue = Convert.ChangeType(data[key], pi.FieldType); pi.SetValue(target, convertedValue); } catch (Exception ex) { LOG.Error("由RT返回的数据更新失败" + key, ex); } } }); } protected override void OnActivate() { base.OnActivate(); EnableTimer(true); } protected override void OnDeactivate(bool close) { base.OnDeactivate(close); if (!ActiveUpdateData) { EnableTimer(false); } } } public class IODisplay : PropertyChangedBase { public string Key { get; set; } private object _value; public object Value { get { return _value; } set { _value = value; this.NotifyOfPropertyChange(nameof(Value)); } } private Visibility _Visiable=Visibility.Visible; public Visibility Visiable { get { return _Visiable; } set { _Visiable = value; this.NotifyOfPropertyChange(nameof(Visiable)); } } } public class UiWithIOViewModelBase : UiViewModelBase { private string _ModuleIndex; public string ModuleIndex { get { return _ModuleIndex; } set { _ModuleIndex = value; InitIO(); this.NotifyOfPropertyChange(nameof(ModuleIndex)); } } public string ModuleName { get; set; } public string PMModuleName { get { string targetModule = ""; switch (ModuleName) { case "CRA": case "IRA": targetModule = ModuleName; break; case "PRA": targetModule = "PRA1"; break; case "PRA1": case "PRA2": int index = int.Parse(ModuleIndex.Split('_')[1]) + 1; targetModule = $"PRA{index}"; break; case "UNC": case "PUP": case "RCV": case "SND": case "RJC": targetModule = "Cassette" + ModuleIndex.Split('_')[1]; break; default: targetModule = "PM" + ModuleIndex.Replace("-", "_"); break; } return targetModule; } } public ObservableCollection SignalsList { get; set; } = new ObservableCollection(); private string _strDI = "DIListString"; public ObservableCollection DIList { get; set; } = new ObservableCollection(); private string _strDO = "DOListString"; public ObservableCollection DOList { get; set; } = new ObservableCollection(); private string _strAI = "AIListString"; public ObservableCollection AIList { get; set; } = new ObservableCollection(); public override void UpdateSubscribe(Dictionary data, object target, string module = null) { UpdateValue(SignalsList,data); UpdateValue(DIList, data); UpdateValue(DOList, data); UpdateValue(AIList, data); } private void UpdateValue(ObservableCollection list, Dictionary data) { foreach (var item in list) { if (data.ContainsKey($"{PMModuleName}.{item.Key}")) item.Value = data[$"{PMModuleName}.{item.Key}"]; } } protected override void OnInitialize() { base.OnInitialize(); InitIO(); } public void InitIO() { InitSignals(); InitDI(); InitDO(); InitAI(); } protected virtual void InitSignals() { } private void InitDI() { DIList.Clear(); string strKey = $"{PMModuleName}.{_strDI}"; var strDIValue = QueryDataClient.Instance.Service.PollData(new string[] { strKey }); if (strDIValue == null || strDIValue.Count <= 0) return; var strDIValues = strDIValue[strKey].ToString().Split(','); foreach (var item in strDIValues) { base.Subscribe($"{PMModuleName}.{item}"); DIList.Add(new IODisplay() { Key = item }); } } private void InitDO() { DOList.Clear(); string strKey = $"{PMModuleName}.{_strDO}"; var strDOValue = QueryDataClient.Instance.Service.PollData(new string[] { strKey }); if (strDOValue == null || strDOValue.Count <= 0) return; var strDOValues = strDOValue[strKey].ToString().Split(','); foreach (var item in strDOValues) { base.Subscribe($"{PMModuleName}.{item}"); DOList.Add(new IODisplay() { Key = item }); } } private void InitAI() { AIList.Clear(); string strKey = $"{PMModuleName}.{_strAI}"; var strAIValue = QueryDataClient.Instance.Service.PollData(new string[] { strKey }); if (strAIValue == null || strAIValue.Count <= 0) return; var strAIValues = strAIValue[strKey].ToString().Split(','); foreach (var item in strAIValues) { base.Subscribe($"{PMModuleName}.{item}"); AIList.Add(new IODisplay() { Key = item }); } } protected bool GetDIValue(string key) { bool bRet=false; Parallel.ForEach(DIList.Where(x => x.Key == key), property => { bool.TryParse(property.Value?.ToString(), out bRet); }); return bRet; } protected T GetSignalValue(string key) { T ret = default(T); Parallel.ForEach(SignalsList.Where(x => x.Key == key), property=> { if (property.Value != null) ret = (T)(object)property.Value; }); return ret; } } }