using log4net; using PdmSwPlugin.Commmon.Util.UI; using PdmSwPlugin.Common.Util; using PdmSwPlugin.Common.Util.Http; using PdmSwPlugin.PropertySetting.Interface; using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; using System; using System.Collections.Generic; using System.ComponentModel; using System.Net.Http; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using PdmSwPlugin.Common.Interface; using PdmSwPlugin.Common; using PdmSwPlugin.PropertySetting.Entity; using PdmSwPlugin.PropertySetting.Panel; using PdmSwPlugin.PropertySetting.Panel.Attr; using System.Linq; using System.Reflection; using System.Windows.Threading; using PdmSwPlugin.Common.Setting; using System.IO; using System.Collections.ObjectModel; using System.Runtime.InteropServices; using PdmSwPlugin.PropertySetting.Util; namespace PdmSwPlugin.PropertySetting { public static class NameConstant { public const string materialCode = "物料编码"; public const string materialName = "物料名称"; public const string materialModel = "型号"; public const string materialType = "物料类型"; public const string weight = "重量"; public const string jgjType = "加工件类型"; public const string stuff = "材质"; public const string surface = "表面处理"; public const string heat = "热处理"; public const string designer = "设计人员"; public const string version = "版本号"; public const string remark = "备注"; public const string docType = "文件格式"; public const string brand = "品牌"; public const string versionChange = "版本变更"; public const string symPart = "对称件"; public const string bakingPart = "烤漆件"; public const string bakingSurface = "烤漆件表面"; public const string size = "外形尺寸"; public static readonly ObservableCollection MaterialTypes = new ObservableCollection { "普通件", "机罩","机架","大板" };// "易损件","备件", public static readonly ObservableCollection DocTypes = new ObservableCollection { "模组", "加工件" }; public static readonly HashSet SpecialJgjType = new HashSet { "型材件", "金属板焊接件" }; public static bool SetProperties(object container, object properties, Dictionary initData, out string errMsg) { if (initData != null) initData.Clear(); errMsg = null; Dictionary datas = properties as Dictionary; (container as UIElement).Dispatcher.Invoke(() => { // PropHolder.SetPropToUI(container, datas); Dictionary map = PropHolder.GetAttrMap(container.GetType()); if (map == null) { return; } foreach (var prop in map.Keys) { PropertySettingAttr attr = map[prop]; if (attr == null || !attr.NeedInit) { continue; } string name = attr.Name; string value = datas.Get(name, string.Empty); if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(attr.defaultValue)) { value = attr.defaultValue; // 默认值不写入initData } else { // 其他写入initData if (initData != null) initData[name] = value; } PropHolder.SetPropToUI(container, prop, value); } // var props = container.GetType().GetProperties().Where(prop => System.Attribute.IsDefined(prop, typeof(PropertySettingAttr))) //.ToList(); // foreach (var prop in props) // { // PropertySettingAttr attr = prop.GetCustomAttribute(); // if (attr == null || !attr.NeedInit) // { // continue; // } // string name = attr.Name; // string value = datas.Get(name, string.Empty); // if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(attr.defaultValue)) // { // value = attr.defaultValue; // // 默认值不写入initData // } // else // { // // 其他写入initData // if (initData != null) initData[name] = value; // } // prop.SetValue(container, value); // } }); return true; } public static bool CompareWithInit(object container, Dictionary initData) { var props = container.GetType().GetProperties().Where(prop => System.Attribute.IsDefined(prop, typeof(PropertySettingAttr))) .ToList(); foreach (var prop in props) { PropertySettingAttr attr = prop.GetCustomAttribute(); if (attr == null || !attr.NeedInit || !attr.NeedSave) { continue; } string name = attr.Name; string value = initData.Get(name, string.Empty); string newValue = prop.GetValue(container) as string; if (name == NameConstant.weight) { if (string.IsNullOrEmpty(value)) { return true; } } else if (value != newValue) { return true; } } return false; } public static Dictionary GetAllProperties(object container) { Dictionary res = new Dictionary(); var props = container.GetType().GetProperties().Where(prop => System.Attribute.IsDefined(prop, typeof(PropertySettingAttr))) .ToList(); foreach (var prop in props) { PropertySettingAttr attr = prop.GetCustomAttribute(); if (attr == null || !attr.NeedSave) { continue; } res.Add(attr.Name, prop.GetValue(container).ToString()); } return res; } public static bool UpdateSingleProperty(object container, string name, string value) { var props = container.GetType().GetProperties().Where(prop => System.Attribute.IsDefined(prop, typeof(PropertySettingAttr))) .ToList(); foreach (var prop in props) { PropertySettingAttr attr = prop.GetCustomAttribute(); if (attr == null || attr.Name != name || !attr.NeedInit) { continue; } string oldValue = prop.GetValue(container) as string; if (oldValue == value) { return false; } prop.SetValue(container, value); return true; } return false; } } /// /// CommonSettingControl.xaml 的交互逻辑 /// [PdmSwPlugin(Title = "属性设置")] public partial class CommonSettingControl : UserControl, ISwAppSetter, INotifyPropertyChanged , IActiveDocChangeHandler, ITabControlSelectionChangeHandler { private static ILog Logger = LogManager.GetLogger("PropertySetting"); #region 不能公用的东西,真有你的啊C# public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public void RaiseAndSetIfChanged(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) { RaisePropertyChanged(propertyName); } } #endregion public readonly Dictionary controlCache = new Dictionary(); #region 属性 public SldWorks SwApp { get; private set; } public ModelDoc2 activeDoc { set; get; } public ModelDoc2 LastReadDoc { get; set; } public ModelDoc2 ReadDoc { get; set; } public Component2 ReadComponent { get; set; } private HttpClient Client { get; set; } Dictionary settings; #endregion #region UI绑定 private string _readDocPath; public string ReadDocPath { get => _readDocPath; set => RaiseAndSetIfChanged(ref _readDocPath, value); } #endregion private HttpClientCreator clientCreator { get; set; } private UserControl ActiveOpter { get; set; } public CommonSettingControl() { clientCreator = new HttpClientCreator(new HttpConfig(PluginSetting.Instance.BaseAddress)); InitializeComponent(); DataContext = this; } public CommonSettingControl(SldWorks SwApp) : this() { this.SwApp = SwApp; } public Dictionary GetPropsWithLog(ModelDoc2 currentModelDoc, bool needResolve, HashSet skipName, HashSet skipResolveName) { if (currentModelDoc == null) return null; var start = DateTime.Now; var data = CustomPropertyUtil.GetCustomProperties2(currentModelDoc, needResolve, skipName, skipResolveName); Logger.Debug($"Get Props {(DateTime.Now - start).TotalMilliseconds} ms."); return data; } public void InitPropertyData() { try { if (Client == null) { Client = clientCreator.GetClient(); } DefaultPanel defaultPanel = new DefaultPanel(); controlCache.Add("default", defaultPanel); JgjPartPanel jgjPart = new JgjPartPanel(); controlCache.Add("jgjPart", jgjPart); JgjModulePanel jgjModule = new JgjModulePanel(); controlCache.Add("jgjModule", jgjModule); var stPart = new StandardPartPanel(); controlCache.Add("standardPart", stPart); var stModule = new StandardModulePanel(); controlCache.Add("standardModule", stModule); LoadComboxItemSource(); Refresh_Click(null, null); } catch (Exception ex) { Logger.Error($"PropertySetting Init Error!", ex); } } private void Jgj_SinglePropertyChanged(object sender, string name, object value) { // CustomPropertyUtil.SetCustomProperties(ReadDoc, name, (string)value); } /// /// 从服务器加载各种选项 /// private void LoadComboxItemSource() { try { Result> res = Client.GetSyncAction>("design/rule/openApi/test"); Dictionary datas = res.HandleResult(); settings = datas; foreach (var key in controlCache.Keys) { (controlCache[key] as IPropertyOpt).SetSettings(settings); } } catch (Exception ex) { Logger.Error("Request Jgj properties failed.", ex); this.Error($"请求加工件属性失败!{ex.Message}"); } } private void UpdateActiveDoc() { var start = DateTime.Now; Logger.Debug("UpdateActiveDoc Start..."); if (activeDoc != null) { DetachDocNotify(activeDoc); } activeDoc = SwApp.ActiveDoc; if (activeDoc != null) { AttachDocNotify(activeDoc); int docType = activeDoc.GetType(); if (docType == (int)swDocumentTypes_e.swDocASSEMBLY) { activeDoc.ClearSelection2(true); } } Logger.Debug($"UpdateActiveDoc End {activeDoc?.GetPathName()} {(DateTime.Now - start).TotalMilliseconds}ms."); UpdateUI(activeDoc); } /// /// 附加一些插件范围内的事件 /// /// private void AttachDocNotify(ModelDoc2 doc) { int docType = doc.GetType(); if (docType == (int)swDocumentTypes_e.swDocASSEMBLY) { AssemblyDoc ass = doc as AssemblyDoc; ass.UserSelectionPostNotify += Ass_UserSelectionPostNotify; ass.DestroyNotify2 += ActiveDocDestroyNotify2; } else if (docType == (int)swDocumentTypes_e.swDocPART) { PartDoc part = doc as PartDoc; part.DestroyNotify2 += ActiveDocDestroyNotify2; } else if (docType == (int)swDocumentTypes_e.swDocDRAWING) { DrawingDoc draw = doc as DrawingDoc; draw.DestroyNotify2 += ActiveDocDestroyNotify2; } } /// /// 移除插件范围内的一些事件 /// /// private void DetachDocNotify(ModelDoc2 doc) { try { int docType = doc.GetType(); if (docType == (int)swDocumentTypes_e.swDocASSEMBLY) { AssemblyDoc ass = doc as AssemblyDoc; ass.UserSelectionPostNotify -= Ass_UserSelectionPostNotify; ass.DestroyNotify2 -= ActiveDocDestroyNotify2; } else if (docType == (int)swDocumentTypes_e.swDocPART) { PartDoc part = doc as PartDoc; part.DestroyNotify2 -= ActiveDocDestroyNotify2; } else if (docType == (int)swDocumentTypes_e.swDocDRAWING) { DrawingDoc draw = doc as DrawingDoc; draw.DestroyNotify2 -= ActiveDocDestroyNotify2; } } catch (COMException e) { // 如果sw把不是装配体/零件体/工程图的文档关了,有时会报这个问题,留个日志不报错了 Logger.Warn("COMObject detach event failed.", e); activeDoc = null; } } private int ActiveDocDestroyNotify2(int DestroyType) { if (activeDoc == null) { return 0; } DetachDocNotify(activeDoc); activeDoc = null; ReadComponent = null; UpdateUI(null); return 0; } public void UpdateUI(ModelDoc2 doc) { var start = DateTime.Now; Logger.Debug("UpdateUI Start..."); AlertSaveWindow(); LastReadDoc = ReadDoc; ReadDoc = doc; SwitchVisiable(); Logger.Debug($"UpdateUI End {activeDoc?.GetPathName()} {(DateTime.Now - start).TotalMilliseconds}ms."); } private int Ass_UserSelectionPostNotify() { var swSelMgr = (SelectionMgr)activeDoc.SelectionManager; var i = swSelMgr.GetSelectedObjectCount2(-1); if (i > 0) { try { Component2 component = swSelMgr.GetSelectedObjectsComponent4(1, -1); ModelDoc2 doc = activeDoc; ReadComponent = null; if (component != null) { doc = component.IGetModelDoc(); ReadComponent = component; } UpdateUI(doc); } catch (Exception ex) { Logger.Error("Ass Change Component Error.", ex); this.Error($"刷新属性失败!{ex.Message}"); } } return 1; } /// /// 根据激活的文档类型,变更属性可视 /// private void SwitchVisiable() { var start = DateTime.Now; Logger.Debug("SwitchVisiable Start..."); HashSet skipName = new HashSet { NameConstant.weight }; HashSet skipResolveName = new HashSet { NameConstant.materialCode }; IPropertyOpt last = ActiveOpter as IPropertyOpt; string contentKey = "default"; int? docType = ReadDoc?.GetType(); UserControl control; IPropertyOpt newOne; Dictionary properties; if (docType == (int)swDocumentTypes_e.swDocDRAWING) { ReadDocPath = ReadDoc.GetPathName(); contentKey = "default"; control = controlCache[contentKey]; newOne = control as IPropertyOpt; newOne.SetProperties(null, "当前不支持工程图", true, out _); } else if (docType == (int)swDocumentTypes_e.swDocPART) { ReadDocPath = ReadDoc.GetPathName(); properties = GetPropsWithLog(ReadDoc, true, skipName, skipResolveName); string fileType = properties.Get(NameConstant.docType); /*if (fileType == "加工件" || fileType == "模组") { contentKey = "jgjPart"; }*/ if (BomIniterHolder.Instance.IsJgj(ReadDoc)) { contentKey = "jgjPart"; } else { contentKey = "standardPart"; } control = controlCache[contentKey]; newOne = control as IPropertyOpt; newOne.SetProperties(ReadDoc, properties, true, out _); } else if (docType == (int)swDocumentTypes_e.swDocASSEMBLY) { ReadDocPath = ReadDoc.GetPathName(); if (ReadDoc.IsOpenedViewOnly()) { contentKey = "default"; control = controlCache[contentKey]; newOne = control as IPropertyOpt; newOne.SetProperties(null, "当前处于只读模式", true, out _); } else if (ReadDoc.IsOpenedReadOnly()) { contentKey = "default"; control = controlCache[contentKey]; newOne = control as IPropertyOpt; newOne.SetProperties(null, "当前处于只读模式", true, out _); } else { // !Equals(LastReadDoc, ReadDoc) properties = GetPropsWithLog(ReadDoc, true, skipName, skipResolveName); string fileType = properties.Get(NameConstant.docType); /*if (fileType == "加工件" || fileType == "模组") { contentKey = "jgjPart"; }*/ if (BomIniterHolder.Instance.IsJgj(ReadDoc)) { contentKey = "jgjModule"; } else { contentKey = "standardModule"; } control = controlCache[contentKey]; newOne = control as IPropertyOpt; newOne.SetProperties(ReadDoc, properties, true, out _); } } else { contentKey = "default"; control = controlCache[contentKey]; newOne = control as IPropertyOpt; string PathName = ReadComponent?.GetPathName(); if (PathName == null) { ReadDocPath = ""; newOne.SetProperties(ReadDoc, "请打开一个文档", true, out _); } else { ReadDocPath = PathName; string name = Path.GetFileNameWithoutExtension(PathName); newOne.SetProperties(ReadDoc, $"【{name}】未找到文档,请检查是否被压缩或轻量化", true, out _); } } if (last != null) { last.UpdateProperty -= Jgj_SinglePropertyChanged; last = null; } ActiveOpter = control; newOne.UpdateProperty += Jgj_SinglePropertyChanged; Dispatcher.Invoke(() => { contentPanel.Children.Clear(); contentPanel.Children.Add(control); }); Logger.Debug($"SwitchVisiable End {activeDoc?.GetPathName()} {(DateTime.Now - start).TotalMilliseconds}ms."); } public void SetSwApp(SldWorks SwApp) { this.SwApp = SwApp; } private void SaveDoc(bool qiaoqiaode) { int errors = 0, warnings = 0; if ((ActiveOpter as IPropertyOpt).SaveDoc(ref errors, ref warnings)) { // if (!qiaoqiaode) this.Info("保存成功"); } } private void SaveButton_Click(object sender, RoutedEventArgs e) { try { if (ReadDoc == null) { return; } SaveDoc(false); } catch (Exception ex) { Logger.Error($"Property Setting Save Doc Error!", ex); this.Error($"保存失败!{ex.Message}"); } } public void RefreshData() { MaskAdorner.ShowMask(content, "属性加载中,请稍候..."); var start = DateTime.Now; Logger.Debug($"Refresh [{ReadDocPath}] Data start."); Task.Run(() => { try { UpdateActiveDoc(); } catch (COMException come) { // 频繁关闭会抛出这个异常,不管了 Logger.Warn("Read property COMObject failed.", come); } catch (Exception ex) { Logger.Error($"读取参数异常,文件:[{ReadDocPath}]!", ex); this.Error($"读取参数异常:{ex.Message}"); } finally { MaskAdorner.HideMask(content); Logger.Debug($"Refresh [{ReadDocPath}] Data end {(DateTime.Now - start).TotalMilliseconds}ms."); } }); } private void Refresh_Click(object sender, RoutedEventArgs e) { RefreshData(); } private void LoadComboBox_Click(object sender, RoutedEventArgs e) { MaskAdorner.ShowMask(content, "加载MES设置,请稍候..."); Task.Run(() => { try { LoadComboxItemSource(); } finally { MaskAdorner.HideMask(content); } }); } private void PropertySettingControl_Initialized(object sender, EventArgs e) { InitPropertyData(); } /// /// 激活的文档变更触发 /// /// /// /// public void OnSwActiveDocChange(ModelDoc2 lastDoc, ModelDoc2 doc, Component2 comp) { RefreshData(); } public void OnSwActiveDocSaved(ModelDoc2 doc, Component2 comp) { // 读取文件,设置参数 // LoadDocProperties(); } public void OnCustomPropertyChange(string propName, string Configuration, string oldValue, string NewValue, int valueType) { try { if (oldValue == NewValue) { return; } IPropertyOpt opt = ActiveOpter as IPropertyOpt; opt.UpdateSingleProperty(propName, NewValue); } catch (Exception ex) { Logger.Error("Property Setting OnCustomPropertyChange Error!", ex); this.Error($"属性变更异常!{ex.Message}"); } } public void OnDocDestroy(ModelDoc2 doc) { } public void AfterDocDestroy() { } /// /// 判断是否需要弹窗提示保存 /// public void AlertSaveWindow() { var start = DateTime.Now; Logger.Debug("AlertSaveWindow Start..."); IPropertyOpt opt = ActiveOpter as IPropertyOpt; if (opt != null && opt.GetDocChanged()) { // 历史文档直接重置 string fullName = Path.GetFileName(ReadDocPath); if (NameUtil.IsHistoryDoc(fullName)) { opt.ResetProperty(out string errMsg); return; } string Message = $"{fullName}属性发生变更,是否保存?"; if (SwApp.SendMsgToUser2(Message, (int)swMessageBoxIcon_e.swMbWarning , (int)swMessageBoxBtn_e.swMbYesNo) == (int)swMessageBoxResult_e.swMbHitYes) { SaveDoc(true); } else { opt.ResetProperty(out string errMsg); } } Logger.Debug($"AlertSaveWindow End {activeDoc?.GetPathName()} {(DateTime.Now - start).TotalMilliseconds}ms."); } public void OnTabControlSelectionChange(object sender, SelectionChangedEventArgs e) { try { if (e.RemovedItems == null) { return; } foreach (object obj in e.RemovedItems) { if (obj is TabItem item) { if (item.Content == this) { AlertSaveWindow(); break; } } else { return; } } } catch (Exception ex) { Logger.Error($"Property Setting OnTabControlSelectionChange Error!", ex); this.Error($"{ex.Message}"); } } public void DisabledHandler() { if (activeDoc != null) { DetachDocNotify(activeDoc); } } } }