From fbf913f9adb396ded4127aae61116524c3a330bb Mon Sep 17 00:00:00 2001 From: JiahaiWu Date: Thu, 29 Jan 2015 14:44:02 +0800 Subject: [PATCH] Update CRLF --- IDCM/IDCM.Data.Base/IDCMViewException.cs | 172 +- IDCM/IDCM.Service.Common/GCMSiteMHub.cs | 258 +-- .../BGHandler/UpdateHomeDataViewHandler.cs | 256 +-- .../BGHandler/XMLExportHandler.cs | 128 +- .../DataTransfer/ExcelDataImporter.cs | 228 +- IDCM/IDCM.Service/DataTransfer/XMLExporter.cs | 220 +- IDCM/IDCM.Service/Utils/ControlAsyncUtil.cs | 300 +-- IDCM/IDCM/Core/DataSourceHolder.cs | 322 +-- IDCM/IDCM/Forms/HomeView.cs | 1480 ++++++------- IDCM/IDCM/Forms/IDCMForm.cs | 532 ++--- IDCM/IDCM/Modules/LocalDataSetBuilder.cs | 1866 ++++++++--------- IDCM/IDCM/ViewManager/GCMViewManager.cs | 378 ++-- IDCM/IDCM/ViewManager/HomeViewManager.cs | 896 ++++---- IDCM/IDCM/ViewManager/IDCMFormManger.cs | 816 +++---- IDCM/IDCM/ViewManager/StartRetainer.cs | 328 +-- IDCM/dgmls/IDCM_outline.dgml | 1568 +++++++------- ...0\345\210\206\345\233\276\344\276\213.vsd" | Bin 0 -> 200192 bytes 17 files changed, 4874 insertions(+), 4874 deletions(-) create mode 100644 "IDCM/docs/\347\263\273\347\273\237\350\256\276\350\256\241\351\203\250\345\210\206\345\233\276\344\276\213.vsd" diff --git a/IDCM/IDCM.Data.Base/IDCMViewException.cs b/IDCM/IDCM.Data.Base/IDCMViewException.cs index 3eea716..f3cc8b5 100644 --- a/IDCM/IDCM.Data.Base/IDCMViewException.cs +++ b/IDCM/IDCM.Data.Base/IDCMViewException.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.Serialization; - -namespace IDCM.Data.Base -{ - [Serializable] - public class IDCMViewException:IDCMException,ISerializable - { - // 摘要: - // 初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 - protected IDCMViewException() - : base() - { - } - // - // 摘要: - // 使用指定的错误消息初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 - // - // 参数: - // message: - // 为此异常显示的消息。 - public IDCMViewException(string message):base(message) - { - } - // - // 摘要: - // 用指定的序列化信息和上下文初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 - // - // 参数: - // info: - // System.Runtime.Serialization.SerializationInfo,它存有有关所引发异常的序列化的对象数据。 - // - // context: - // System.Runtime.Serialization.StreamingContext,它包含有关源或目标的上下文信息。 - public IDCMViewException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - // - // 摘要: - // 使用指定的错误消息和对导致此异常的内部异常的引用初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 - // - // 参数: - // message: - // 错误消息字符串。 - // - // innerException: - // 内部异常引用。 - public IDCMViewException(string message, Exception innerException) - : base(message, innerException) - { - } - // - // 摘要: - // 使用指定的错误消息和错误代码初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 - // - // 参数: - // message: - // 解释异常原因的错误消息。 - // - // errorCode: - // 异常的错误代码。 - public IDCMViewException(string message, int errorCode) - : base(message, errorCode) - { - } - - // 摘要: - // Adds extra information to the serialized object data specific to this class - // type. This is only used for serialization. - // - // 参数: - // info: - // Holds the serialized object data about the exception being thrown. - // - // context: - // Contains contextual information about the source or destination. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace IDCM.Data.Base +{ + [Serializable] + public class IDCMViewException:IDCMException,ISerializable + { + // 摘要: + // 初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 + protected IDCMViewException() + : base() + { + } + // + // 摘要: + // 使用指定的错误消息初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 + // + // 参数: + // message: + // 为此异常显示的消息。 + public IDCMViewException(string message):base(message) + { + } + // + // 摘要: + // 用指定的序列化信息和上下文初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 + // + // 参数: + // info: + // System.Runtime.Serialization.SerializationInfo,它存有有关所引发异常的序列化的对象数据。 + // + // context: + // System.Runtime.Serialization.StreamingContext,它包含有关源或目标的上下文信息。 + public IDCMViewException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + // + // 摘要: + // 使用指定的错误消息和对导致此异常的内部异常的引用初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 + // + // 参数: + // message: + // 错误消息字符串。 + // + // innerException: + // 内部异常引用。 + public IDCMViewException(string message, Exception innerException) + : base(message, innerException) + { + } + // + // 摘要: + // 使用指定的错误消息和错误代码初始化 IDCM.Data.Base.IDCMViewException 类的新实例。 + // + // 参数: + // message: + // 解释异常原因的错误消息。 + // + // errorCode: + // 异常的错误代码。 + public IDCMViewException(string message, int errorCode) + : base(message, errorCode) + { + } + + // 摘要: + // Adds extra information to the serialized object data specific to this class + // type. This is only used for serialization. + // + // 参数: + // info: + // Holds the serialized object data about the exception being thrown. + // + // context: + // Contains contextual information about the source or destination. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + } + } +} diff --git a/IDCM/IDCM.Service.Common/GCMSiteMHub.cs b/IDCM/IDCM.Service.Common/GCMSiteMHub.cs index 491c6a3..10ab4f8 100644 --- a/IDCM/IDCM.Service.Common/GCMSiteMHub.cs +++ b/IDCM/IDCM.Service.Common/GCMSiteMHub.cs @@ -1,129 +1,129 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using IDCM.Data; -using IDCM.Service.Common.GCMDAM; -using IDCM.Data.Base; -using IDCM.Data.Base.Utils; -/******************************** - * Individual Data Center of Microbial resources (IDCM) - * A desktop software package for microbial resources researchers. - * - * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - * - * @Contact NO.1 Beichen West Road, Chaoyang District, Beijing 100101, Email: office@im.ac.cn - */ -namespace IDCM.Service.Common -{ - /// - /// GCM网站授权资源管理集线器类 - /// 说明: - /// 1.本实现类主要支持访问GCM的用户身份保持与连接状态保持. - /// - public class GCMSiteMHub - { - /// - /// 构造方法 - /// - /// GCM ID - /// GCM Password - /// - public GCMSiteMHub(string loginName, string gcmPassword, bool autoLogin = true) - { - this.authInfo = new AuthInfo(); - authInfo.Username = loginName; - authInfo.Password = gcmPassword; - authInfo.autoLogin = autoLogin; - } - /// - /// Connect GCM server with specific Login Name and password. - /// - /// - public bool connect(int timeout = 10000) - { - AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin, timeout); - if (auth != null && auth.autoLogin) - { - signMonitor = new System.Windows.Forms.Timer(); - signMonitor.Interval = 600000; - signMonitor.Tick += OnSignInHold; - signMonitor.Start(); - new System.Threading.Thread(delegate() { OnSignInHold(null, null); }).Start(); - } - return auth != null && auth.LoginFlag; - } - /// - /// 登录状态验证与保持 - /// - /// - /// - private void OnSignInHold(object sender, EventArgs e) - { -#if DEBUG - Console.WriteLine("* Sign in hold For Login()"); -#endif - if (authInfo != null && authInfo.autoLogin && authInfo.Username != null && authInfo.Password != null) - { - AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin); - authInfo.LoginFlag = auth.LoginFlag; - authInfo.Jsessionid = auth.Jsessionid; - authInfo.Timestamp = auth.Timestamp; - string tip = authInfo.LoginFlag ? authInfo.Username : null; - DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); - } - } - /// - /// 获取有效登录用户身份信息,如果登录状态无效则返回null - /// - /// - public AuthInfo getSignedAuthInfo() - { - if (authInfo != null) - { - long elapsedTicks = DateTime.Now.Ticks - authInfo.Timestamp; - TimeSpan elapsedSpan = new TimeSpan(elapsedTicks); - if (elapsedSpan.TotalMinutes > 15) - { - if (authInfo.Username != null && authInfo.Password != null) - { - AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin, 3000); - authInfo.LoginFlag = auth.LoginFlag; - authInfo.Jsessionid = auth.Jsessionid; - authInfo.Timestamp = auth.Timestamp; - string tip = authInfo.LoginFlag ? authInfo.Username : null; - DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); - } - } - return (authInfo != null && authInfo.LoginFlag) ? authInfo : null; - } - return null; - } - /// - /// 关闭用户工作空间 - /// - /// - public bool disconnect(bool cancelDefaultWorkSpace=false) - { - if (signMonitor != null) - { - signMonitor.Stop(); - signMonitor = null; - SignExecutor.SignOff(authInfo); - string tip = authInfo.LoginFlag ? authInfo.Username : null; - DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); - } - if (cancelDefaultWorkSpace) - { - ConfigurationHelper.SetAppConfig(SysConstants.LWSAsDefault, "False"); - } - return true; - } - - /// - /// SignIn hold Monitor - /// - private System.Windows.Forms.Timer signMonitor = null; - private readonly AuthInfo authInfo = null; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using IDCM.Data; +using IDCM.Service.Common.GCMDAM; +using IDCM.Data.Base; +using IDCM.Data.Base.Utils; +/******************************** + * Individual Data Center of Microbial resources (IDCM) + * A desktop software package for microbial resources researchers. + * + * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + * + * @Contact NO.1 Beichen West Road, Chaoyang District, Beijing 100101, Email: office@im.ac.cn + */ +namespace IDCM.Service.Common +{ + /// + /// GCM网站授权资源管理集线器类 + /// 说明: + /// 1.本实现类主要支持访问GCM的用户身份保持与连接状态保持. + /// + public class GCMSiteMHub + { + /// + /// 构造方法 + /// + /// GCM ID + /// GCM Password + /// + public GCMSiteMHub(string loginName, string gcmPassword, bool autoLogin = true) + { + this.authInfo = new AuthInfo(); + authInfo.Username = loginName; + authInfo.Password = gcmPassword; + authInfo.autoLogin = autoLogin; + } + /// + /// Connect GCM server with specific Login Name and password. + /// + /// + public bool connect(int timeout = 10000) + { + AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin, timeout); + if (auth != null && auth.autoLogin) + { + signMonitor = new System.Windows.Forms.Timer(); + signMonitor.Interval = 600000; + signMonitor.Tick += OnSignInHold; + signMonitor.Start(); + new System.Threading.Thread(delegate() { OnSignInHold(null, null); }).Start(); + } + return auth != null && auth.LoginFlag; + } + /// + /// 登录状态验证与保持 + /// + /// + /// + private void OnSignInHold(object sender, EventArgs e) + { +#if DEBUG + Console.WriteLine("* Sign in hold For Login()"); +#endif + if (authInfo != null && authInfo.autoLogin && authInfo.Username != null && authInfo.Password != null) + { + AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin); + authInfo.LoginFlag = auth.LoginFlag; + authInfo.Jsessionid = auth.Jsessionid; + authInfo.Timestamp = auth.Timestamp; + string tip = authInfo.LoginFlag ? authInfo.Username : null; + DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); + } + } + /// + /// 获取有效登录用户身份信息,如果登录状态无效则返回null + /// + /// + public AuthInfo getSignedAuthInfo() + { + if (authInfo != null) + { + long elapsedTicks = DateTime.Now.Ticks - authInfo.Timestamp; + TimeSpan elapsedSpan = new TimeSpan(elapsedTicks); + if (elapsedSpan.TotalMinutes > 15) + { + if (authInfo.Username != null && authInfo.Password != null) + { + AuthInfo auth = SignExecutor.SignIn(authInfo.Username, authInfo.Password, authInfo.autoLogin, 3000); + authInfo.LoginFlag = auth.LoginFlag; + authInfo.Jsessionid = auth.Jsessionid; + authInfo.Timestamp = auth.Timestamp; + string tip = authInfo.LoginFlag ? authInfo.Username : null; + DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); + } + } + return (authInfo != null && authInfo.LoginFlag) ? authInfo : null; + } + return null; + } + /// + /// 关闭用户工作空间 + /// + /// + public bool disconnect(bool cancelDefaultWorkSpace=false) + { + if (signMonitor != null) + { + signMonitor.Stop(); + signMonitor = null; + SignExecutor.SignOff(authInfo); + string tip = authInfo.LoginFlag ? authInfo.Username : null; + DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); + } + if (cancelDefaultWorkSpace) + { + ConfigurationHelper.SetAppConfig(SysConstants.LWSAsDefault, "False"); + } + return true; + } + + /// + /// SignIn hold Monitor + /// + private System.Windows.Forms.Timer signMonitor = null; + private readonly AuthInfo authInfo = null; + } +} diff --git a/IDCM/IDCM.Service/BGHandler/UpdateHomeDataViewHandler.cs b/IDCM/IDCM.Service/BGHandler/UpdateHomeDataViewHandler.cs index e6d0a0f..3d35f75 100644 --- a/IDCM/IDCM.Service/BGHandler/UpdateHomeDataViewHandler.cs +++ b/IDCM/IDCM.Service/BGHandler/UpdateHomeDataViewHandler.cs @@ -1,128 +1,128 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using System.ComponentModel; -using System.Data; -using IDCM.Data.Base; -using IDCM.Service.Utils; -using IDCM.Service.Common; - -namespace IDCM.Service.BGHandler -{ - /// - /// 根据选中节点更新数据表记录显示 - /// - public class UpdateHomeDataViewHandler:AbsHandler - { - /// - /// 指定查询的节点和目标数据表单,以及是否指定快速失效模式 - /// - /// - /// - /// - public UpdateHomeDataViewHandler(DataSourceMHub datasource,TreeNode filterNode,DataGridView dgv,bool failFast=true) - { - this.filterNode = filterNode; - this.dgv = dgv; - this.failFast = failFast; - this.datasource = datasource; - } - /// - /// 后台任务执行方法的主体部分,异步执行代码段! - /// - /// - /// - public override Object doWork(BackgroundWorker worker, bool cancel, List args) - { - bool res = false; - DWorkMHub.note(AsyncMessage.StartBackProgress); - List viewAttrs = LocalRecordMHub.getViewAttrs(datasource); - long lid = Convert.ToInt64(filterNode.Name); - DGVAsyncUtil.syncRemoveAllRow(dgv); - string filterLids = lid.ToString(); - if (lid > 0) - { - long[] lids = LocalRecordMHub.extractToLids(datasource, lid); - if (lids != null) - { - filterLids = ""; - foreach (long _lid in lids) - { - filterLids += "," + _lid; - } - filterLids = filterLids.Substring(1); - } - } - string cmdstr = null; - //数据查询与装载 - DataTable records = LocalRecordMHub.queryCTDRecord(datasource, filterLids, null, out cmdstr); - LocalRecordMHub.cacheDGVQuery(cmdstr, records.Rows.Count); - if (records != null && records.Rows.Count > 0) - { - foreach (DataRow dr in records.Rows) - { - loadCTableData(dr, viewAttrs); - } - } - res = true; - return new object[] { res}; - } - /// - /// 转换数据对象值到列表显示 - /// - /// - /// - protected void loadCTableData(DataRow dr, List viewAttrs) - { - string[] vals = new string[viewAttrs.Count+1]; - vals[0] = false.ToString(); - int index = 1; - foreach (string attr in viewAttrs) - { -#if DEBUG - //log.Debug("(loadCTableData) " + attr + "-->" + LocalRecordMHub.getDBOrder(datasource, attr) + ">>" + dr[LocalRecordMHub.getDBOrder(datasource, attr)].ToString()); -#endif - vals[index] = dr[LocalRecordMHub.getDBOrder(datasource,attr)].ToString(); - ++index; - } - //////////////////////////////////////////////////// - //注意: - //如何针对不同类型的DGVCell的设定值显示,有待进一步考虑。 - ////////////////////////////////////////////////////////// - DGVAsyncUtil.syncAddRow(dgv, vals); - } - /// - /// 后台任务执行结束,回调代码段 - /// - /// - /// - public override void complete(BackgroundWorker worker, bool canceled, Exception error, List args) - { - DWorkMHub.note(AsyncMessage.EndBackProgress); - if (canceled || (args.Count>0 && args[0].Equals(false))) - { - if(nextHandlers!=null) - nextHandlers.Clear(); - return; - } - if (error != null) - { - MessageBox.Show("ERROR::" + error.Message + "\n" + error.StackTrace); - nextHandlers.Clear(); - return; - } - } - - public override void addHandler(AbsHandler nextHandler) - { - base.addHandler(nextHandler); - } - - private TreeNode filterNode; - private DataGridView dgv; - private DataSourceMHub datasource; - private bool failFast = true; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.ComponentModel; +using System.Data; +using IDCM.Data.Base; +using IDCM.Service.Utils; +using IDCM.Service.Common; + +namespace IDCM.Service.BGHandler +{ + /// + /// 根据选中节点更新数据表记录显示 + /// + public class UpdateHomeDataViewHandler:AbsHandler + { + /// + /// 指定查询的节点和目标数据表单,以及是否指定快速失效模式 + /// + /// + /// + /// + public UpdateHomeDataViewHandler(DataSourceMHub datasource,TreeNode filterNode,DataGridView dgv,bool failFast=true) + { + this.filterNode = filterNode; + this.dgv = dgv; + this.failFast = failFast; + this.datasource = datasource; + } + /// + /// 后台任务执行方法的主体部分,异步执行代码段! + /// + /// + /// + public override Object doWork(BackgroundWorker worker, bool cancel, List args) + { + bool res = false; + DWorkMHub.note(AsyncMessage.StartBackProgress); + List viewAttrs = LocalRecordMHub.getViewAttrs(datasource); + long lid = Convert.ToInt64(filterNode.Name); + DGVAsyncUtil.syncRemoveAllRow(dgv); + string filterLids = lid.ToString(); + if (lid > 0) + { + long[] lids = LocalRecordMHub.extractToLids(datasource, lid); + if (lids != null) + { + filterLids = ""; + foreach (long _lid in lids) + { + filterLids += "," + _lid; + } + filterLids = filterLids.Substring(1); + } + } + string cmdstr = null; + //数据查询与装载 + DataTable records = LocalRecordMHub.queryCTDRecord(datasource, filterLids, null, out cmdstr); + LocalRecordMHub.cacheDGVQuery(cmdstr, records.Rows.Count); + if (records != null && records.Rows.Count > 0) + { + foreach (DataRow dr in records.Rows) + { + loadCTableData(dr, viewAttrs); + } + } + res = true; + return new object[] { res}; + } + /// + /// 转换数据对象值到列表显示 + /// + /// + /// + protected void loadCTableData(DataRow dr, List viewAttrs) + { + string[] vals = new string[viewAttrs.Count+1]; + vals[0] = false.ToString(); + int index = 1; + foreach (string attr in viewAttrs) + { +#if DEBUG + //log.Debug("(loadCTableData) " + attr + "-->" + LocalRecordMHub.getDBOrder(datasource, attr) + ">>" + dr[LocalRecordMHub.getDBOrder(datasource, attr)].ToString()); +#endif + vals[index] = dr[LocalRecordMHub.getDBOrder(datasource,attr)].ToString(); + ++index; + } + //////////////////////////////////////////////////// + //注意: + //如何针对不同类型的DGVCell的设定值显示,有待进一步考虑。 + ////////////////////////////////////////////////////////// + DGVAsyncUtil.syncAddRow(dgv, vals); + } + /// + /// 后台任务执行结束,回调代码段 + /// + /// + /// + public override void complete(BackgroundWorker worker, bool canceled, Exception error, List args) + { + DWorkMHub.note(AsyncMessage.EndBackProgress); + if (canceled || (args.Count>0 && args[0].Equals(false))) + { + if(nextHandlers!=null) + nextHandlers.Clear(); + return; + } + if (error != null) + { + MessageBox.Show("ERROR::" + error.Message + "\n" + error.StackTrace); + nextHandlers.Clear(); + return; + } + } + + public override void addHandler(AbsHandler nextHandler) + { + base.addHandler(nextHandler); + } + + private TreeNode filterNode; + private DataGridView dgv; + private DataSourceMHub datasource; + private bool failFast = true; + } +} diff --git a/IDCM/IDCM.Service/BGHandler/XMLExportHandler.cs b/IDCM/IDCM.Service/BGHandler/XMLExportHandler.cs index 83034f6..bc9309d 100644 --- a/IDCM/IDCM.Service/BGHandler/XMLExportHandler.cs +++ b/IDCM/IDCM.Service/BGHandler/XMLExportHandler.cs @@ -1,64 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.ComponentModel; -using IDCM.Data.Base; -using IDCM.Service.Utils; -using IDCM.Service.DataTransfer; -using IDCM.Service.Common; -using System.Windows.Forms; - -namespace IDCM.Service.BGHandler -{ - public class XMLExportHandler:AbsHandler - { - public XMLExportHandler(DataSourceMHub datasource, string fpath, string cmdstr, int tcount, string spliter = " ") - { - this.textPath = System.IO.Path.GetFullPath(fpath); - this.cmdstr = cmdstr; - this.tcount = tcount; - this.spliter = spliter; - this.datasource = datasource; - } - /// - /// 后台任务执行方法的主体部分,异步执行代码段! - /// - /// - /// - public override Object doWork(BackgroundWorker worker, bool cancel, List args) - { - bool res=false; - DWorkMHub.note(AsyncMessage.StartBackProgress); - XMLExporter exporter = new XMLExporter(); - res = exporter.exportXML(datasource, textPath, cmdstr, tcount, spliter); - return new object[] { res}; - } - /// - /// 后台任务执行结束,回调代码段 - /// - /// - /// - public override void complete(BackgroundWorker worker, bool canceled, Exception error, List args) - { - DWorkMHub.note(AsyncMessage.EndBackProgress); - if (canceled) - return; - if (error != null) - { - MessageBox.Show("ERROR::" + error.Message + "\n" + error.StackTrace); - return; - } - else - { - MessageBox.Show("Export success. @filepath=" + textPath); - } - } - - private string spliter = null; - private string textPath = null; - private string cmdstr=null; - private int tcount = 0; - private DataSourceMHub datasource=null; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel; +using IDCM.Data.Base; +using IDCM.Service.Utils; +using IDCM.Service.DataTransfer; +using IDCM.Service.Common; +using System.Windows.Forms; + +namespace IDCM.Service.BGHandler +{ + public class XMLExportHandler:AbsHandler + { + public XMLExportHandler(DataSourceMHub datasource, string fpath, string cmdstr, int tcount, string spliter = " ") + { + this.textPath = System.IO.Path.GetFullPath(fpath); + this.cmdstr = cmdstr; + this.tcount = tcount; + this.spliter = spliter; + this.datasource = datasource; + } + /// + /// 后台任务执行方法的主体部分,异步执行代码段! + /// + /// + /// + public override Object doWork(BackgroundWorker worker, bool cancel, List args) + { + bool res=false; + DWorkMHub.note(AsyncMessage.StartBackProgress); + XMLExporter exporter = new XMLExporter(); + res = exporter.exportXML(datasource, textPath, cmdstr, tcount, spliter); + return new object[] { res}; + } + /// + /// 后台任务执行结束,回调代码段 + /// + /// + /// + public override void complete(BackgroundWorker worker, bool canceled, Exception error, List args) + { + DWorkMHub.note(AsyncMessage.EndBackProgress); + if (canceled) + return; + if (error != null) + { + MessageBox.Show("ERROR::" + error.Message + "\n" + error.StackTrace); + return; + } + else + { + MessageBox.Show("Export success. @filepath=" + textPath); + } + } + + private string spliter = null; + private string textPath = null; + private string cmdstr=null; + private int tcount = 0; + private DataSourceMHub datasource=null; + } +} diff --git a/IDCM/IDCM.Service/DataTransfer/ExcelDataImporter.cs b/IDCM/IDCM.Service/DataTransfer/ExcelDataImporter.cs index 2a68399..a8694a3 100644 --- a/IDCM/IDCM.Service/DataTransfer/ExcelDataImporter.cs +++ b/IDCM/IDCM.Service/DataTransfer/ExcelDataImporter.cs @@ -1,114 +1,114 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data; -using System.Collections; -using System.Data.OleDb; -using System.Threading; -using NPOI.XSSF.UserModel; -using NPOI.HSSF.UserModel; -using NPOI.SS.UserModel; -using System.IO; -using System.Windows.Forms; -using IDCM.Data.Base; -using IDCM.Data.Base.Utils; -using IDCM.Service.Common; - -namespace IDCM.Service.DataTransfer -{ - class ExcelDataImporter - { - /// - /// 解析指定的Excel文档,执行数据转换. - /// 本方法调用对类功能予以线程包装,用于异步调用如何方法。 - /// 在本线程调用下的控件调用,需通过UI控件的Invoke/BegainInvoke方法更新。 - /// - /// - /// 返回请求流程是否执行完成 - public static bool parseExcelData(DataSourceMHub datasource, string fpath, ref Dictionary dataMapping, long lid, long plid) - { - if (fpath == null || fpath.Length < 1) - return false; - string fullPath = System.IO.Path.GetFullPath(fpath); - IWorkbook workbook = null; - try - { - using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) - { - workbook = WorkbookFactory.Create(fs); - ISheet dataSheet = workbook.GetSheet("Core Datasets"); - if (dataSheet == null) - dataSheet = workbook.GetSheetAt(0); - parseSheetInfo(datasource,dataSheet, ref dataMapping, Convert.ToString(lid, 10), Convert.ToString(plid, 10)); - } - } - catch (Exception ex) - { - log.Info("ERROR: Excel文件导入失败! ", ex); - MessageBox.Show("ERROR: Excel文件导入失败! " + ex.Message + "\n" + ex.StackTrace); - } - return true; - } - /// - /// 通过NPOI读取Excel文档,转换可识别内容至本地数据库中 - /// - /// - /// - public static void parseSheetInfo(DataSourceMHub datasource, ISheet sheet, ref Dictionary dataMapping, string lid, string plid) - { - int skipIdx = 1; - if (sheet == null || sheet.LastRowNum < skipIdx) //no data - return; - ///////////////////////////////////////////////////////// - IRow titleRow = sheet.GetRow(skipIdx - 1); - int columnSize = titleRow.LastCellNum; - int rowSize = sheet.LastRowNum; - List xlscols = new List(columnSize); - for (int i = titleRow.FirstCellNum; i < columnSize; i++) - { - ICell titleCell = titleRow.GetCell(i); - if (titleCell != null && titleCell.ToString().Length > 0) - { - string cellData = titleCell.ToString(); - xlscols.Add(CVNameConverter.toViewName(cellData.Trim().ToLower())); - } - else - { - xlscols.Add(null); - } - } - /////////////////////////////////////////////////////////////// - if (dataMapping!=null && dataMapping.Count > 0) - { - for (int i = skipIdx; i <= rowSize; ++i) - { - IRow row = sheet.GetRow(i); - if (row == null) continue; //没有数据的行默认是null  - ICell headCell = row.GetCell(row.FirstCellNum); - if (headCell == null || headCell.ToString().Length == 0 || headCell.ToString().Equals("end!")) - break; - Dictionary mapValues = new Dictionary(); - for (int j = row.FirstCellNum; j < columnSize; j++) - { - if (row.GetCell(j) != null && xlscols[j] != null) - { - string cellData = row.GetCell(j).ToString().Trim(); - string mapName = null; - dataMapping.TryGetValue(xlscols[j], out mapName); - if (mapName != null) - { - mapValues[mapName] = cellData; - } - } - } - mapValues[CTDRecordA.CTD_LID] = lid; - mapValues[CTDRecordA.CTD_PLID] = plid; - long nuid = LocalRecordMHub.mergeRecord(datasource,mapValues); - } - } - } - - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using System.Collections; +using System.Data.OleDb; +using System.Threading; +using NPOI.XSSF.UserModel; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using System.IO; +using System.Windows.Forms; +using IDCM.Data.Base; +using IDCM.Data.Base.Utils; +using IDCM.Service.Common; + +namespace IDCM.Service.DataTransfer +{ + class ExcelDataImporter + { + /// + /// 解析指定的Excel文档,执行数据转换. + /// 本方法调用对类功能予以线程包装,用于异步调用如何方法。 + /// 在本线程调用下的控件调用,需通过UI控件的Invoke/BegainInvoke方法更新。 + /// + /// + /// 返回请求流程是否执行完成 + public static bool parseExcelData(DataSourceMHub datasource, string fpath, ref Dictionary dataMapping, long lid, long plid) + { + if (fpath == null || fpath.Length < 1) + return false; + string fullPath = System.IO.Path.GetFullPath(fpath); + IWorkbook workbook = null; + try + { + using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) + { + workbook = WorkbookFactory.Create(fs); + ISheet dataSheet = workbook.GetSheet("Core Datasets"); + if (dataSheet == null) + dataSheet = workbook.GetSheetAt(0); + parseSheetInfo(datasource,dataSheet, ref dataMapping, Convert.ToString(lid, 10), Convert.ToString(plid, 10)); + } + } + catch (Exception ex) + { + log.Info("ERROR: Excel文件导入失败! ", ex); + MessageBox.Show("ERROR: Excel文件导入失败! " + ex.Message + "\n" + ex.StackTrace); + } + return true; + } + /// + /// 通过NPOI读取Excel文档,转换可识别内容至本地数据库中 + /// + /// + /// + public static void parseSheetInfo(DataSourceMHub datasource, ISheet sheet, ref Dictionary dataMapping, string lid, string plid) + { + int skipIdx = 1; + if (sheet == null || sheet.LastRowNum < skipIdx) //no data + return; + ///////////////////////////////////////////////////////// + IRow titleRow = sheet.GetRow(skipIdx - 1); + int columnSize = titleRow.LastCellNum; + int rowSize = sheet.LastRowNum; + List xlscols = new List(columnSize); + for (int i = titleRow.FirstCellNum; i < columnSize; i++) + { + ICell titleCell = titleRow.GetCell(i); + if (titleCell != null && titleCell.ToString().Length > 0) + { + string cellData = titleCell.ToString(); + xlscols.Add(CVNameConverter.toViewName(cellData.Trim().ToLower())); + } + else + { + xlscols.Add(null); + } + } + /////////////////////////////////////////////////////////////// + if (dataMapping!=null && dataMapping.Count > 0) + { + for (int i = skipIdx; i <= rowSize; ++i) + { + IRow row = sheet.GetRow(i); + if (row == null) continue; //没有数据的行默认是null  + ICell headCell = row.GetCell(row.FirstCellNum); + if (headCell == null || headCell.ToString().Length == 0 || headCell.ToString().Equals("end!")) + break; + Dictionary mapValues = new Dictionary(); + for (int j = row.FirstCellNum; j < columnSize; j++) + { + if (row.GetCell(j) != null && xlscols[j] != null) + { + string cellData = row.GetCell(j).ToString().Trim(); + string mapName = null; + dataMapping.TryGetValue(xlscols[j], out mapName); + if (mapName != null) + { + mapValues[mapName] = cellData; + } + } + } + mapValues[CTDRecordA.CTD_LID] = lid; + mapValues[CTDRecordA.CTD_PLID] = plid; + long nuid = LocalRecordMHub.mergeRecord(datasource,mapValues); + } + } + } + + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + } +} diff --git a/IDCM/IDCM.Service/DataTransfer/XMLExporter.cs b/IDCM/IDCM.Service/DataTransfer/XMLExporter.cs index ba5afe5..7397791 100644 --- a/IDCM/IDCM.Service/DataTransfer/XMLExporter.cs +++ b/IDCM/IDCM.Service/DataTransfer/XMLExporter.cs @@ -1,110 +1,110 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data; -using IDCM.Data.Base; -using IDCM.Data.Base.Utils; -using IDCM.Data; -using IDCM.Service.Common; -using System.IO; -using System.Windows.Forms; - -namespace IDCM.Service.DataTransfer -{ - class XMLExporter - { - /// - /// 根据历史查询条件导出目标文本数据集 - /// @author JiahaiWu - /// 通过getValidViewDBMapping()方法获取已经被缓存的用户浏览字段~数据库字段位序的映射关系; - /// 然后对历史查询条件进行限定批量长度的轮询和导出转换操作。 - /// 本数据导出方式使用静态分隔符策略。 - /// 请注意对存储数据值中存在等同分隔符情形,尚未考虑额外处理策略,使用不当将造成导出不规范的数据文件。 - /// @note 更进一步支持转移字符转换的模式有待补充。 - /// - /// - /// - /// - /// - /// - public bool exportXML(DataSourceMHub datasource, string filepath, string cmdstr, int tcount, string spliter = " ") - { - try - { - StringBuilder strbuilder = new StringBuilder(); - //int count = 0; - //using (FileStream fs = new FileStream(filepath, FileMode.Create)) - //{ - // Dictionary maps = LocalRecordMHub.getCustomViewDBMapping(datasource); - // //填写表头 - // int i = 0; - // string key = null; - // for (i = 0; i < maps.Count - 1; i++) - // { - // key = CVNameConverter.toViewName(maps.ElementAt(i).Key); - // strbuilder.Append(key).Append(spliter); - // } - // key = CVNameConverter.toViewName(maps.ElementAt(i).Key); - // strbuilder.Append(key); - // //填写内容//////////////////// - // int offset = 0; - // int stepLen = SysConstants.EXPORT_PAGING_COUNT; - // while (offset < tcount) - // { - // int lcount = tcount - offset > stepLen ? stepLen : tcount - offset; - // DataTable table = LocalRecordMHub.queryCTDRecordByHistSQL(datasource, cmdstr, lcount, offset); - // foreach (DataRow row in table.Rows) - // { - // string dataLine = convertToXML(maps, row, spliter); - // strbuilder.Append("\n\r").Append(dataLine); - // ///////////// - // if (++count % 100 == 0) - // { - // Byte[] info = new UTF8Encoding(true).GetBytes(strbuilder.ToString()); - // BinaryWriter bw = new BinaryWriter(fs); - // fs.Write(info, 0, info.Length); - // strbuilder.Length = 0; - // } - // } - // if (strbuilder.Length > 0) - // { - // Byte[] info = new UTF8Encoding(true).GetBytes(strbuilder.ToString()); - // BinaryWriter bw = new BinaryWriter(fs); - // fs.Write(info, 0, info.Length); - // strbuilder.Length = 0; - // } - // offset += lcount; - // } - // fs.Close(); - //} - } - catch (Exception ex) - { - MessageBox.Show("ERROR::" + ex.Message + "\n" + ex.StackTrace); - log.Error(ex); - return false; - } - return true; - } - private static string convertToXML(Dictionary maps, DataRow row, string spliter) - { - StringBuilder strbuilder = new StringBuilder(); - //int j = 0; - //int idx = -1; - //for (j = 0; j < maps.Count - 1; j++) - //{ - // idx = maps.ElementAt(j).Value; - // idx = idx > SysConstants.Max_Attr_Count ? idx - SysConstants.Max_Attr_Count : idx; - // if (idx >= 0) - // strbuilder.Append(row[idx]).Append(spliter); - //} - //idx = maps.ElementAt(j).Value; - //idx = idx > SysConstants.Max_Attr_Count ? idx - SysConstants.Max_Attr_Count : idx; - //if (idx >= 0) - // strbuilder.Append(row[idx]); - return strbuilder.ToString(); - } - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using IDCM.Data.Base; +using IDCM.Data.Base.Utils; +using IDCM.Data; +using IDCM.Service.Common; +using System.IO; +using System.Windows.Forms; + +namespace IDCM.Service.DataTransfer +{ + class XMLExporter + { + /// + /// 根据历史查询条件导出目标文本数据集 + /// @author JiahaiWu + /// 通过getValidViewDBMapping()方法获取已经被缓存的用户浏览字段~数据库字段位序的映射关系; + /// 然后对历史查询条件进行限定批量长度的轮询和导出转换操作。 + /// 本数据导出方式使用静态分隔符策略。 + /// 请注意对存储数据值中存在等同分隔符情形,尚未考虑额外处理策略,使用不当将造成导出不规范的数据文件。 + /// @note 更进一步支持转移字符转换的模式有待补充。 + /// + /// + /// + /// + /// + /// + public bool exportXML(DataSourceMHub datasource, string filepath, string cmdstr, int tcount, string spliter = " ") + { + try + { + StringBuilder strbuilder = new StringBuilder(); + //int count = 0; + //using (FileStream fs = new FileStream(filepath, FileMode.Create)) + //{ + // Dictionary maps = LocalRecordMHub.getCustomViewDBMapping(datasource); + // //填写表头 + // int i = 0; + // string key = null; + // for (i = 0; i < maps.Count - 1; i++) + // { + // key = CVNameConverter.toViewName(maps.ElementAt(i).Key); + // strbuilder.Append(key).Append(spliter); + // } + // key = CVNameConverter.toViewName(maps.ElementAt(i).Key); + // strbuilder.Append(key); + // //填写内容//////////////////// + // int offset = 0; + // int stepLen = SysConstants.EXPORT_PAGING_COUNT; + // while (offset < tcount) + // { + // int lcount = tcount - offset > stepLen ? stepLen : tcount - offset; + // DataTable table = LocalRecordMHub.queryCTDRecordByHistSQL(datasource, cmdstr, lcount, offset); + // foreach (DataRow row in table.Rows) + // { + // string dataLine = convertToXML(maps, row, spliter); + // strbuilder.Append("\n\r").Append(dataLine); + // ///////////// + // if (++count % 100 == 0) + // { + // Byte[] info = new UTF8Encoding(true).GetBytes(strbuilder.ToString()); + // BinaryWriter bw = new BinaryWriter(fs); + // fs.Write(info, 0, info.Length); + // strbuilder.Length = 0; + // } + // } + // if (strbuilder.Length > 0) + // { + // Byte[] info = new UTF8Encoding(true).GetBytes(strbuilder.ToString()); + // BinaryWriter bw = new BinaryWriter(fs); + // fs.Write(info, 0, info.Length); + // strbuilder.Length = 0; + // } + // offset += lcount; + // } + // fs.Close(); + //} + } + catch (Exception ex) + { + MessageBox.Show("ERROR::" + ex.Message + "\n" + ex.StackTrace); + log.Error(ex); + return false; + } + return true; + } + private static string convertToXML(Dictionary maps, DataRow row, string spliter) + { + StringBuilder strbuilder = new StringBuilder(); + //int j = 0; + //int idx = -1; + //for (j = 0; j < maps.Count - 1; j++) + //{ + // idx = maps.ElementAt(j).Value; + // idx = idx > SysConstants.Max_Attr_Count ? idx - SysConstants.Max_Attr_Count : idx; + // if (idx >= 0) + // strbuilder.Append(row[idx]).Append(spliter); + //} + //idx = maps.ElementAt(j).Value; + //idx = idx > SysConstants.Max_Attr_Count ? idx - SysConstants.Max_Attr_Count : idx; + //if (idx >= 0) + // strbuilder.Append(row[idx]); + return strbuilder.ToString(); + } + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + } +} diff --git a/IDCM/IDCM.Service/Utils/ControlAsyncUtil.cs b/IDCM/IDCM.Service/Utils/ControlAsyncUtil.cs index 0608ac7..8a7cd04 100644 --- a/IDCM/IDCM.Service/Utils/ControlAsyncUtil.cs +++ b/IDCM/IDCM.Service/Utils/ControlAsyncUtil.cs @@ -1,150 +1,150 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using System.Threading; -using System.Reflection; -using IDCM.Data.Base; - -namespace IDCM.Service.Utils -{ - public class ControlAsyncUtil - { - internal delegate void InvokeHandler(); - - internal delegate void InvokeMethodDelegate(Control control, InvokeHandler handler); - /// - /// 为指定的UI控件执行异步操作更新的方法 - /// - /// - /// - /// - internal static void SyncInvoke(Control control, InvokeHandler handler) - { - try - { - // InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread. - // If these threads are different, it returns true. - if (control.InvokeRequired)//如果调用控件的线程和创建创建控件的线程不是同一个则为True - { - while (!control.IsHandleCreated || control.RecreatingHandle) //如果当前控件没有与它关联的句柄或正在重绘中,则等待执行。 - { - //解决窗体关闭时出现“访问已释放句柄“的异常 - if (control.Disposing || control.IsDisposed) - return; - Thread.Sleep(1); - } - IAsyncResult result = control.BeginInvoke(new InvokeMethodDelegate(SyncInvoke), new object[] { control, handler }); - control.EndInvoke(result);//获取委托执行结果的返回值 - } - else - { - IAsyncResult result2 = control.BeginInvoke(handler); - control.EndInvoke(result2); - } - } - catch (Exception ex) - { - log.Error(ex); -#if DEBUG - throw new IDCMViewException("Asynchronous Control Invoke Error.", ex); -#endif - } - } - /// - /// 为指定的UI控件执行异步操作更新的方法 - /// - /// - /// - internal static void SyncInvokeNoWait(Control control, InvokeHandler handler) - { - try{ - if (control.InvokeRequired) - { - //解决窗体关闭时出现“访问已释放句柄“的异常 - if (control.Disposing || control.IsDisposed) - return; - IAsyncResult result = control.BeginInvoke(new InvokeMethodDelegate(SyncInvoke), new object[] { control, handler }); - control.EndInvoke(result);//获取委托执行结果的返回值 - } - else - { - IAsyncResult result2 = control.BeginInvoke(handler); - control.EndInvoke(result2); - } - } - catch (Exception ex) - { - log.Error(ex); -#if DEBUG - throw new IDCMViewException("Asynchronous Control Invoke Error.", ex); -#endif - } - } - - /// - /// 为指定的UI空间执行异步的赋值更新的方法 - /// - /// - /// - /// - public static void SyncInvokeData(Control control, MethodInfo method, Object[] data) - { - SyncInvoke(control, new InvokeHandler(delegate() - { - method.Invoke(control, data); - })); - } - /// - /// 异步调用具有特定方法名称的UI控件方法 - /// - /// - /// - /// - public static void SyncInvokeData(Control control, String methodName, Object data) - { - SyncInvokeData(control, methodName, new Object[] { data }); - } - /// - /// 异步调用具有特定方法名称的UI控件方法 - /// - /// - /// - /// - public static void SyncInvokeData(Control control, String methodName, Object[] data) - { - MethodInfo method = control.GetType().GetMethod(methodName); - if (method != null) - SyncInvokeData(control, method, data); - else - throw new NotSupportedException("Un Supported Method to invoke! The method named with " + methodName + " should be declare as a public function."); - } - /// - /// 异步调用具有特定名称的UI控件设置文本 - /// - /// - /// - public static void SyncSetText(Control control, string data) - { - SyncInvokeNoWait(control, new InvokeHandler(delegate() - { - control.Text = data; - })); - } - /// - /// 异步调用具有特定名称的UI控件设置是否可见 - /// - /// - /// - public static void SyncSetVisible(Control control, bool data) - { - SyncInvokeNoWait(control, new InvokeHandler(delegate() - { - control.Visible = data; - })); - } - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Threading; +using System.Reflection; +using IDCM.Data.Base; + +namespace IDCM.Service.Utils +{ + public class ControlAsyncUtil + { + internal delegate void InvokeHandler(); + + internal delegate void InvokeMethodDelegate(Control control, InvokeHandler handler); + /// + /// 为指定的UI控件执行异步操作更新的方法 + /// + /// + /// + /// + internal static void SyncInvoke(Control control, InvokeHandler handler) + { + try + { + // InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread. + // If these threads are different, it returns true. + if (control.InvokeRequired)//如果调用控件的线程和创建创建控件的线程不是同一个则为True + { + while (!control.IsHandleCreated || control.RecreatingHandle) //如果当前控件没有与它关联的句柄或正在重绘中,则等待执行。 + { + //解决窗体关闭时出现“访问已释放句柄“的异常 + if (control.Disposing || control.IsDisposed) + return; + Thread.Sleep(1); + } + IAsyncResult result = control.BeginInvoke(new InvokeMethodDelegate(SyncInvoke), new object[] { control, handler }); + control.EndInvoke(result);//获取委托执行结果的返回值 + } + else + { + IAsyncResult result2 = control.BeginInvoke(handler); + control.EndInvoke(result2); + } + } + catch (Exception ex) + { + log.Error(ex); +#if DEBUG + throw new IDCMViewException("Asynchronous Control Invoke Error.", ex); +#endif + } + } + /// + /// 为指定的UI控件执行异步操作更新的方法 + /// + /// + /// + internal static void SyncInvokeNoWait(Control control, InvokeHandler handler) + { + try{ + if (control.InvokeRequired) + { + //解决窗体关闭时出现“访问已释放句柄“的异常 + if (control.Disposing || control.IsDisposed) + return; + IAsyncResult result = control.BeginInvoke(new InvokeMethodDelegate(SyncInvoke), new object[] { control, handler }); + control.EndInvoke(result);//获取委托执行结果的返回值 + } + else + { + IAsyncResult result2 = control.BeginInvoke(handler); + control.EndInvoke(result2); + } + } + catch (Exception ex) + { + log.Error(ex); +#if DEBUG + throw new IDCMViewException("Asynchronous Control Invoke Error.", ex); +#endif + } + } + + /// + /// 为指定的UI空间执行异步的赋值更新的方法 + /// + /// + /// + /// + public static void SyncInvokeData(Control control, MethodInfo method, Object[] data) + { + SyncInvoke(control, new InvokeHandler(delegate() + { + method.Invoke(control, data); + })); + } + /// + /// 异步调用具有特定方法名称的UI控件方法 + /// + /// + /// + /// + public static void SyncInvokeData(Control control, String methodName, Object data) + { + SyncInvokeData(control, methodName, new Object[] { data }); + } + /// + /// 异步调用具有特定方法名称的UI控件方法 + /// + /// + /// + /// + public static void SyncInvokeData(Control control, String methodName, Object[] data) + { + MethodInfo method = control.GetType().GetMethod(methodName); + if (method != null) + SyncInvokeData(control, method, data); + else + throw new NotSupportedException("Un Supported Method to invoke! The method named with " + methodName + " should be declare as a public function."); + } + /// + /// 异步调用具有特定名称的UI控件设置文本 + /// + /// + /// + public static void SyncSetText(Control control, string data) + { + SyncInvokeNoWait(control, new InvokeHandler(delegate() + { + control.Text = data; + })); + } + /// + /// 异步调用具有特定名称的UI控件设置是否可见 + /// + /// + /// + public static void SyncSetVisible(Control control, bool data) + { + SyncInvokeNoWait(control, new InvokeHandler(delegate() + { + control.Visible = data; + })); + } + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + + } +} diff --git a/IDCM/IDCM/Core/DataSourceHolder.cs b/IDCM/IDCM/Core/DataSourceHolder.cs index e3ebde5..76e3aec 100644 --- a/IDCM/IDCM/Core/DataSourceHolder.cs +++ b/IDCM/IDCM/Core/DataSourceHolder.cs @@ -1,161 +1,161 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Diagnostics; -using System.Runtime.InteropServices; -using IDCM.Service; -using IDCM.Service.Common; -using System.Windows.Forms; -using IDCM.Data.Base; -using IDCM.Service.BGHandler; -using IDCM.Service.POO; - -namespace IDCM.Core -{ - /// - /// 工作空间保持及验证工具类 - /// @author Jiahai Wu - /// @Date 2014-08-19 - /// - class DataSourceHolder - { - /// - /// Connect Workspace, it willl choose or create a new workspace in local disk. - /// - /// - internal static bool connectWorkspace(string location,string loginName) - { - dataSource = new DataSourceMHub(location, loginName); - return dataSource.connect(); - } - /// - /// Connect GCM server with specific Login Name and password. - /// - /// - /// - /// - /// - internal static bool connectGCM(string loginName, string gcmPassword, bool autoLogin = true) - { - gcmHolder = new GCMSiteMHub(loginName, gcmPassword, autoLogin); - return gcmHolder.connect(2000); - } - /// - /// Connect Workspace and Connect GCM server asynchronous with specific Login Name and password. - /// - /// - /// - /// - /// - internal static bool quickConnect(string location, string loginName, string gcmPassword, bool autoLogin = true) - { - dataSource = new DataSourceMHub(location, loginName); - gcmHolder = new GCMSiteMHub(loginName, gcmPassword, autoLogin); - DWorkMHub.callAsyncHandle(new SignInHandler(gcmHolder)); - return dataSource.connect(); - } - - /// - /// 启动工作空间实例 - /// - public static bool prepareInstance() - { - if (dataSource.Connected) - { - if (dataSource.prepare()) - { - log.Info("Prepare datasource succeed."); - return true; - }else - { - log.Error(new IDCMServCommonException("Failed to open the data source. Cause:"+dataSource.LastError)); - MessageBox.Show("Failed to open the data source. Cause:"+dataSource.LastError); - } - } - return false; - } - /// - /// 关闭用户工作空间 - /// - /// - public static bool close() - { - if (gcmHolder != null) - { - gcmHolder.disconnect(); - gcmHolder = null; - } - bool res = false; - if (dataSource != null) - { - res=dataSource.disconnect(); - dataSource = null; - } - return res; - } - /// - /// 关闭GCM连接 - /// - public static void disconnectGCM(bool cancelDefaultWorkSpace = false) - { - if (gcmHolder != null) - { - gcmHolder.disconnect(cancelDefaultWorkSpace); - gcmHolder = null; - } - } - /// - /// 尝试获取登录用户身份信息,如果缓存状态无效则返回新对象 - /// - /// - public static AuthInfo getLoginAuthInfo() - { - AuthInfo auth = null; - if (gcmHolder != null) - auth = gcmHolder.getSignedAuthInfo(); - else - { - StartInfo si = IDCMEnvironment.getLastStartInfo(); - auth=new AuthInfo(); - auth.Username = si.LoginName; - auth.Password = si.GCMPassword; - auth.autoLogin = si.rememberPassword; - } - return auth; - } - /// - /// 返回是否处于数据源连接保持中 - /// - public static bool InWorking - { - get { return dataSource!=null && dataSource.InWorking; } - } - /// - /// 获取连接数据源 - /// - public static DataSourceMHub DataSource - { - get { return dataSource; } - } - /// - /// 获取GCM连接资源 - /// - public static GCMSiteMHub GCMHolder - { - get { return gcmHolder; } - } - #region 实例对象保持部分 - /// - /// 数据源实例 - /// - private static volatile DataSourceMHub dataSource = null; - private static volatile GCMSiteMHub gcmHolder = null; - - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - #endregion - - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Diagnostics; +using System.Runtime.InteropServices; +using IDCM.Service; +using IDCM.Service.Common; +using System.Windows.Forms; +using IDCM.Data.Base; +using IDCM.Service.BGHandler; +using IDCM.Service.POO; + +namespace IDCM.Core +{ + /// + /// 工作空间保持及验证工具类 + /// @author Jiahai Wu + /// @Date 2014-08-19 + /// + class DataSourceHolder + { + /// + /// Connect Workspace, it willl choose or create a new workspace in local disk. + /// + /// + internal static bool connectWorkspace(string location,string loginName) + { + dataSource = new DataSourceMHub(location, loginName); + return dataSource.connect(); + } + /// + /// Connect GCM server with specific Login Name and password. + /// + /// + /// + /// + /// + internal static bool connectGCM(string loginName, string gcmPassword, bool autoLogin = true) + { + gcmHolder = new GCMSiteMHub(loginName, gcmPassword, autoLogin); + return gcmHolder.connect(2000); + } + /// + /// Connect Workspace and Connect GCM server asynchronous with specific Login Name and password. + /// + /// + /// + /// + /// + internal static bool quickConnect(string location, string loginName, string gcmPassword, bool autoLogin = true) + { + dataSource = new DataSourceMHub(location, loginName); + gcmHolder = new GCMSiteMHub(loginName, gcmPassword, autoLogin); + DWorkMHub.callAsyncHandle(new SignInHandler(gcmHolder)); + return dataSource.connect(); + } + + /// + /// 启动工作空间实例 + /// + public static bool prepareInstance() + { + if (dataSource.Connected) + { + if (dataSource.prepare()) + { + log.Info("Prepare datasource succeed."); + return true; + }else + { + log.Error(new IDCMServCommonException("Failed to open the data source. Cause:"+dataSource.LastError)); + MessageBox.Show("Failed to open the data source. Cause:"+dataSource.LastError); + } + } + return false; + } + /// + /// 关闭用户工作空间 + /// + /// + public static bool close() + { + if (gcmHolder != null) + { + gcmHolder.disconnect(); + gcmHolder = null; + } + bool res = false; + if (dataSource != null) + { + res=dataSource.disconnect(); + dataSource = null; + } + return res; + } + /// + /// 关闭GCM连接 + /// + public static void disconnectGCM(bool cancelDefaultWorkSpace = false) + { + if (gcmHolder != null) + { + gcmHolder.disconnect(cancelDefaultWorkSpace); + gcmHolder = null; + } + } + /// + /// 尝试获取登录用户身份信息,如果缓存状态无效则返回新对象 + /// + /// + public static AuthInfo getLoginAuthInfo() + { + AuthInfo auth = null; + if (gcmHolder != null) + auth = gcmHolder.getSignedAuthInfo(); + else + { + StartInfo si = IDCMEnvironment.getLastStartInfo(); + auth=new AuthInfo(); + auth.Username = si.LoginName; + auth.Password = si.GCMPassword; + auth.autoLogin = si.rememberPassword; + } + return auth; + } + /// + /// 返回是否处于数据源连接保持中 + /// + public static bool InWorking + { + get { return dataSource!=null && dataSource.InWorking; } + } + /// + /// 获取连接数据源 + /// + public static DataSourceMHub DataSource + { + get { return dataSource; } + } + /// + /// 获取GCM连接资源 + /// + public static GCMSiteMHub GCMHolder + { + get { return gcmHolder; } + } + #region 实例对象保持部分 + /// + /// 数据源实例 + /// + private static volatile DataSourceMHub dataSource = null; + private static volatile GCMSiteMHub gcmHolder = null; + + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + #endregion + + + } +} diff --git a/IDCM/IDCM/Forms/HomeView.cs b/IDCM/IDCM/Forms/HomeView.cs index 4c0996e..ed6ad5c 100644 --- a/IDCM/IDCM/Forms/HomeView.cs +++ b/IDCM/IDCM/Forms/HomeView.cs @@ -1,740 +1,740 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using System.Threading; -using IDCM.ViewManager; -using IDCM.Service.Utils; -using IDCM.Data.Base; - -namespace IDCM.Forms -{ - public partial class HomeView : Form - { - private DataGridViewSelectedRowCollection dgvsRowCollection = null;//用来保存选中的行 - private HomeViewManager manager = null; - internal void setManager(HomeViewManager manager) - { - this.manager = manager; - } - /// - /// 客户端默认首页面视图实例初始化 - /// - public HomeView() - { - InitializeComponent(); - this.splitContainer_middle.Panel1Collapsed = true; - dataGridView_items.AllowDrop = true; - dataGridView_items.AllowUserToAddRows = false; - dataGridView_items.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal; - dataGridView_items.EditMode = DataGridViewEditMode.EditOnKeystroke; - ////////////////////////////////////////////////////////// - ////dataGridView_items.TopLeftHeaderCell = new DataGridViewTopLeftHeaderCell(); - ////dataGridView_items.AdjustedTopLeftHeaderBorderStyle = DataGridViewTopLeftHeaderCell.MeasureTextPreferredSize(); - //////////////////////////////////////////////////////// - - treeView_base.ImageList = imageList_lib; - treeView_library.ImageList = imageList_lib; - } - /// - /// 客户端默认首页面视图实例化后,加载数据过程 - /// - /// - /// - private void HomeView_Load(object sender, EventArgs e) - { - } - - private void HomeView_Shown(object sender, EventArgs e) - { - } - - /// - /// 左键或右键的Base分组事件处理方法 - /// - /// - /// - private void treeView_base_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) - { - if (e.Node != null) - { - treeView_base.SelectedNode = e.Node; - manager.noteCurSelectedNode(e.Node); - //左键(激活节点选定事件,并将触发必要的右侧数据表单的更新显示) - if (e.Button == MouseButtons.Left) - { - } - //右键(不会激活节点选定事件,事件触发节点信息通过匿名委托方法绑定到弹出菜单项的事件方法中去) - if (e.Button == MouseButtons.Right) - { - foreach (ToolStripItem tsItem in contextMenuStrip_base.Items) - { - if (tsItem is ToolStripSeparator) - continue; - ControlUtil.ClearEvent(tsItem, "Click"); - tsItem.Click += delegate(object tsender, EventArgs te) { toolStripMenuItem_base_Click(tsender, te, e.Node); }; - } - contextMenuStrip_base.Show(treeView_base, e.X, e.Y); - } - } - } - /// - /// 左键或右键单击的自定义分组事件处理方法 - /// - /// - /// - private void treeView_library_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) - { - if (e.Node != null) - { - treeView_library.SelectedNode = e.Node; - manager.noteCurSelectedNode(e.Node); - //左键 - if (e.Button == MouseButtons.Left) - { - } - //右键 - if (e.Button == MouseButtons.Right) - { - manager.filterContextMenuItems(contextMenuStrip_lib, e.Node); - foreach (ToolStripItem tsItem in contextMenuStrip_lib.Items) - { - if (tsItem is ToolStripSeparator) - continue; - ControlUtil.ClearEvent(tsItem, "Click"); - tsItem.Click += delegate(object tsender, EventArgs te) { toolStripMenuItem_lib_Click(tsender, te, e.Node); }; - } - contextMenuStrip_lib.Show(treeView_library, e.X, e.Y); - } - } - } - protected void toolStripMenuItem_base_Click(object sender, EventArgs e, TreeNode node) - { - string name=((ToolStripItem)sender).Name; - switch (name) - { - case "clear_toolStripMenuItem": - clear_toolStripMenuItem_Click(sender, e, node); - break; - default: - break; - } - } - protected void toolStripMenuItem_lib_Click(object sender, EventArgs e,TreeNode node) - { - string name = ((ToolStripItem)sender).Name; - switch (name) - { - case "CreateGroupSet": - CreateGroupSet_Click(sender, e, node); - break; - case "CreateGroup": - CreateGroup_Click(sender, e, node); - break; - case "CreateSmartGroup": - CreateSmartGroup_Click(sender, e, node); - break; - case "RenameGroup": - RenameGroup_Click(sender, e, node); - break; - case "RenameGroupSet": - RenameGroupSet_Click(sender, e, node); - break; - case "DeleteGroup": - DeleteGroup_Click(sender, e, node); - break; - case "DeleteGroupSet": - DeleteGroupSet_Click(sender, e, node); - break; - default: - break; - } - } - /// - /// 新建分组节点 - /// - /// - /// - private void CreateGroupSet_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - manager.addGroupSet(node); - } - } - - private void RenameGroupSet_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - treeView_library.LabelEdit = true; - node.BeginEdit(); - } - } - - private void DeleteGroupSet_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - DialogResult res = MessageBox.Show("Are you sure to delete the selected Node named " + node.Text, "Confirm Delete", MessageBoxButtons.OKCancel); - if (res == DialogResult.OK) - { - manager.deleteNode(node); - } - } - } - - private void CreateGroup_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - manager.addGroup(node); - } - } - - private void RenameGroup_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - treeView_library.LabelEdit = true; - node.BeginEdit(); - } - } - - private void DeleteGroup_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - DialogResult res = MessageBox.Show("Are you sure to delete the selected Node named " + node.Text, "Confirm Delete", MessageBoxButtons.OKCancel); - if (res == DialogResult.OK) - { - manager.deleteNode(node); - } - } - } - private void CreateSmartGroup_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - MessageBox.Show("UnImplicated"); - } - } - private void clear_toolStripMenuItem_Click(object sender, EventArgs e, TreeNode node) - { - if (node != null) - { - DialogResult res = MessageBox.Show("Are you sure to Empty Data", "Confirm Empty", MessageBoxButtons.OKCancel); - if (res == DialogResult.OK) - { - manager.trashDataSet(node); - } - } - } - private void treeView_library_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) - { - manager.renameNode(e.Node, e.Label); - e.Node.EndEdit(false); - treeView_library.LabelEdit = false; - manager.updateCatRecCount(e.Node); - } - private void treeView_library_DrawNode(object sender, DrawTreeNodeEventArgs e) - { - if (e.Node.Equals(manager.SelectedNode_Current)) - { - e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); - } - else - { - e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); - } - //由系統繪制 - e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font, Brushes.Black, e.Bounds.Left, e.Bounds.Top); - ////e.DrawDefault = true; - if (e.Node.Tag != null) - { - string newMail = string.Format(" ({0})", e.Node.Tag.ToString()); - e.Graphics.DrawString(newMail, e.Node.TreeView.Font, Brushes.Blue, e.Bounds.Right, e.Bounds.Top); - } - //e.Node.Expand(); - } - - private void treeView_base_DrawNode(object sender, DrawTreeNodeEventArgs e) - { - if (e.Node.Equals(manager.SelectedNode_Current)) - { - e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); - } - else - { - e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); - } - //由系統繪制 - e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font, Brushes.Black, e.Bounds.Left, e.Bounds.Top); - ////e.DrawDefault = true; - if (e.Node.Tag != null) - { - string newMail = string.Format(" ({0})", e.Node.Tag.ToString()); - e.Graphics.DrawString(newMail, e.Node.TreeView.Font, Brushes.Blue, e.Bounds.Right, e.Bounds.Top); - } - //e.Node.Expand(); - } - - /// - /// 新增记录 - /// - /// - /// - private void toolStripButton_add_Click(object sender, EventArgs e) - { - if (dataGridView_items.Rows.Count > 0 && dataGridView_items.Rows[dataGridView_items.Rows.Count - 1].IsNewRow) - return; - manager.addNewRecord(); - manager.updateCatRecCount(); - } - /// - /// 删除记录 - /// - /// - /// - private void toolStripButton_del_Click(object sender, EventArgs e) - { - foreach (DataGridViewRow row in dataGridView_items.SelectedRows) - { - DataGridViewCell idCell = row.Cells[CTDRecordA.CTD_RID]; - if (idCell != null) - { - long uid = Convert.ToInt64(idCell.FormattedValue.ToString()); - { - int ic = -1; - if (manager.CURRENT_LID != CatalogNode.REC_TRASH && manager.CURRENT_LID != CatalogNode.REC_TEMP) - { - ic = manager.updateCTCRecordLid(CatalogNode.REC_TRASH, CatalogNode.REC_UNFILED, uid); - } - else - { - ic = manager.deleteRec(uid); - } - if (ic > 0) - dataGridView_items.Rows.Remove(row); - } - } - } - manager.updateCatRecCount(); - } - /// - /// 单元格的值改变后,执行更新或插入操作 - /// - /// - /// - private void dataGridView_items_CellValueChanged(object sender, DataGridViewCellEventArgs e) - { - if (e.ColumnIndex > 0) - { - DataGridViewCell idCell = dataGridView_items.Rows[e.RowIndex].Cells[CTDRecordA.CTD_RID]; - DataGridViewCell cell = dataGridView_items.Rows[e.RowIndex].Cells[e.ColumnIndex]; - if (cell != null && idCell!=null) - { - string cellVal = cell.FormattedValue.ToString(); - string attrName = dataGridView_items.Columns[e.ColumnIndex].Name; - if (idCell.Value != null) - { - string uid = idCell.FormattedValue.ToString(); - manager.updateAttrVal(uid, cellVal, attrName); - } - else - { - Console.WriteLine("Error!!!"); - } - } - } - } - - /// - /// 拖拽事件运行时的鼠标状态切换方法 - /// - /// - /// - private void dataGridView_items_DragEnter(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - e.Effect = DragDropEffects.Link; - } - else - { - e.Effect = DragDropEffects.None; - } - } - /// - /// 文件拖拽后事件处理方法 - /// - /// - /// - private void dataGridView_items_DragDrop(object sender, DragEventArgs e) - { - String[] recvs = (String[])e.Data.GetData(DataFormats.FileDrop, false); - for (int i = 0; i < recvs.Length; i++) - { - if (recvs[i].Trim() != "") - { - String fpath = recvs[i].Trim(); - bool exists = System.IO.File.Exists(fpath); - if (exists == true) - { - try - { - manager.importData(fpath); - } - catch (Exception ex) - { - MessageBox.Show("数据导入失败。"); - log.Info("数据导入失败,错误信息:",ex); - } - } - } - } - } - /// - /// 变更选取行记录事件处理 - /// - /// - /// - private void dataGridView_items_SelectionChanged(object sender, EventArgs e) - { - if (dataGridView_items.Rows.Count > 0 && dataGridView_items.CurrentRow !=null) - { - DataGridViewRow dgvr = dataGridView_items.CurrentRow; - try - { - DataGridViewCell dgvc = dgvr.Cells[CTDRecordA.CTD_RID]; - if (dgvc != null) - { - string rid = dgvc.FormattedValue.ToString(); - if (rid.Length > 0 && !rid.Equals(manager.CURRENT_RID.ToString())) - { - manager.selectViewRecord(dgvr); - } - } - } - catch (ArgumentException ex) - { - log.Warn(ex); - } - } - } - private void toolStripTextBox_quickSearch_TextChanged(object sender, EventArgs e) - { - - } - - - private void dataGridView_items_MouseDown(object sender, MouseEventArgs e) - { - //捕获鼠标点击区域的信息 - DataGridView.HitTestInfo hitTestInfo = this.dataGridView_items.HitTest(e.X, e.Y); - if (hitTestInfo.RowIndex > -1) - { - if (this.dataGridView_items.SelectedRows.Count > 0) - { - dgvsRowCollection = this.dataGridView_items.SelectedRows; - } - } - else - dgvsRowCollection = null; - } - - private void dataGridView_items_MouseMove(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - if (dgvsRowCollection != null) - { - DragDropEffects effect = this.dataGridView_items.DoDragDrop(dgvsRowCollection, DragDropEffects.Link); - if (effect == DragDropEffects.Move) - { - Console.WriteLine("将dgvsRowCollection重新置空"); - //将dgvsRowCollection重新置空 - dgvsRowCollection = null; - } - } - } - } - - private void treeView_library_DragOver(object sender, DragEventArgs e) - { - //获得鼠标的坐标 - Point point = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); - // 按鼠标所指示的位置选择节点 - ((TreeView)sender).SelectedNode = ((TreeView)sender).GetNodeAt(point); - - if (e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection))) - { - e.Effect = DragDropEffects.Link; //这个值会返回给DoDragDrop方法 - /////////////////////////////////////// - // 拖放的目标节点 - TreeNode EnterNode = null; - // 根据坐标点取得处于坐标点位置的节点 - EnterNode = ((TreeView)sender).GetNodeAt(Cursor.Position.X, Cursor.Position.Y); - if (EnterNode != null && EnterNode.Parent != null) - { - e.Effect = DragDropEffects.Move; //这个值会返回给DoDragDrop方法 - } - } - else - { - e.Effect = DragDropEffects.None; - } - } - private void treeView_library_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.AllowedEffect; - } - - private void treeView_library_DragDrop(object sender, DragEventArgs e) - { - //获得释放鼠标位置的坐标 - Point point = treeView_library.PointToClient(new Point(e.X, e.Y)); - //获得在鼠标释放处的节点 - TreeNode targetNode = treeView_library.GetNodeAt(point); - if (targetNode != null && targetNode.Parent != null) - { - if (e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection))) - { - DataGridViewSelectedRowCollection rowCollection = e.Data.GetData(typeof(DataGridViewSelectedRowCollection)) as DataGridViewSelectedRowCollection; - if (rowCollection != null) - { - DataGridViewColumn dgvc = dataGridView_items.Columns[CTDRecordA.CTD_RID]; - if (dgvc != null) - { - foreach (DataGridViewRow row in rowCollection) - { - int lid = Convert.ToInt32(targetNode.Name); - int plid = Convert.ToInt32(targetNode.Parent.Name); - long rid = Convert.ToInt64(row.Cells[dgvc.Index].Value.ToString()); - manager.updateCTCRecordLid(lid, plid, rid); - } - } - manager.updateCatRecCount(); - } - } - manager.updateDataSet(targetNode); - } - } - /// - /// 设置Datagridview显示行号 - /// - /// - /// - private void dataGridView_items_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) - { - System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(e.RowBounds.Location.X,e.RowBounds.Location.Y,dataGridView_items.RowHeadersWidth - 4,e.RowBounds.Height); - - TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(),dataGridView_items.RowHeadersDefaultCellStyle.Font,rectangle, - dataGridView_items.RowHeadersDefaultCellStyle.ForeColor,TextFormatFlags.VerticalCenter | TextFormatFlags.Right); - dataGridView_items.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders); - } - - private void treeView_library_AfterSelect(object sender, TreeViewEventArgs e) - { - if (e.Node != null) - manager.noteCurSelectedNode(e.Node); - } - - private void treeView_base_AfterSelect(object sender, TreeViewEventArgs e) - { - if (e.Node != null) - manager.noteCurSelectedNode(e.Node); - } - public TreeView getBaseTree() - { - return this.treeView_base; - } - public TreeView getLibTree() - { - return this.treeView_library; - } - public DataGridView getItemGridView() - { - return this.dataGridView_items; - } - public TabControl getAttachTabControl() - { - return this.tabControl_attach; - } - public ToolStripProgressBar getProgressBar() - { - return toolStripProgressBar_bottom; - } - private void treeView_library_BeforeCollapse(object sender, TreeViewCancelEventArgs e) - { - e.Cancel = true; - } - private void treeView_base_BeforeCollapse(object sender, TreeViewCancelEventArgs e) - { - e.Cancel = true; - } - - private void toolStripButton_import_Click(object sender, EventArgs e) - { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "Excel文件,mdi缓存文件,DI打包文件(*.xls,*.xlsx)|*.xls;*.xlsx;"; - if (ofd.ShowDialog() == DialogResult.OK) - { - string fpath = ofd.FileName; - bool exists = System.IO.File.Exists(fpath); - if (exists == true) - { - try - { - manager.importData(fpath); - } - catch (Exception ex) - { - MessageBox.Show("数据导入失败。"); - log.Info("数据导入失败,错误信息:",ex); - } - } - } - } - - private void toolStripButton_export_Click(object sender, EventArgs e) - { - ExportTypeDlg exportDlg = new ExportTypeDlg(); - if(exportDlg.ShowDialog()==DialogResult.OK) - { - try - { - manager.exportData(ExportTypeDlg.LastOptionValue, ExportTypeDlg.LastFilePath); - } - catch (Exception ex) - { - MessageBox.Show("数据导出失败。"); - log.Info("数据导出失败,错误信息:",ex); - } - } - } - /// - /// For Quick search - /// - /// - /// - private void toolStripButton_qsearch_Click(object sender, EventArgs e) - { - string findTerm = this.toolStripTextBox_quickSearch.Text.Trim(); - manager.quickSearch(findTerm); - } - private void toolStripTextBox_quickSearch_Enter(object sender, EventArgs e) - { - this.toolStripTextBox_quickSearch.Text = ""; - this.toolStripTextBox_quickSearch.Owner.Update(); - } - - private void toolStripTextBox_quickSearch_Leave(object sender, EventArgs e) - { - if (this.toolStripTextBox_quickSearch.Text.Trim().Length < 1) - this.toolStripTextBox_quickSearch.Text = "Quick Search"; - } - - private void toolStripTextBox_quickSearch_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Enter) - { - string findTerm = this.toolStripTextBox_quickSearch.Text.Trim(); - manager.quickSearch(findTerm); - } - } - private void btn_search_Click(object sender, EventArgs e) - { - if (this.textBox_search1.Text.Trim().Length > 0) - { - manager.doDBDataSearch(); - } - } - public TableLayoutPanel getDBSearchPanel() - { - return this.tableLayoutPanel_search; - } - public SplitContainer getSearchSpliter() - { - return splitContainer_middle; - } - /// - /// 验证登录状态,并打开GCM视图页面 - /// - /// - /// - private void toolStripButton_gcm_Click(object sender, EventArgs e) - { - manager.activeGCMView(); - } - /// - /// 云备份 - /// - /// - /// - private void toolStripButton_download_Click(object sender, EventArgs e) - { - - } - /// - /// 云恢复 - /// - /// - /// - private void toolStripButton_upload_Click(object sender, EventArgs e) - { - - } - /// - /// 本地数据刷新 - /// - /// - /// - private void toolStripButton_refresh_Click(object sender, EventArgs e) - { - - } - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - /// - /// 右键菜单中复制请求 - /// - /// - /// - private void copyCtrlCToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.CopyClipboard(); - DataObject d = dataGridView_items.GetClipboardContent(); - Clipboard.SetDataObject(d); - } - /// - /// 右键菜单中粘贴请求 - /// - /// - /// - private void pasteCtrlVToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.PasteClipboard(); - } - /// - /// 绑定剪贴板复制粘贴的快捷键处理Ctrl+C Ctrl+V Shift+Delete 及 Shift+Insert - /// - /// - /// - private void dataGridView_items_KeyDown(object sender, KeyEventArgs e) - { - if ((e.Control && e.KeyCode == Keys.C) || (e.Shift && e.KeyCode == Keys.Delete)) - { - manager.CopyClipboard(); - } - if ((e.Control && e.KeyCode == Keys.V) || (e.Shift && e.KeyCode == Keys.Insert)) - { - manager.PasteClipboard(); - } - } - - } -} +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Threading; +using IDCM.ViewManager; +using IDCM.Service.Utils; +using IDCM.Data.Base; + +namespace IDCM.Forms +{ + public partial class HomeView : Form + { + private DataGridViewSelectedRowCollection dgvsRowCollection = null;//用来保存选中的行 + private HomeViewManager manager = null; + internal void setManager(HomeViewManager manager) + { + this.manager = manager; + } + /// + /// 客户端默认首页面视图实例初始化 + /// + public HomeView() + { + InitializeComponent(); + this.splitContainer_middle.Panel1Collapsed = true; + dataGridView_items.AllowDrop = true; + dataGridView_items.AllowUserToAddRows = false; + dataGridView_items.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal; + dataGridView_items.EditMode = DataGridViewEditMode.EditOnKeystroke; + ////////////////////////////////////////////////////////// + ////dataGridView_items.TopLeftHeaderCell = new DataGridViewTopLeftHeaderCell(); + ////dataGridView_items.AdjustedTopLeftHeaderBorderStyle = DataGridViewTopLeftHeaderCell.MeasureTextPreferredSize(); + //////////////////////////////////////////////////////// + + treeView_base.ImageList = imageList_lib; + treeView_library.ImageList = imageList_lib; + } + /// + /// 客户端默认首页面视图实例化后,加载数据过程 + /// + /// + /// + private void HomeView_Load(object sender, EventArgs e) + { + } + + private void HomeView_Shown(object sender, EventArgs e) + { + } + + /// + /// 左键或右键的Base分组事件处理方法 + /// + /// + /// + private void treeView_base_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + if (e.Node != null) + { + treeView_base.SelectedNode = e.Node; + manager.noteCurSelectedNode(e.Node); + //左键(激活节点选定事件,并将触发必要的右侧数据表单的更新显示) + if (e.Button == MouseButtons.Left) + { + } + //右键(不会激活节点选定事件,事件触发节点信息通过匿名委托方法绑定到弹出菜单项的事件方法中去) + if (e.Button == MouseButtons.Right) + { + foreach (ToolStripItem tsItem in contextMenuStrip_base.Items) + { + if (tsItem is ToolStripSeparator) + continue; + ControlUtil.ClearEvent(tsItem, "Click"); + tsItem.Click += delegate(object tsender, EventArgs te) { toolStripMenuItem_base_Click(tsender, te, e.Node); }; + } + contextMenuStrip_base.Show(treeView_base, e.X, e.Y); + } + } + } + /// + /// 左键或右键单击的自定义分组事件处理方法 + /// + /// + /// + private void treeView_library_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + if (e.Node != null) + { + treeView_library.SelectedNode = e.Node; + manager.noteCurSelectedNode(e.Node); + //左键 + if (e.Button == MouseButtons.Left) + { + } + //右键 + if (e.Button == MouseButtons.Right) + { + manager.filterContextMenuItems(contextMenuStrip_lib, e.Node); + foreach (ToolStripItem tsItem in contextMenuStrip_lib.Items) + { + if (tsItem is ToolStripSeparator) + continue; + ControlUtil.ClearEvent(tsItem, "Click"); + tsItem.Click += delegate(object tsender, EventArgs te) { toolStripMenuItem_lib_Click(tsender, te, e.Node); }; + } + contextMenuStrip_lib.Show(treeView_library, e.X, e.Y); + } + } + } + protected void toolStripMenuItem_base_Click(object sender, EventArgs e, TreeNode node) + { + string name=((ToolStripItem)sender).Name; + switch (name) + { + case "clear_toolStripMenuItem": + clear_toolStripMenuItem_Click(sender, e, node); + break; + default: + break; + } + } + protected void toolStripMenuItem_lib_Click(object sender, EventArgs e,TreeNode node) + { + string name = ((ToolStripItem)sender).Name; + switch (name) + { + case "CreateGroupSet": + CreateGroupSet_Click(sender, e, node); + break; + case "CreateGroup": + CreateGroup_Click(sender, e, node); + break; + case "CreateSmartGroup": + CreateSmartGroup_Click(sender, e, node); + break; + case "RenameGroup": + RenameGroup_Click(sender, e, node); + break; + case "RenameGroupSet": + RenameGroupSet_Click(sender, e, node); + break; + case "DeleteGroup": + DeleteGroup_Click(sender, e, node); + break; + case "DeleteGroupSet": + DeleteGroupSet_Click(sender, e, node); + break; + default: + break; + } + } + /// + /// 新建分组节点 + /// + /// + /// + private void CreateGroupSet_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + manager.addGroupSet(node); + } + } + + private void RenameGroupSet_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + treeView_library.LabelEdit = true; + node.BeginEdit(); + } + } + + private void DeleteGroupSet_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + DialogResult res = MessageBox.Show("Are you sure to delete the selected Node named " + node.Text, "Confirm Delete", MessageBoxButtons.OKCancel); + if (res == DialogResult.OK) + { + manager.deleteNode(node); + } + } + } + + private void CreateGroup_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + manager.addGroup(node); + } + } + + private void RenameGroup_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + treeView_library.LabelEdit = true; + node.BeginEdit(); + } + } + + private void DeleteGroup_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + DialogResult res = MessageBox.Show("Are you sure to delete the selected Node named " + node.Text, "Confirm Delete", MessageBoxButtons.OKCancel); + if (res == DialogResult.OK) + { + manager.deleteNode(node); + } + } + } + private void CreateSmartGroup_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + MessageBox.Show("UnImplicated"); + } + } + private void clear_toolStripMenuItem_Click(object sender, EventArgs e, TreeNode node) + { + if (node != null) + { + DialogResult res = MessageBox.Show("Are you sure to Empty Data", "Confirm Empty", MessageBoxButtons.OKCancel); + if (res == DialogResult.OK) + { + manager.trashDataSet(node); + } + } + } + private void treeView_library_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) + { + manager.renameNode(e.Node, e.Label); + e.Node.EndEdit(false); + treeView_library.LabelEdit = false; + manager.updateCatRecCount(e.Node); + } + private void treeView_library_DrawNode(object sender, DrawTreeNodeEventArgs e) + { + if (e.Node.Equals(manager.SelectedNode_Current)) + { + e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); + } + else + { + e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); + } + //由系統繪制 + e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font, Brushes.Black, e.Bounds.Left, e.Bounds.Top); + ////e.DrawDefault = true; + if (e.Node.Tag != null) + { + string newMail = string.Format(" ({0})", e.Node.Tag.ToString()); + e.Graphics.DrawString(newMail, e.Node.TreeView.Font, Brushes.Blue, e.Bounds.Right, e.Bounds.Top); + } + //e.Node.Expand(); + } + + private void treeView_base_DrawNode(object sender, DrawTreeNodeEventArgs e) + { + if (e.Node.Equals(manager.SelectedNode_Current)) + { + e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); + } + else + { + e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.Left, e.Bounds.Top, e.Node.TreeView.Width - e.Bounds.Left - 2, e.Bounds.Height); + } + //由系統繪制 + e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font, Brushes.Black, e.Bounds.Left, e.Bounds.Top); + ////e.DrawDefault = true; + if (e.Node.Tag != null) + { + string newMail = string.Format(" ({0})", e.Node.Tag.ToString()); + e.Graphics.DrawString(newMail, e.Node.TreeView.Font, Brushes.Blue, e.Bounds.Right, e.Bounds.Top); + } + //e.Node.Expand(); + } + + /// + /// 新增记录 + /// + /// + /// + private void toolStripButton_add_Click(object sender, EventArgs e) + { + if (dataGridView_items.Rows.Count > 0 && dataGridView_items.Rows[dataGridView_items.Rows.Count - 1].IsNewRow) + return; + manager.addNewRecord(); + manager.updateCatRecCount(); + } + /// + /// 删除记录 + /// + /// + /// + private void toolStripButton_del_Click(object sender, EventArgs e) + { + foreach (DataGridViewRow row in dataGridView_items.SelectedRows) + { + DataGridViewCell idCell = row.Cells[CTDRecordA.CTD_RID]; + if (idCell != null) + { + long uid = Convert.ToInt64(idCell.FormattedValue.ToString()); + { + int ic = -1; + if (manager.CURRENT_LID != CatalogNode.REC_TRASH && manager.CURRENT_LID != CatalogNode.REC_TEMP) + { + ic = manager.updateCTCRecordLid(CatalogNode.REC_TRASH, CatalogNode.REC_UNFILED, uid); + } + else + { + ic = manager.deleteRec(uid); + } + if (ic > 0) + dataGridView_items.Rows.Remove(row); + } + } + } + manager.updateCatRecCount(); + } + /// + /// 单元格的值改变后,执行更新或插入操作 + /// + /// + /// + private void dataGridView_items_CellValueChanged(object sender, DataGridViewCellEventArgs e) + { + if (e.ColumnIndex > 0) + { + DataGridViewCell idCell = dataGridView_items.Rows[e.RowIndex].Cells[CTDRecordA.CTD_RID]; + DataGridViewCell cell = dataGridView_items.Rows[e.RowIndex].Cells[e.ColumnIndex]; + if (cell != null && idCell!=null) + { + string cellVal = cell.FormattedValue.ToString(); + string attrName = dataGridView_items.Columns[e.ColumnIndex].Name; + if (idCell.Value != null) + { + string uid = idCell.FormattedValue.ToString(); + manager.updateAttrVal(uid, cellVal, attrName); + } + else + { + Console.WriteLine("Error!!!"); + } + } + } + } + + /// + /// 拖拽事件运行时的鼠标状态切换方法 + /// + /// + /// + private void dataGridView_items_DragEnter(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + e.Effect = DragDropEffects.Link; + } + else + { + e.Effect = DragDropEffects.None; + } + } + /// + /// 文件拖拽后事件处理方法 + /// + /// + /// + private void dataGridView_items_DragDrop(object sender, DragEventArgs e) + { + String[] recvs = (String[])e.Data.GetData(DataFormats.FileDrop, false); + for (int i = 0; i < recvs.Length; i++) + { + if (recvs[i].Trim() != "") + { + String fpath = recvs[i].Trim(); + bool exists = System.IO.File.Exists(fpath); + if (exists == true) + { + try + { + manager.importData(fpath); + } + catch (Exception ex) + { + MessageBox.Show("数据导入失败。"); + log.Info("数据导入失败,错误信息:",ex); + } + } + } + } + } + /// + /// 变更选取行记录事件处理 + /// + /// + /// + private void dataGridView_items_SelectionChanged(object sender, EventArgs e) + { + if (dataGridView_items.Rows.Count > 0 && dataGridView_items.CurrentRow !=null) + { + DataGridViewRow dgvr = dataGridView_items.CurrentRow; + try + { + DataGridViewCell dgvc = dgvr.Cells[CTDRecordA.CTD_RID]; + if (dgvc != null) + { + string rid = dgvc.FormattedValue.ToString(); + if (rid.Length > 0 && !rid.Equals(manager.CURRENT_RID.ToString())) + { + manager.selectViewRecord(dgvr); + } + } + } + catch (ArgumentException ex) + { + log.Warn(ex); + } + } + } + private void toolStripTextBox_quickSearch_TextChanged(object sender, EventArgs e) + { + + } + + + private void dataGridView_items_MouseDown(object sender, MouseEventArgs e) + { + //捕获鼠标点击区域的信息 + DataGridView.HitTestInfo hitTestInfo = this.dataGridView_items.HitTest(e.X, e.Y); + if (hitTestInfo.RowIndex > -1) + { + if (this.dataGridView_items.SelectedRows.Count > 0) + { + dgvsRowCollection = this.dataGridView_items.SelectedRows; + } + } + else + dgvsRowCollection = null; + } + + private void dataGridView_items_MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + if (dgvsRowCollection != null) + { + DragDropEffects effect = this.dataGridView_items.DoDragDrop(dgvsRowCollection, DragDropEffects.Link); + if (effect == DragDropEffects.Move) + { + Console.WriteLine("将dgvsRowCollection重新置空"); + //将dgvsRowCollection重新置空 + dgvsRowCollection = null; + } + } + } + } + + private void treeView_library_DragOver(object sender, DragEventArgs e) + { + //获得鼠标的坐标 + Point point = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); + // 按鼠标所指示的位置选择节点 + ((TreeView)sender).SelectedNode = ((TreeView)sender).GetNodeAt(point); + + if (e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection))) + { + e.Effect = DragDropEffects.Link; //这个值会返回给DoDragDrop方法 + /////////////////////////////////////// + // 拖放的目标节点 + TreeNode EnterNode = null; + // 根据坐标点取得处于坐标点位置的节点 + EnterNode = ((TreeView)sender).GetNodeAt(Cursor.Position.X, Cursor.Position.Y); + if (EnterNode != null && EnterNode.Parent != null) + { + e.Effect = DragDropEffects.Move; //这个值会返回给DoDragDrop方法 + } + } + else + { + e.Effect = DragDropEffects.None; + } + } + private void treeView_library_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.AllowedEffect; + } + + private void treeView_library_DragDrop(object sender, DragEventArgs e) + { + //获得释放鼠标位置的坐标 + Point point = treeView_library.PointToClient(new Point(e.X, e.Y)); + //获得在鼠标释放处的节点 + TreeNode targetNode = treeView_library.GetNodeAt(point); + if (targetNode != null && targetNode.Parent != null) + { + if (e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection))) + { + DataGridViewSelectedRowCollection rowCollection = e.Data.GetData(typeof(DataGridViewSelectedRowCollection)) as DataGridViewSelectedRowCollection; + if (rowCollection != null) + { + DataGridViewColumn dgvc = dataGridView_items.Columns[CTDRecordA.CTD_RID]; + if (dgvc != null) + { + foreach (DataGridViewRow row in rowCollection) + { + int lid = Convert.ToInt32(targetNode.Name); + int plid = Convert.ToInt32(targetNode.Parent.Name); + long rid = Convert.ToInt64(row.Cells[dgvc.Index].Value.ToString()); + manager.updateCTCRecordLid(lid, plid, rid); + } + } + manager.updateCatRecCount(); + } + } + manager.updateDataSet(targetNode); + } + } + /// + /// 设置Datagridview显示行号 + /// + /// + /// + private void dataGridView_items_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) + { + System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(e.RowBounds.Location.X,e.RowBounds.Location.Y,dataGridView_items.RowHeadersWidth - 4,e.RowBounds.Height); + + TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(),dataGridView_items.RowHeadersDefaultCellStyle.Font,rectangle, + dataGridView_items.RowHeadersDefaultCellStyle.ForeColor,TextFormatFlags.VerticalCenter | TextFormatFlags.Right); + dataGridView_items.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders); + } + + private void treeView_library_AfterSelect(object sender, TreeViewEventArgs e) + { + if (e.Node != null) + manager.noteCurSelectedNode(e.Node); + } + + private void treeView_base_AfterSelect(object sender, TreeViewEventArgs e) + { + if (e.Node != null) + manager.noteCurSelectedNode(e.Node); + } + public TreeView getBaseTree() + { + return this.treeView_base; + } + public TreeView getLibTree() + { + return this.treeView_library; + } + public DataGridView getItemGridView() + { + return this.dataGridView_items; + } + public TabControl getAttachTabControl() + { + return this.tabControl_attach; + } + public ToolStripProgressBar getProgressBar() + { + return toolStripProgressBar_bottom; + } + private void treeView_library_BeforeCollapse(object sender, TreeViewCancelEventArgs e) + { + e.Cancel = true; + } + private void treeView_base_BeforeCollapse(object sender, TreeViewCancelEventArgs e) + { + e.Cancel = true; + } + + private void toolStripButton_import_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = "Excel文件,mdi缓存文件,DI打包文件(*.xls,*.xlsx)|*.xls;*.xlsx;"; + if (ofd.ShowDialog() == DialogResult.OK) + { + string fpath = ofd.FileName; + bool exists = System.IO.File.Exists(fpath); + if (exists == true) + { + try + { + manager.importData(fpath); + } + catch (Exception ex) + { + MessageBox.Show("数据导入失败。"); + log.Info("数据导入失败,错误信息:",ex); + } + } + } + } + + private void toolStripButton_export_Click(object sender, EventArgs e) + { + ExportTypeDlg exportDlg = new ExportTypeDlg(); + if(exportDlg.ShowDialog()==DialogResult.OK) + { + try + { + manager.exportData(ExportTypeDlg.LastOptionValue, ExportTypeDlg.LastFilePath); + } + catch (Exception ex) + { + MessageBox.Show("数据导出失败。"); + log.Info("数据导出失败,错误信息:",ex); + } + } + } + /// + /// For Quick search + /// + /// + /// + private void toolStripButton_qsearch_Click(object sender, EventArgs e) + { + string findTerm = this.toolStripTextBox_quickSearch.Text.Trim(); + manager.quickSearch(findTerm); + } + private void toolStripTextBox_quickSearch_Enter(object sender, EventArgs e) + { + this.toolStripTextBox_quickSearch.Text = ""; + this.toolStripTextBox_quickSearch.Owner.Update(); + } + + private void toolStripTextBox_quickSearch_Leave(object sender, EventArgs e) + { + if (this.toolStripTextBox_quickSearch.Text.Trim().Length < 1) + this.toolStripTextBox_quickSearch.Text = "Quick Search"; + } + + private void toolStripTextBox_quickSearch_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + string findTerm = this.toolStripTextBox_quickSearch.Text.Trim(); + manager.quickSearch(findTerm); + } + } + private void btn_search_Click(object sender, EventArgs e) + { + if (this.textBox_search1.Text.Trim().Length > 0) + { + manager.doDBDataSearch(); + } + } + public TableLayoutPanel getDBSearchPanel() + { + return this.tableLayoutPanel_search; + } + public SplitContainer getSearchSpliter() + { + return splitContainer_middle; + } + /// + /// 验证登录状态,并打开GCM视图页面 + /// + /// + /// + private void toolStripButton_gcm_Click(object sender, EventArgs e) + { + manager.activeGCMView(); + } + /// + /// 云备份 + /// + /// + /// + private void toolStripButton_download_Click(object sender, EventArgs e) + { + + } + /// + /// 云恢复 + /// + /// + /// + private void toolStripButton_upload_Click(object sender, EventArgs e) + { + + } + /// + /// 本地数据刷新 + /// + /// + /// + private void toolStripButton_refresh_Click(object sender, EventArgs e) + { + + } + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + /// + /// 右键菜单中复制请求 + /// + /// + /// + private void copyCtrlCToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.CopyClipboard(); + DataObject d = dataGridView_items.GetClipboardContent(); + Clipboard.SetDataObject(d); + } + /// + /// 右键菜单中粘贴请求 + /// + /// + /// + private void pasteCtrlVToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.PasteClipboard(); + } + /// + /// 绑定剪贴板复制粘贴的快捷键处理Ctrl+C Ctrl+V Shift+Delete 及 Shift+Insert + /// + /// + /// + private void dataGridView_items_KeyDown(object sender, KeyEventArgs e) + { + if ((e.Control && e.KeyCode == Keys.C) || (e.Shift && e.KeyCode == Keys.Delete)) + { + manager.CopyClipboard(); + } + if ((e.Control && e.KeyCode == Keys.V) || (e.Shift && e.KeyCode == Keys.Insert)) + { + manager.PasteClipboard(); + } + } + + } +} diff --git a/IDCM/IDCM/Forms/IDCMForm.cs b/IDCM/IDCM/Forms/IDCMForm.cs index eb92436..c46453d 100644 --- a/IDCM/IDCM/Forms/IDCMForm.cs +++ b/IDCM/IDCM/Forms/IDCMForm.cs @@ -1,266 +1,266 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using System.Threading; -using System.Configuration; -using IDCM.ViewManager; -using IDCM.Service; -using IDCM.Service.Utils; - -namespace IDCM.Forms -{ - public partial class IDCMForm : Form - { - private IDCMFormManger manager = null; - internal void setManager(IDCMFormManger manager) - { - this.manager = manager; - } - - public IDCMForm() - { - InitializeComponent(); - - } - - private void IDCMForm_Load(object sender, EventArgs e) - { - //Thread.CurrentThread.Name = "IDCMForm" + HandleToken.nextTempID(); - } - - private void MenuStrip_IDCM_ItemAdded(object sender, ToolStripItemEventArgs e) - { - /////////////////////////////////////////////////////////// - //if (e.Item.Text.Length == 0 || e.Item.Text == "还原(&R)" || e.Item.Text == "最小化(&N)") - //{ - // e.Item.Visible = false; - //} - //////////////////////////////////////////////////////////// - //@Deprecated 该方法可以解决图标更新显示的问题,但会导致另外的显示时间处理的问题,有待测试改进。 - } - /// - // 主窗口关闭事件处理 - /// - /// - /// - private void IDCMForm_FormClosed(object sender, FormClosedEventArgs e) - { - manager.closeWorkSpace(); - } - /// - /// 打开或新建一个本地数据库 - /// - /// - /// - private void newToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.reopenWorkSpace(false); - } - public void setLoginTip(string tip=null) - { - ToolStripItemAsyncUtil.SyncSetText(this.ToolStripTextBox_user, tip); - } - /// - /// 打开或新建一个本地数据库 - /// - /// - /// - private void openToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.reopenWorkSpace(true); - } - /// - /// 关闭一个本地数据库 - /// - /// - /// - private void closeToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.closeWorkSpace(); - } - /// - /// 更新字段模板 - /// - /// - /// - private void templatesToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.activeTemplateView(); - } - - /// - /// 身份认证信息配置 - /// - /// - /// - private void authToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.activeAuthView(); - } - - private void showBackTaskToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.activeBackTaskInfoView(); - } - /****************************************************************** - * 键盘事件处理方法 - * @auther JiahaiWu 2014-03-17 - ******************************************************************/ - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) - { - switch (keyData) - { - case Keys.Alt | Keys.F://打开File菜单项 - this.ToolStripMenuItem_file.ShowDropDown(); - break; - case Keys.Alt | Keys.C://打开Configuration菜单项 - this.ToolStripMenuItem_cfg.ShowDropDown(); - break; - case Keys.Alt | Keys.T://打开Tools菜单项 - this.ToolStripMenuItem_tool.ShowDropDown(); - break; - case Keys.Alt | Keys.W://打开Window菜单项 - this.ToolStripMenuItem_window.ShowDropDown(); - break; - case Keys.Alt | Keys.H://打开Help菜单项 - this.ToolStripMenuItem_help.ShowDropDown(); - break; - case Keys.Control | Keys.F://打开查找菜单 - manager.showDBDataSearch(); - break; - case Keys.Control | Keys.Shift | Keys.F://打开前端记录查找菜单 - manager.frontDataSearch(); - break; - case Keys.Control | Keys.Shift | Keys.N: - manager.frontSearchNext(); - break; - case Keys.Control | Keys.Shift | Keys.P: - manager.frontSearchPrev(); - break; - default: - return base.ProcessCmdKey(ref msg, keyData); - } - return true; - } - /// - /// 根据HomeView和GCMView的打开状态控制菜单栏Tools选项下的菜单的可用状态 - /// - /// - /// - private void ToolStripMenuItem_tool_DropDownOpening(object sender, EventArgs e) - { - ManagerI hvManager = manager.getHomeViewManager(); - ManagerI gcmManager = manager.getGCMViewManager(); - localSearchToolStripMenuItem.Enabled = false; - frontPageSearchToolStripMenuItem.Enabled = false; - onlineSearchToolStripMenuItem.Enabled = false; - if (hvManager != null) - { - if (hvManager.isActive()) - { - localSearchToolStripMenuItem.Enabled = true; - frontPageSearchToolStripMenuItem.Enabled = true; - } - } - if (gcmManager != null) - { - if (gcmManager.isActive()) - { - onlineSearchToolStripMenuItem.Enabled = true; - frontPageSearchToolStripMenuItem.Enabled = true; - } - } - - } - private void ToolStripMenuItem_file_DropDownOpening(object sender, EventArgs e) - { - if (IDCM.Core.DataSourceHolder.InWorking) - { - closeToolStripMenuItem.Enabled = true; - newToolStripMenuItem.Enabled = false; - openToolStripMenuItem.Enabled = false; - } - else - { - closeToolStripMenuItem.Enabled = false; - newToolStripMenuItem.Enabled = true; - openToolStripMenuItem.Enabled = true; - } - } - - private void ToolStripMenuItem_window_DropDownOpening(object sender, EventArgs e) - { - if (IDCM.Core.DataSourceHolder.InWorking) - { - showBackTaskToolStripMenuItem.Enabled = true; - } - else - { - showBackTaskToolStripMenuItem.Enabled = false; - } - } - - /// - /// 根据HomeView打开状态控制菜单栏Configuration选项下的菜单的可用状态 - /// - /// - /// - private void ToolStripMenuItem_cfg_DropDownOpening(object sender, EventArgs e) - { - if (IDCM.Core.DataSourceHolder.InWorking) - { - ManagerI hvManager = manager.getHomeViewManager(); - templatesToolStripMenuItem.Enabled = false; - authToolStripMenuItem.Enabled = true; - if (hvManager != null) - { - if (hvManager.isActive()) - { - templatesToolStripMenuItem.Enabled = true; - } - else - { - templatesToolStripMenuItem.Enabled = false; - } - } - } - else - { - templatesToolStripMenuItem.Enabled = false; - } - } - - private void localSearchToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.showDBDataSearch(); - } - - private void onlineSearchToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.showDBDataSearch(); - } - - private void frontPageSearchToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.frontDataSearch(); - } - private void aboutIDCMToolStripMenuItem1_Click(object sender, EventArgs e) - { - AboutDlg aboutDlg = new AboutDlg(); - aboutDlg.ShowDialog(); - } - - private void closeAllToolStripMenuItem_Click(object sender, EventArgs e) - { - manager.closeWorkSpace(); - } - - - - } -} +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Threading; +using System.Configuration; +using IDCM.ViewManager; +using IDCM.Service; +using IDCM.Service.Utils; + +namespace IDCM.Forms +{ + public partial class IDCMForm : Form + { + private IDCMFormManger manager = null; + internal void setManager(IDCMFormManger manager) + { + this.manager = manager; + } + + public IDCMForm() + { + InitializeComponent(); + + } + + private void IDCMForm_Load(object sender, EventArgs e) + { + //Thread.CurrentThread.Name = "IDCMForm" + HandleToken.nextTempID(); + } + + private void MenuStrip_IDCM_ItemAdded(object sender, ToolStripItemEventArgs e) + { + /////////////////////////////////////////////////////////// + //if (e.Item.Text.Length == 0 || e.Item.Text == "还原(&R)" || e.Item.Text == "最小化(&N)") + //{ + // e.Item.Visible = false; + //} + //////////////////////////////////////////////////////////// + //@Deprecated 该方法可以解决图标更新显示的问题,但会导致另外的显示时间处理的问题,有待测试改进。 + } + /// + // 主窗口关闭事件处理 + /// + /// + /// + private void IDCMForm_FormClosed(object sender, FormClosedEventArgs e) + { + manager.closeWorkSpace(); + } + /// + /// 打开或新建一个本地数据库 + /// + /// + /// + private void newToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.reopenWorkSpace(false); + } + public void setLoginTip(string tip=null) + { + ToolStripItemAsyncUtil.SyncSetText(this.ToolStripTextBox_user, tip); + } + /// + /// 打开或新建一个本地数据库 + /// + /// + /// + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.reopenWorkSpace(true); + } + /// + /// 关闭一个本地数据库 + /// + /// + /// + private void closeToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.closeWorkSpace(); + } + /// + /// 更新字段模板 + /// + /// + /// + private void templatesToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.activeTemplateView(); + } + + /// + /// 身份认证信息配置 + /// + /// + /// + private void authToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.activeAuthView(); + } + + private void showBackTaskToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.activeBackTaskInfoView(); + } + /****************************************************************** + * 键盘事件处理方法 + * @auther JiahaiWu 2014-03-17 + ******************************************************************/ + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + switch (keyData) + { + case Keys.Alt | Keys.F://打开File菜单项 + this.ToolStripMenuItem_file.ShowDropDown(); + break; + case Keys.Alt | Keys.C://打开Configuration菜单项 + this.ToolStripMenuItem_cfg.ShowDropDown(); + break; + case Keys.Alt | Keys.T://打开Tools菜单项 + this.ToolStripMenuItem_tool.ShowDropDown(); + break; + case Keys.Alt | Keys.W://打开Window菜单项 + this.ToolStripMenuItem_window.ShowDropDown(); + break; + case Keys.Alt | Keys.H://打开Help菜单项 + this.ToolStripMenuItem_help.ShowDropDown(); + break; + case Keys.Control | Keys.F://打开查找菜单 + manager.showDBDataSearch(); + break; + case Keys.Control | Keys.Shift | Keys.F://打开前端记录查找菜单 + manager.frontDataSearch(); + break; + case Keys.Control | Keys.Shift | Keys.N: + manager.frontSearchNext(); + break; + case Keys.Control | Keys.Shift | Keys.P: + manager.frontSearchPrev(); + break; + default: + return base.ProcessCmdKey(ref msg, keyData); + } + return true; + } + /// + /// 根据HomeView和GCMView的打开状态控制菜单栏Tools选项下的菜单的可用状态 + /// + /// + /// + private void ToolStripMenuItem_tool_DropDownOpening(object sender, EventArgs e) + { + ManagerI hvManager = manager.getHomeViewManager(); + ManagerI gcmManager = manager.getGCMViewManager(); + localSearchToolStripMenuItem.Enabled = false; + frontPageSearchToolStripMenuItem.Enabled = false; + onlineSearchToolStripMenuItem.Enabled = false; + if (hvManager != null) + { + if (hvManager.isActive()) + { + localSearchToolStripMenuItem.Enabled = true; + frontPageSearchToolStripMenuItem.Enabled = true; + } + } + if (gcmManager != null) + { + if (gcmManager.isActive()) + { + onlineSearchToolStripMenuItem.Enabled = true; + frontPageSearchToolStripMenuItem.Enabled = true; + } + } + + } + private void ToolStripMenuItem_file_DropDownOpening(object sender, EventArgs e) + { + if (IDCM.Core.DataSourceHolder.InWorking) + { + closeToolStripMenuItem.Enabled = true; + newToolStripMenuItem.Enabled = false; + openToolStripMenuItem.Enabled = false; + } + else + { + closeToolStripMenuItem.Enabled = false; + newToolStripMenuItem.Enabled = true; + openToolStripMenuItem.Enabled = true; + } + } + + private void ToolStripMenuItem_window_DropDownOpening(object sender, EventArgs e) + { + if (IDCM.Core.DataSourceHolder.InWorking) + { + showBackTaskToolStripMenuItem.Enabled = true; + } + else + { + showBackTaskToolStripMenuItem.Enabled = false; + } + } + + /// + /// 根据HomeView打开状态控制菜单栏Configuration选项下的菜单的可用状态 + /// + /// + /// + private void ToolStripMenuItem_cfg_DropDownOpening(object sender, EventArgs e) + { + if (IDCM.Core.DataSourceHolder.InWorking) + { + ManagerI hvManager = manager.getHomeViewManager(); + templatesToolStripMenuItem.Enabled = false; + authToolStripMenuItem.Enabled = true; + if (hvManager != null) + { + if (hvManager.isActive()) + { + templatesToolStripMenuItem.Enabled = true; + } + else + { + templatesToolStripMenuItem.Enabled = false; + } + } + } + else + { + templatesToolStripMenuItem.Enabled = false; + } + } + + private void localSearchToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.showDBDataSearch(); + } + + private void onlineSearchToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.showDBDataSearch(); + } + + private void frontPageSearchToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.frontDataSearch(); + } + private void aboutIDCMToolStripMenuItem1_Click(object sender, EventArgs e) + { + AboutDlg aboutDlg = new AboutDlg(); + aboutDlg.ShowDialog(); + } + + private void closeAllToolStripMenuItem_Click(object sender, EventArgs e) + { + manager.closeWorkSpace(); + } + + + + } +} diff --git a/IDCM/IDCM/Modules/LocalDataSetBuilder.cs b/IDCM/IDCM/Modules/LocalDataSetBuilder.cs index 555c34b..3713242 100644 --- a/IDCM/IDCM/Modules/LocalDataSetBuilder.cs +++ b/IDCM/IDCM/Modules/LocalDataSetBuilder.cs @@ -1,933 +1,933 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using System.Drawing; -using System.Data; -using IDCM.Data.Base; -using IDCM.Service.Common; -using IDCM.Data.Base.Utils; -using IDCM.Service.Utils; -using IDCM.Core; -using System.IO; -using NPOI.XSSF.UserModel; -using NPOI.HSSF.UserModel; -using NPOI.SS.UserModel; -using IDCM.Forms; - -namespace IDCM.Modules -{ - class LocalDataSetBuilder - { - #region 构造&析构 - /// - /// 初始化个人资源目录树 - /// - /// - public LocalDataSetBuilder(DataGridView dgv_items, TabControl tc_attach) - { - this.itemDGV = dgv_items; - this.attachTC = tc_attach; - /////////////////////////////// - //AddHeaderCheckBox(); - //////////////////////////// - //本地数据提交优先考虑只读软连接模式,全选操作模式暂行屏蔽,有待增设状态后再利用。 - ///////////////////////// - //CustomRowSelectionStyle(); - //////////////////////////// - //该方法在单元格选择情况下有缺陷,暂行屏蔽,有待改进。 - } - ~LocalDataSetBuilder() - { - Dispose(); - } - public void Dispose() - { - itemDGV = null; - attachTC = null; - } - #endregion - #region 实例对象保持部分 - private long CUR_LID = CatalogNode.REC_ALL; - - public long CURRENT_LID - { - get { return CUR_LID; } - } - private long CUR_PLID = CatalogNode.REC_ALL; - - public long CURRENT_PLID - { - get { return CUR_PLID; } - } - - private long CUR_RID = -1L; - - public long CURRENT_RID - { - get { return CUR_RID; } - set { CUR_RID=value; } - } - /// - /// 当前表单显示的查询条件缓存 - /// - private volatile string queryCondtion = null; - - public string QueryCondtion - { - get { return queryCondtion; } - } - - private volatile int TotalCheckedCheckBoxes = 0; - private volatile CheckBox HeaderCheckBox = null; - private volatile bool IsHeaderCheckBoxClicked = false; - private volatile int oldRowSelectionIndex = 0; - #endregion - - - #region 自定义itemDGV支持多行选取的代码实现 - /// - /// Add the checkBox into the datagridview - /// - private void AddHeaderCheckBox() - { - HeaderCheckBox = new CheckBox(); - HeaderCheckBox.Size = new Size(15, 15); - - //Add the CheckBox into the DataGridView - this.itemDGV.Controls.Add(HeaderCheckBox); - HeaderCheckBox.KeyUp += new KeyEventHandler(HeaderCheckBox_KeyUp); - HeaderCheckBox.MouseClick += new MouseEventHandler(HeaderCheckBox_MouseClick); - itemDGV.CellValueChanged += new DataGridViewCellEventHandler(dgvSelectAll_CellValueChanged); - itemDGV.CurrentCellDirtyStateChanged += new EventHandler(dgvSelectAll_CurrentCellDirtyStateChanged); - itemDGV.CellPainting += new DataGridViewCellPaintingEventHandler(dgvSelectAll_CellPainting); - } - /// - /// 当Checkbox被点击时的事件处理 - /// - /// - /// - private void HeaderCheckBox_MouseClick(object sender, MouseEventArgs e) - { - HeaderCheckBoxClick((CheckBox)sender); - } - /// - /// 获取空格键输入的键盘弹起事件处理 - /// - /// - /// - private void HeaderCheckBox_KeyUp(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Space) - HeaderCheckBoxClick((CheckBox)sender); - } - /// - /// 获取记录改变消息事件,按单元格识别判断如何处理事件响应 - /// 说明: - /// 1.如果单击Checkbox那么设定Checkbox选中操作 - /// - /// - /// - private void dgvSelectAll_CellValueChanged(object sender, DataGridViewCellEventArgs e) - { - if (e.RowIndex < 0) - return; - if (e.ColumnIndex == 0 && !IsHeaderCheckBoxClicked) - RowCheckBoxClick((DataGridViewCheckBoxCell)itemDGV[e.ColumnIndex, e.RowIndex]); - } - /// - /// 当单元格状态改变时,事件触发机制 - /// - /// - /// - private void dgvSelectAll_CurrentCellDirtyStateChanged(object sender, EventArgs e) - { - if (itemDGV.CurrentCell!=null && itemDGV.CurrentCell.OwningColumn.Name.Equals(CTDRecordA.CTD_RID)) - itemDGV.CommitEdit(DataGridViewDataErrorContexts.Commit); - } - /// - /// 当单元格需要绘制时,捕获事件重绘Checkbox - /// - /// - /// - private void dgvSelectAll_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) - { - if (e.RowIndex == -1 && e.ColumnIndex == 0) - ResetHeaderCheckBoxLocation(e.ColumnIndex, e.RowIndex); - } - /// - /// 重置Checkbox绘制图层的显示位置 - /// - /// - /// - private void ResetHeaderCheckBoxLocation(int ColumnIndex, int RowIndex) - { - //Get the column header cell bounds - Rectangle oRectangle = this.itemDGV.GetCellDisplayRectangle(ColumnIndex, RowIndex, true); - - Point oPoint = new Point(); - - oPoint.X = oRectangle.Location.X + (oRectangle.Width - HeaderCheckBox.Width) / 2 + 1; - oPoint.Y = oRectangle.Location.Y + (oRectangle.Height - HeaderCheckBox.Height) / 2 + 1; - - //Change the location of the CheckBox to make it stay on the header - HeaderCheckBox.Location = oPoint; - } - /// - /// 全选 - /// - /// - private void HeaderCheckBoxClick(CheckBox HCheckBox) - { - IsHeaderCheckBoxClicked = true; - - foreach (DataGridViewRow Row in itemDGV.Rows) - ((DataGridViewCheckBoxCell)Row.Cells[0]).Value = HCheckBox.Checked; - itemDGV.RefreshEdit(); - int TotalCheckBoxes = itemDGV.Rows.Count; - TotalCheckedCheckBoxes = HCheckBox.Checked ? TotalCheckBoxes : 0; - IsHeaderCheckBoxClicked = false; - } - /// - /// 选中一行 - /// - /// - private void RowCheckBoxClick(DataGridViewCheckBoxCell RCheckBox) - { - int TotalCheckBoxes = itemDGV.Rows.Count; - if (RCheckBox != null) - { - //Modifiy Counter; - if ((bool)RCheckBox.Value && TotalCheckedCheckBoxes < TotalCheckBoxes) - TotalCheckedCheckBoxes++; - else if (TotalCheckedCheckBoxes > 0) - TotalCheckedCheckBoxes--; - - //Change state of the header CheckBox. - if (TotalCheckedCheckBoxes < TotalCheckBoxes) - HeaderCheckBox.Checked = false; - else if (TotalCheckedCheckBoxes == TotalCheckBoxes) - HeaderCheckBox.Checked = true; - } - } -#endregion - - #region 自定义itemDGV行选中的外观样式 - private void CustomRowSelectionStyle() - { - this.itemDGV.RowTemplate.DefaultCellStyle.SelectionBackColor = Color.Transparent; - // Attach handlers to DataGridView events. - this.itemDGV.ColumnWidthChanged += new - DataGridViewColumnEventHandler(itemDGV_ColumnWidthChanged); - this.itemDGV.RowPrePaint += new - DataGridViewRowPrePaintEventHandler(itemDGV_RowPrePaint); - this.itemDGV.RowPostPaint += new - DataGridViewRowPostPaintEventHandler(itemDGV_RowPostPaint); - this.itemDGV.CurrentCellChanged += new - EventHandler(itemDGV_CurrentCellChanged); - this.itemDGV.RowHeightChanged += new - DataGridViewRowEventHandler(itemDGV_RowHeightChanged); - } - // Forces the control to repaint itself when the user - // manually changes the width of a column. - void itemDGV_ColumnWidthChanged(object sender, - DataGridViewColumnEventArgs e) - { - this.itemDGV.Invalidate(); - } - - // Forces the row to repaint itself when the user changes the - // current cell. This is necessary to refresh the focus rectangle. - void itemDGV_CurrentCellChanged(object sender, EventArgs e) - { - if (oldRowSelectionIndex != -1) - { - this.itemDGV.InvalidateRow(oldRowSelectionIndex); - } - oldRowSelectionIndex = this.itemDGV.CurrentCellAddress.Y; - } - - // Paints the custom selection background for selected rows. - void itemDGV_RowPrePaint(object sender,DataGridViewRowPrePaintEventArgs e) - { - // Do not automatically paint the focus rectangle. - e.PaintParts &= ~DataGridViewPaintParts.Focus; - - // Determine whether the cell should be painted - // with the custom selection background. - if ((e.State & DataGridViewElementStates.Selected) == - DataGridViewElementStates.Selected) - { - // Calculate the bounds of the row. - Rectangle rowBounds = new Rectangle( - this.itemDGV.RowHeadersWidth, e.RowBounds.Top, - this.itemDGV.Columns.GetColumnsWidth( - DataGridViewElementStates.Visible) - - this.itemDGV.HorizontalScrollingOffset + 1, - e.RowBounds.Height); - - // Paint the custom selection background. - using (Brush backbrush = - new System.Drawing.Drawing2D.LinearGradientBrush(rowBounds, - this.itemDGV.DefaultCellStyle.SelectionBackColor, - Color.LightSkyBlue, - System.Drawing.Drawing2D.LinearGradientMode.Horizontal)) - { - e.Graphics.FillRectangle(backbrush, rowBounds); - } - } - } - - // Paints the content that spans multiple columns and the focus rectangle. - void itemDGV_RowPostPaint(object sender, - DataGridViewRowPostPaintEventArgs e) - { - // Calculate the bounds of the row. - Rectangle rowBounds = new Rectangle( - this.itemDGV.RowHeadersWidth, e.RowBounds.Top, - this.itemDGV.Columns.GetColumnsWidth( - DataGridViewElementStates.Visible) - - this.itemDGV.HorizontalScrollingOffset + 1, - e.RowBounds.Height); - - SolidBrush forebrush = null; - try - { - // Determine the foreground color. - if ((e.State & DataGridViewElementStates.Selected) == - DataGridViewElementStates.Selected) - { - forebrush = new SolidBrush(e.InheritedRowStyle.SelectionForeColor); - } - else - { - forebrush = new SolidBrush(e.InheritedRowStyle.ForeColor); - } - - DataGridViewRow dgvr = this.itemDGV.Rows.SharedRow(e.RowIndex); - if (dgvr != null && dgvr.Index > 0) - { - // Get the content that spans multiple columns. - object recipe = - this.itemDGV.Rows.SharedRow(e.RowIndex).Cells[2].Value; - - if (recipe != null) - { - String text = recipe.ToString(); - - // Calculate the bounds for the content that spans multiple - // columns, adjusting for the horizontal scrolling position - // and the current row height, and displaying only whole - // lines of text. - Rectangle textArea = rowBounds; - textArea.X -= this.itemDGV.HorizontalScrollingOffset; - textArea.Width += this.itemDGV.HorizontalScrollingOffset; - textArea.Y += rowBounds.Height - e.InheritedRowStyle.Padding.Bottom; - textArea.Height -= rowBounds.Height - - e.InheritedRowStyle.Padding.Bottom; - textArea.Height = (textArea.Height / e.InheritedRowStyle.Font.Height) * - e.InheritedRowStyle.Font.Height; - - // Calculate the portion of the text area that needs painting. - RectangleF clip = textArea; - clip.Width -= this.itemDGV.RowHeadersWidth + 1 - clip.X; - clip.X = this.itemDGV.RowHeadersWidth + 1; - RectangleF oldClip = e.Graphics.ClipBounds; - e.Graphics.SetClip(clip); - - // Draw the content that spans multiple columns. - e.Graphics.DrawString( - text, e.InheritedRowStyle.Font, forebrush, textArea); - - e.Graphics.SetClip(oldClip); - } - } - } - finally - { - forebrush.Dispose(); - } - - if (this.itemDGV.CurrentCellAddress.Y == e.RowIndex) - { - // Paint the focus rectangle. - e.DrawFocus(rowBounds, true); - } - } - - // Adjusts the padding when the user changes the row height so that - // the normal cell content is fully displayed and any extra - // height is used for the content that spans multiple columns. - void itemDGV_RowHeightChanged(object sender, - DataGridViewRowEventArgs e) - { - // Calculate the new height of the normal cell content. - Int32 preferredNormalContentHeight = - e.Row.GetPreferredHeight(e.Row.Index, - DataGridViewAutoSizeRowMode.AllCellsExceptHeader, true) - - e.Row.DefaultCellStyle.Padding.Bottom; - - // Specify a new padding. - Padding newPadding = e.Row.DefaultCellStyle.Padding; - newPadding.Bottom = e.Row.Height - preferredNormalContentHeight; - e.Row.DefaultCellStyle.Padding = newPadding; - } - #endregion - - - /// - /// 从剪贴板粘贴文本型数据记录到目标区域 - /// This will be moved to the util class so it can service any paste into a DGV - /// - internal void PasteClipboard() - { - try - { - string s = Clipboard.GetText(); - string[] lines = s.Split('\n'); - int iFail = 0, iRow = itemDGV.CurrentCell.RowIndex; - int iCol = itemDGV.CurrentCell.ColumnIndex; - DataGridViewCell oCell; - foreach (string line in lines) - { - if (iRow < itemDGV.RowCount && line.Length > 0) - { - string[] sCells = line.Split('\t'); - for (int i = 0; i < sCells.GetLength(0); ++i) - { - if (iCol + i < this.itemDGV.ColumnCount) - { - oCell = itemDGV[iCol + i, iRow]; - if (!oCell.ReadOnly) - { - if (oCell.Value == null || oCell.Value.ToString() != sCells[i]) - { - oCell.Value = Convert.ChangeType(sCells[i], oCell.ValueType); - oCell.Style.BackColor = Color.Tomato; - } - else - iFail++;//only traps a fail if the data has changed and you are pasting into a read only cell - } - } - else - { break; } - } - iRow++; - } - else - { break; } - if (iFail > 0) - MessageBox.Show(string.Format("{0} updates failed due to read only column setting", iFail)); - } - } - catch (FormatException) - { - MessageBox.Show("The data you pasted is in the wrong format for the cell"); - return; - } - } - - /// - /// 根据指定的索引位序更新显示附加的属性信息 - /// - /// - /// - public void selectViewRecord(DataGridViewRow dgvr) - { - int rIdx = dgvr.DataGridView.Columns[CTDRecordA.CTD_RID.ToString()].Index; - if (dgvr.Cells.Count > rIdx) - { - CUR_RID = Convert.ToInt64(dgvr.Cells[rIdx].FormattedValue.ToString()); - DataTable table = LocalRecordMHub.queryCTDRecord(DataSourceHolder.DataSource, CUR_RID.ToString()); - if (table.Rows.Count > 0) - { - DataRow dr = table.Rows[0]; - List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); - showReferences(viewAttrs, dr); - } - } - } - - /// - /// 根据指定的数据集合加载数据报表显示,指定的字段映射为空时则使用默认的字段映射显示规则。 - /// - /// - /// - /// - public void loadDataSetView() - { - List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource);//获取所有属性名称集合 - lock (LocalDataGridView_Lock) - { - if (itemDGV.ColumnCount > 0) - { - DGVAsyncUtil.syncRemoveAllRow(itemDGV); - resetReferences(viewAttrs); - } - else - { - //行列表头显示 - loadDGVColumns(viewAttrs); - loadReferences(viewAttrs); - } - } - } - /// - /// 标记目标数据报表关联文档目录键值 - /// - public void noteDataSetLib(TreeNode filterNode) - { - long lid = Convert.ToInt64(filterNode.Name); - - if (filterNode.Level > 0) - { - CUR_LID = lid; - CUR_PLID = Convert.ToInt64(filterNode.Parent.Name); - } - else - { - CUR_LID = lid; - CUR_PLID = lid; - } - } - /// - /// 删除数据归档目标的数据记录,置入未分类目录 - /// - /// - /// - public void trashDataSet(TreeNode filteNode, int newlid = CatalogNode.REC_TRASH) - { - List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); - long lid = Convert.ToInt64(filteNode.Name); - lock (LocalDataGridView_Lock) - { - if (filteNode.Level > 0) - { - CUR_LID = lid; - CUR_PLID = Convert.ToInt64(filteNode.Parent.Name); - } - else - { - CUR_LID = lid; - CUR_PLID = lid; - } - itemDGV.Rows.Clear(); - resetReferences(viewAttrs); - string filterLids = lid.ToString(); - if (lid > 0) - { - long[] lids = LocalRecordMHub.extractToLids(DataSourceHolder.DataSource,lid); - if (lids != null) - { - filterLids = ""; - foreach (long _lid in lids) - { - filterLids += "," + _lid; - } - filterLids = filterLids.Substring(1); - } - } - //数据归档更新 - LocalRecordMHub.updateCTCRecordLid(DataSourceHolder.DataSource, newlid, CatalogNode.REC_ALL, filterLids); - } - } - /// - /// 删除数据归档目标的数据记录,置入未分类目录 - /// - /// - public void dropDataSet(TreeNode filteNode) - { - List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); - long lid = Convert.ToInt64(filteNode.Name); - lock (LocalDataGridView_Lock) - { - if (filteNode.Level > 0) - { - CUR_LID = lid; - CUR_PLID = Convert.ToInt64(filteNode.Parent.Name); - } - else - { - CUR_LID = lid; - CUR_PLID = lid; - } - itemDGV.Rows.Clear(); - resetReferences(viewAttrs); - string filterLids = lid.ToString(); - if (lid > 0) - { - long[] lids = LocalRecordMHub.extractToLids(DataSourceHolder.DataSource,lid); - if (lids != null) - { - filterLids = ""; - foreach (long _lid in lids) - { - filterLids += "," + _lid; - } - filterLids = filterLids.Substring(1); - } - } - //数据归档更新 - LocalRecordMHub.dropCTCRecordLid(DataSourceHolder.DataSource, filterLids); - } - } - - - /// - /// 加载数据表头展示 - /// - /// - /// - private void loadDGVColumns(List viewAttrs) - { - DGVAsyncUtil.syncClearAll(itemDGV); - //默认前置的选择列 - DataGridViewCheckBoxColumn chxCol = new DataGridViewCheckBoxColumn(); - chxCol.ReadOnly = true; - chxCol.Resizable = DataGridViewTriState.False; - chxCol.FlatStyle = FlatStyle.Popup; - chxCol.CellTemplate.Style.ForeColor = Color.LightGray; - DGVAsyncUtil.syncAddCol(itemDGV,chxCol); - //创建显性列属性 - foreach (string attr in viewAttrs) - { - int viewOrder = LocalRecordMHub.getViewOrder(DataSourceHolder.DataSource, attr);//返回属性显示位序 - log.Debug("##"+attr+"->"+viewOrder); - if (viewOrder < CustomTColMap.MaxMainViewCount) - { - CustomTColDef ctcd = LocalRecordMHub.getCustomTColDef(DataSourceHolder.DataSource,attr); - Type colType = RecordControlTypeConverter.getDGVColType(ctcd.AttrType); - DataGridViewColumn dgvCol = Activator.CreateInstance(colType) as DataGridViewColumn; - dgvCol.Name = ctcd.Attr; - dgvCol.HeaderText = CVNameConverter.toViewName(ctcd.Attr); - if(attr.Equals(CTDRecordA.CTD_RID)|| attr.Equals(CTDRecordA.CTD_PLID) || attr.Equals(CTDRecordA.CTD_LID)){ - dgvCol.Visible = false; - dgvCol.Width = 0; - } - DGVAsyncUtil.syncAddCol(itemDGV, dgvCol); - if (viewOrder != dgvCol.Index) - LocalRecordMHub.updateViewOrder(DataSourceHolder.DataSource,attr, dgvCol.Index); - } - } - } - /// - /// 加载附加注解字段名展示 - /// - /// - /// - private void loadReferences(List viewAttrs) - { - //清理tabControl控件 - foreach (TabPage tp in attachTC.TabPages) - { - foreach (Control ictl in tp.Controls) - { - ictl.Dispose(); - } - } - //重新build references Page - TabPage tabPage = attachTC.TabPages["references"]; - int idx = 0; - foreach (string attr in viewAttrs) - { - if (LocalRecordMHub.getViewOrder(DataSourceHolder.DataSource, attr) < CustomTColMap.MaxMainViewCount) - { - ++idx; - continue; - } - CustomTColDef ctcd = LocalRecordMHub.getCustomTColDef(DataSourceHolder.DataSource, attr); - Panel panel = new Panel(); - panel.Name = "referPanel_" + idx; - panel.Dock = DockStyle.Top; - panel.Margin = new Padding(0, 5, 0, 0); - panel.BorderStyle = System.Windows.Forms.BorderStyle.None; - panel.Height = 45; - //panel.BorderStyle = BorderStyle.FixedSingle; - TextBox label = new TextBox(); - label.ReadOnly = true; - label.BorderStyle = System.Windows.Forms.BorderStyle.None; - label.BackColor = Color.WhiteSmoke; - label.Name = "referLabel_" + ctcd.Attr; - string pattr =CVNameConverter.toViewName(ctcd.Attr); - label.Text = pattr; - label.Font = new Font(label.Font, label.Font.Style ^ FontStyle.Bold); - label.Height = 14; - label.Dock = DockStyle.Top; - panel.Controls.Add(label); - Type ctype = RecordControlTypeConverter.getControlType(ctcd.AttrType); - Control control = Activator.CreateInstance(ctype) as Control; - if (control is TextBox) - { - (control as TextBox).BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - } - control.Name = pattr; - control.Dock = DockStyle.Bottom; - control.Height = 20; - control.Margin = new Padding(0, 1, 0, 0); - control.TextChanged += Refers_record_TextChanged; - panel.Controls.Add(control); - tabPage.Controls.Add(panel); - ++idx; - } - Label ridLabel = new Label(); - ridLabel.Name = "ctd_rid_Label"; - ridLabel.Visible = false; - ridLabel.Height = 0; - ridLabel.Dock = DockStyle.Top; - ridLabel.Margin = new Padding(0, 0, 0, 0); - tabPage.Controls.Add(ridLabel); - } - /// - /// 根据指定的数据行置空所有附加的属性信息 - /// - /// - public void resetReferences(List viewAttrs) - { - showReferences(viewAttrs, null); - } - /// - /// 根据指定的数据行更新显示附加的属性信息 - /// - /// - /// - /// dr为null则等效于清空表单操作 - public void showReferences(List viewAttrs, DataRow dr = null)//参数是所有属性名称集合 - { - TabPage tabPage = attachTC.TabPages["references"]; - if (dr != null) - { - (tabPage.Controls["ctd_rid_Label"] as Label).Text = dr[CTDRecordA.CTD_RID].ToString(); - } - foreach (Control ctl in tabPage.Controls)//获取选项卡内所有集合 - { - if (ctl is Panel)//如果空间是面板 - { - //获取,选择项卡中的集合名称从referPanel_开始处的索引 - int idx = Convert.ToInt32(ctl.Name.Substring("referPanel_".Length)); - - //从viewAttrs[idx]第一位开始,viewAttrs[idx]-2个长度的字符串 - string attr =CVNameConverter.toViewName(viewAttrs[idx]);//注意: - Control ictl = ctl.Controls[attr]; - if (ictl != null) - { - if (ictl is TextBox) - { - (ictl as TextBox).Text = dr == null ? "" : dr[attr].ToString(); - } - else if (ictl is ComboBox) - { - (ictl as ComboBox).FormatString = dr == null ? "" : dr[attr].ToString(); - } - else if (ictl is DateTimePicker) - { - (ictl as DateTimePicker).CustomFormat = dr == null ? "" : dr[attr].ToString(); - } - } - } - } - } - public DataGridViewCell quickSearch(string findTerm) - { - if (findTerm.Length > 0) - { - DataGridViewCell ncell = null; - if (itemDGV.SelectedCells != null && itemDGV.SelectedCells.Count > 0) - { - if(itemDGV.SelectedCells[0].Displayed) - ncell = itemDGV.SelectedCells[0]; - } - while ((ncell = nextTextCell(ncell)) != null) - { - string cellval = DGVUtil.getCellValue(ncell,""); - if (cellval.ToLower().Contains(findTerm.ToLower())) - { - return ncell; - } - } - if (ncell == null) - { - MessageBox.Show("It's reached the end, and no subsequent matches."); - } - } - return null; - } - public void doDBDataSearch(string whereCmd) - { - //unimplemented - } - /// - /// 下一个单元格定位,如定位失败返回null - /// - /// - private DataGridViewCell nextTextCell(DataGridViewCell cell = null) - { - DataGridViewCell ncell = null; - int rowCount = DGVUtil.getRowCount(itemDGV); - int columnCount = DGVUtil.getTextColumnCount(itemDGV); - int rowIndex = cell == null ? 0 : cell.RowIndex; - int colIndex = cell == null ? 0 : cell.ColumnIndex + 1; - if (colIndex >= columnCount) - { - rowIndex = rowIndex + 1; - colIndex = 0; - } - if (colIndex < columnCount && rowIndex - /// 添加新纪录,自动生成默认的数据字段值 - /// - /// - public void addNewRecord() - { - long nuid = LocalRecordMHub.addNewRecord(DataSourceHolder.DataSource,CUR_LID, CURRENT_PLID); - if (nuid > 0) - { - int idx = itemDGV.Rows.Add(); - itemDGV.Rows[idx].Cells[CTDRecordA.CTD_RID].Value = nuid; - itemDGV.Rows[idx].Cells[CTDRecordA.CTD_LID].Value = CUR_LID; - itemDGV.Rows[idx].Cells[CTDRecordA.CTD_PLID].Value = CURRENT_PLID; - } - } - - /// - /// 伴随用户修改操作同步更新记录属性信息 - /// - /// - /// - public static void Refers_record_TextChanged(object sender, EventArgs e) - { - if ((sender as Control).Focused) - { - string rid = null; - string attrName = null; - string cellVal = null; - if (sender is TextBox) - { - TextBox tb = (sender as TextBox); - rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; - attrName = tb.Name; - cellVal = tb.Text.Trim(); - } - else if (sender is ComboBox) - { - ComboBox tb = (sender as ComboBox); - rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; - attrName = tb.Name; - cellVal = tb.FormatString.Trim(); - } - else if (sender is DateTimePicker) - { - DateTimePicker tb = (sender as DateTimePicker); - rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; - attrName = tb.Name; - cellVal = tb.Text.Trim(); - } - if (rid.Length > 0 && cellVal.Length > 0) - { - LocalRecordMHub.updateAttrVal(DataSourceHolder.DataSource,rid, cellVal, "[" + attrName + "]"); - } - } - } - /// - /// 解析指定的Excel文档,验证数据转换的属性映射条件. - /// - /// - /// - public bool checkForExcelImport(string fpath, ref Dictionary dataMapping, Form pForm) - { - if (fpath == null || fpath.Length < 1) - return false; - string fullPath = System.IO.Path.GetFullPath(fpath); - IWorkbook workbook = null; - try - { - using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) - { - workbook = WorkbookFactory.Create(fs); - ISheet dataSheet = workbook.GetSheet("Core Datasets"); - if (dataSheet == null) - dataSheet = workbook.GetSheetAt(0); - return fetchSheetMappingInfo(dataSheet, ref dataMapping, pForm) && dataMapping.Count > 0; - } - } - catch (Exception ex) - { - log.Info("ERROR: Excel文件导入失败! ", ex); - MessageBox.Show("ERROR: Excel文件导入失败! " + ex.Message + "\n" + ex.StackTrace); - } - return false; - } - /// - /// 通过NPOI读取Excel文档,转换可识别内容至本地数据库中 - /// - /// - /// - private bool fetchSheetMappingInfo(ISheet sheet, ref Dictionary dataMapping,Form pForm) - { - int skipIdx = 1; - if (sheet == null || sheet.LastRowNum < skipIdx) //no data - return false; - ///////////////////////////////////////////////////////// - IRow titleRow = sheet.GetRow(skipIdx - 1); - int columnSize = titleRow.LastCellNum; - int rowSize = sheet.LastRowNum; - List xlscols = new List(columnSize); - for (int i = titleRow.FirstCellNum; i < columnSize; i++) - { - ICell titleCell = titleRow.GetCell(i); - if (titleCell != null && titleCell.ToString().Length > 0) - { - string cellData = titleCell.ToString(); - xlscols.Add(CVNameConverter.toViewName(cellData.Trim().ToLower())); - } - else - { - xlscols.Add(null); - } - } - /////////////////////////////////////////////////////////////// - using (AttrMapOptionDlg amoDlg = new AttrMapOptionDlg()) - { - amoDlg.BringToFront(); - amoDlg.setInitCols(xlscols, LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource,false), ref dataMapping); - amoDlg.ShowDialog(); - /////////////////////////////////////////// - if (amoDlg.DialogResult == DialogResult.OK) - return true; - } - return false; - } - private DataGridView itemDGV; - - public DataGridView ItemDGV - { - get { return itemDGV; } - } - private TabControl attachTC; - - public TabControl AttachTC - { - get { return attachTC; } - } - private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); - /// - /// 本地表单数据视图控件的独占保持的共享锁对象 - /// - public static object LocalDataGridView_Lock = new object(); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Data; +using IDCM.Data.Base; +using IDCM.Service.Common; +using IDCM.Data.Base.Utils; +using IDCM.Service.Utils; +using IDCM.Core; +using System.IO; +using NPOI.XSSF.UserModel; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using IDCM.Forms; + +namespace IDCM.Modules +{ + class LocalDataSetBuilder + { + #region 构造&析构 + /// + /// 初始化个人资源目录树 + /// + /// + public LocalDataSetBuilder(DataGridView dgv_items, TabControl tc_attach) + { + this.itemDGV = dgv_items; + this.attachTC = tc_attach; + /////////////////////////////// + //AddHeaderCheckBox(); + //////////////////////////// + //本地数据提交优先考虑只读软连接模式,全选操作模式暂行屏蔽,有待增设状态后再利用。 + ///////////////////////// + //CustomRowSelectionStyle(); + //////////////////////////// + //该方法在单元格选择情况下有缺陷,暂行屏蔽,有待改进。 + } + ~LocalDataSetBuilder() + { + Dispose(); + } + public void Dispose() + { + itemDGV = null; + attachTC = null; + } + #endregion + #region 实例对象保持部分 + private long CUR_LID = CatalogNode.REC_ALL; + + public long CURRENT_LID + { + get { return CUR_LID; } + } + private long CUR_PLID = CatalogNode.REC_ALL; + + public long CURRENT_PLID + { + get { return CUR_PLID; } + } + + private long CUR_RID = -1L; + + public long CURRENT_RID + { + get { return CUR_RID; } + set { CUR_RID=value; } + } + /// + /// 当前表单显示的查询条件缓存 + /// + private volatile string queryCondtion = null; + + public string QueryCondtion + { + get { return queryCondtion; } + } + + private volatile int TotalCheckedCheckBoxes = 0; + private volatile CheckBox HeaderCheckBox = null; + private volatile bool IsHeaderCheckBoxClicked = false; + private volatile int oldRowSelectionIndex = 0; + #endregion + + + #region 自定义itemDGV支持多行选取的代码实现 + /// + /// Add the checkBox into the datagridview + /// + private void AddHeaderCheckBox() + { + HeaderCheckBox = new CheckBox(); + HeaderCheckBox.Size = new Size(15, 15); + + //Add the CheckBox into the DataGridView + this.itemDGV.Controls.Add(HeaderCheckBox); + HeaderCheckBox.KeyUp += new KeyEventHandler(HeaderCheckBox_KeyUp); + HeaderCheckBox.MouseClick += new MouseEventHandler(HeaderCheckBox_MouseClick); + itemDGV.CellValueChanged += new DataGridViewCellEventHandler(dgvSelectAll_CellValueChanged); + itemDGV.CurrentCellDirtyStateChanged += new EventHandler(dgvSelectAll_CurrentCellDirtyStateChanged); + itemDGV.CellPainting += new DataGridViewCellPaintingEventHandler(dgvSelectAll_CellPainting); + } + /// + /// 当Checkbox被点击时的事件处理 + /// + /// + /// + private void HeaderCheckBox_MouseClick(object sender, MouseEventArgs e) + { + HeaderCheckBoxClick((CheckBox)sender); + } + /// + /// 获取空格键输入的键盘弹起事件处理 + /// + /// + /// + private void HeaderCheckBox_KeyUp(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Space) + HeaderCheckBoxClick((CheckBox)sender); + } + /// + /// 获取记录改变消息事件,按单元格识别判断如何处理事件响应 + /// 说明: + /// 1.如果单击Checkbox那么设定Checkbox选中操作 + /// + /// + /// + private void dgvSelectAll_CellValueChanged(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) + return; + if (e.ColumnIndex == 0 && !IsHeaderCheckBoxClicked) + RowCheckBoxClick((DataGridViewCheckBoxCell)itemDGV[e.ColumnIndex, e.RowIndex]); + } + /// + /// 当单元格状态改变时,事件触发机制 + /// + /// + /// + private void dgvSelectAll_CurrentCellDirtyStateChanged(object sender, EventArgs e) + { + if (itemDGV.CurrentCell!=null && itemDGV.CurrentCell.OwningColumn.Name.Equals(CTDRecordA.CTD_RID)) + itemDGV.CommitEdit(DataGridViewDataErrorContexts.Commit); + } + /// + /// 当单元格需要绘制时,捕获事件重绘Checkbox + /// + /// + /// + private void dgvSelectAll_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) + { + if (e.RowIndex == -1 && e.ColumnIndex == 0) + ResetHeaderCheckBoxLocation(e.ColumnIndex, e.RowIndex); + } + /// + /// 重置Checkbox绘制图层的显示位置 + /// + /// + /// + private void ResetHeaderCheckBoxLocation(int ColumnIndex, int RowIndex) + { + //Get the column header cell bounds + Rectangle oRectangle = this.itemDGV.GetCellDisplayRectangle(ColumnIndex, RowIndex, true); + + Point oPoint = new Point(); + + oPoint.X = oRectangle.Location.X + (oRectangle.Width - HeaderCheckBox.Width) / 2 + 1; + oPoint.Y = oRectangle.Location.Y + (oRectangle.Height - HeaderCheckBox.Height) / 2 + 1; + + //Change the location of the CheckBox to make it stay on the header + HeaderCheckBox.Location = oPoint; + } + /// + /// 全选 + /// + /// + private void HeaderCheckBoxClick(CheckBox HCheckBox) + { + IsHeaderCheckBoxClicked = true; + + foreach (DataGridViewRow Row in itemDGV.Rows) + ((DataGridViewCheckBoxCell)Row.Cells[0]).Value = HCheckBox.Checked; + itemDGV.RefreshEdit(); + int TotalCheckBoxes = itemDGV.Rows.Count; + TotalCheckedCheckBoxes = HCheckBox.Checked ? TotalCheckBoxes : 0; + IsHeaderCheckBoxClicked = false; + } + /// + /// 选中一行 + /// + /// + private void RowCheckBoxClick(DataGridViewCheckBoxCell RCheckBox) + { + int TotalCheckBoxes = itemDGV.Rows.Count; + if (RCheckBox != null) + { + //Modifiy Counter; + if ((bool)RCheckBox.Value && TotalCheckedCheckBoxes < TotalCheckBoxes) + TotalCheckedCheckBoxes++; + else if (TotalCheckedCheckBoxes > 0) + TotalCheckedCheckBoxes--; + + //Change state of the header CheckBox. + if (TotalCheckedCheckBoxes < TotalCheckBoxes) + HeaderCheckBox.Checked = false; + else if (TotalCheckedCheckBoxes == TotalCheckBoxes) + HeaderCheckBox.Checked = true; + } + } +#endregion + + #region 自定义itemDGV行选中的外观样式 + private void CustomRowSelectionStyle() + { + this.itemDGV.RowTemplate.DefaultCellStyle.SelectionBackColor = Color.Transparent; + // Attach handlers to DataGridView events. + this.itemDGV.ColumnWidthChanged += new + DataGridViewColumnEventHandler(itemDGV_ColumnWidthChanged); + this.itemDGV.RowPrePaint += new + DataGridViewRowPrePaintEventHandler(itemDGV_RowPrePaint); + this.itemDGV.RowPostPaint += new + DataGridViewRowPostPaintEventHandler(itemDGV_RowPostPaint); + this.itemDGV.CurrentCellChanged += new + EventHandler(itemDGV_CurrentCellChanged); + this.itemDGV.RowHeightChanged += new + DataGridViewRowEventHandler(itemDGV_RowHeightChanged); + } + // Forces the control to repaint itself when the user + // manually changes the width of a column. + void itemDGV_ColumnWidthChanged(object sender, + DataGridViewColumnEventArgs e) + { + this.itemDGV.Invalidate(); + } + + // Forces the row to repaint itself when the user changes the + // current cell. This is necessary to refresh the focus rectangle. + void itemDGV_CurrentCellChanged(object sender, EventArgs e) + { + if (oldRowSelectionIndex != -1) + { + this.itemDGV.InvalidateRow(oldRowSelectionIndex); + } + oldRowSelectionIndex = this.itemDGV.CurrentCellAddress.Y; + } + + // Paints the custom selection background for selected rows. + void itemDGV_RowPrePaint(object sender,DataGridViewRowPrePaintEventArgs e) + { + // Do not automatically paint the focus rectangle. + e.PaintParts &= ~DataGridViewPaintParts.Focus; + + // Determine whether the cell should be painted + // with the custom selection background. + if ((e.State & DataGridViewElementStates.Selected) == + DataGridViewElementStates.Selected) + { + // Calculate the bounds of the row. + Rectangle rowBounds = new Rectangle( + this.itemDGV.RowHeadersWidth, e.RowBounds.Top, + this.itemDGV.Columns.GetColumnsWidth( + DataGridViewElementStates.Visible) - + this.itemDGV.HorizontalScrollingOffset + 1, + e.RowBounds.Height); + + // Paint the custom selection background. + using (Brush backbrush = + new System.Drawing.Drawing2D.LinearGradientBrush(rowBounds, + this.itemDGV.DefaultCellStyle.SelectionBackColor, + Color.LightSkyBlue, + System.Drawing.Drawing2D.LinearGradientMode.Horizontal)) + { + e.Graphics.FillRectangle(backbrush, rowBounds); + } + } + } + + // Paints the content that spans multiple columns and the focus rectangle. + void itemDGV_RowPostPaint(object sender, + DataGridViewRowPostPaintEventArgs e) + { + // Calculate the bounds of the row. + Rectangle rowBounds = new Rectangle( + this.itemDGV.RowHeadersWidth, e.RowBounds.Top, + this.itemDGV.Columns.GetColumnsWidth( + DataGridViewElementStates.Visible) - + this.itemDGV.HorizontalScrollingOffset + 1, + e.RowBounds.Height); + + SolidBrush forebrush = null; + try + { + // Determine the foreground color. + if ((e.State & DataGridViewElementStates.Selected) == + DataGridViewElementStates.Selected) + { + forebrush = new SolidBrush(e.InheritedRowStyle.SelectionForeColor); + } + else + { + forebrush = new SolidBrush(e.InheritedRowStyle.ForeColor); + } + + DataGridViewRow dgvr = this.itemDGV.Rows.SharedRow(e.RowIndex); + if (dgvr != null && dgvr.Index > 0) + { + // Get the content that spans multiple columns. + object recipe = + this.itemDGV.Rows.SharedRow(e.RowIndex).Cells[2].Value; + + if (recipe != null) + { + String text = recipe.ToString(); + + // Calculate the bounds for the content that spans multiple + // columns, adjusting for the horizontal scrolling position + // and the current row height, and displaying only whole + // lines of text. + Rectangle textArea = rowBounds; + textArea.X -= this.itemDGV.HorizontalScrollingOffset; + textArea.Width += this.itemDGV.HorizontalScrollingOffset; + textArea.Y += rowBounds.Height - e.InheritedRowStyle.Padding.Bottom; + textArea.Height -= rowBounds.Height - + e.InheritedRowStyle.Padding.Bottom; + textArea.Height = (textArea.Height / e.InheritedRowStyle.Font.Height) * + e.InheritedRowStyle.Font.Height; + + // Calculate the portion of the text area that needs painting. + RectangleF clip = textArea; + clip.Width -= this.itemDGV.RowHeadersWidth + 1 - clip.X; + clip.X = this.itemDGV.RowHeadersWidth + 1; + RectangleF oldClip = e.Graphics.ClipBounds; + e.Graphics.SetClip(clip); + + // Draw the content that spans multiple columns. + e.Graphics.DrawString( + text, e.InheritedRowStyle.Font, forebrush, textArea); + + e.Graphics.SetClip(oldClip); + } + } + } + finally + { + forebrush.Dispose(); + } + + if (this.itemDGV.CurrentCellAddress.Y == e.RowIndex) + { + // Paint the focus rectangle. + e.DrawFocus(rowBounds, true); + } + } + + // Adjusts the padding when the user changes the row height so that + // the normal cell content is fully displayed and any extra + // height is used for the content that spans multiple columns. + void itemDGV_RowHeightChanged(object sender, + DataGridViewRowEventArgs e) + { + // Calculate the new height of the normal cell content. + Int32 preferredNormalContentHeight = + e.Row.GetPreferredHeight(e.Row.Index, + DataGridViewAutoSizeRowMode.AllCellsExceptHeader, true) - + e.Row.DefaultCellStyle.Padding.Bottom; + + // Specify a new padding. + Padding newPadding = e.Row.DefaultCellStyle.Padding; + newPadding.Bottom = e.Row.Height - preferredNormalContentHeight; + e.Row.DefaultCellStyle.Padding = newPadding; + } + #endregion + + + /// + /// 从剪贴板粘贴文本型数据记录到目标区域 + /// This will be moved to the util class so it can service any paste into a DGV + /// + internal void PasteClipboard() + { + try + { + string s = Clipboard.GetText(); + string[] lines = s.Split('\n'); + int iFail = 0, iRow = itemDGV.CurrentCell.RowIndex; + int iCol = itemDGV.CurrentCell.ColumnIndex; + DataGridViewCell oCell; + foreach (string line in lines) + { + if (iRow < itemDGV.RowCount && line.Length > 0) + { + string[] sCells = line.Split('\t'); + for (int i = 0; i < sCells.GetLength(0); ++i) + { + if (iCol + i < this.itemDGV.ColumnCount) + { + oCell = itemDGV[iCol + i, iRow]; + if (!oCell.ReadOnly) + { + if (oCell.Value == null || oCell.Value.ToString() != sCells[i]) + { + oCell.Value = Convert.ChangeType(sCells[i], oCell.ValueType); + oCell.Style.BackColor = Color.Tomato; + } + else + iFail++;//only traps a fail if the data has changed and you are pasting into a read only cell + } + } + else + { break; } + } + iRow++; + } + else + { break; } + if (iFail > 0) + MessageBox.Show(string.Format("{0} updates failed due to read only column setting", iFail)); + } + } + catch (FormatException) + { + MessageBox.Show("The data you pasted is in the wrong format for the cell"); + return; + } + } + + /// + /// 根据指定的索引位序更新显示附加的属性信息 + /// + /// + /// + public void selectViewRecord(DataGridViewRow dgvr) + { + int rIdx = dgvr.DataGridView.Columns[CTDRecordA.CTD_RID.ToString()].Index; + if (dgvr.Cells.Count > rIdx) + { + CUR_RID = Convert.ToInt64(dgvr.Cells[rIdx].FormattedValue.ToString()); + DataTable table = LocalRecordMHub.queryCTDRecord(DataSourceHolder.DataSource, CUR_RID.ToString()); + if (table.Rows.Count > 0) + { + DataRow dr = table.Rows[0]; + List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); + showReferences(viewAttrs, dr); + } + } + } + + /// + /// 根据指定的数据集合加载数据报表显示,指定的字段映射为空时则使用默认的字段映射显示规则。 + /// + /// + /// + /// + public void loadDataSetView() + { + List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource);//获取所有属性名称集合 + lock (LocalDataGridView_Lock) + { + if (itemDGV.ColumnCount > 0) + { + DGVAsyncUtil.syncRemoveAllRow(itemDGV); + resetReferences(viewAttrs); + } + else + { + //行列表头显示 + loadDGVColumns(viewAttrs); + loadReferences(viewAttrs); + } + } + } + /// + /// 标记目标数据报表关联文档目录键值 + /// + public void noteDataSetLib(TreeNode filterNode) + { + long lid = Convert.ToInt64(filterNode.Name); + + if (filterNode.Level > 0) + { + CUR_LID = lid; + CUR_PLID = Convert.ToInt64(filterNode.Parent.Name); + } + else + { + CUR_LID = lid; + CUR_PLID = lid; + } + } + /// + /// 删除数据归档目标的数据记录,置入未分类目录 + /// + /// + /// + public void trashDataSet(TreeNode filteNode, int newlid = CatalogNode.REC_TRASH) + { + List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); + long lid = Convert.ToInt64(filteNode.Name); + lock (LocalDataGridView_Lock) + { + if (filteNode.Level > 0) + { + CUR_LID = lid; + CUR_PLID = Convert.ToInt64(filteNode.Parent.Name); + } + else + { + CUR_LID = lid; + CUR_PLID = lid; + } + itemDGV.Rows.Clear(); + resetReferences(viewAttrs); + string filterLids = lid.ToString(); + if (lid > 0) + { + long[] lids = LocalRecordMHub.extractToLids(DataSourceHolder.DataSource,lid); + if (lids != null) + { + filterLids = ""; + foreach (long _lid in lids) + { + filterLids += "," + _lid; + } + filterLids = filterLids.Substring(1); + } + } + //数据归档更新 + LocalRecordMHub.updateCTCRecordLid(DataSourceHolder.DataSource, newlid, CatalogNode.REC_ALL, filterLids); + } + } + /// + /// 删除数据归档目标的数据记录,置入未分类目录 + /// + /// + public void dropDataSet(TreeNode filteNode) + { + List viewAttrs = LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource); + long lid = Convert.ToInt64(filteNode.Name); + lock (LocalDataGridView_Lock) + { + if (filteNode.Level > 0) + { + CUR_LID = lid; + CUR_PLID = Convert.ToInt64(filteNode.Parent.Name); + } + else + { + CUR_LID = lid; + CUR_PLID = lid; + } + itemDGV.Rows.Clear(); + resetReferences(viewAttrs); + string filterLids = lid.ToString(); + if (lid > 0) + { + long[] lids = LocalRecordMHub.extractToLids(DataSourceHolder.DataSource,lid); + if (lids != null) + { + filterLids = ""; + foreach (long _lid in lids) + { + filterLids += "," + _lid; + } + filterLids = filterLids.Substring(1); + } + } + //数据归档更新 + LocalRecordMHub.dropCTCRecordLid(DataSourceHolder.DataSource, filterLids); + } + } + + + /// + /// 加载数据表头展示 + /// + /// + /// + private void loadDGVColumns(List viewAttrs) + { + DGVAsyncUtil.syncClearAll(itemDGV); + //默认前置的选择列 + DataGridViewCheckBoxColumn chxCol = new DataGridViewCheckBoxColumn(); + chxCol.ReadOnly = true; + chxCol.Resizable = DataGridViewTriState.False; + chxCol.FlatStyle = FlatStyle.Popup; + chxCol.CellTemplate.Style.ForeColor = Color.LightGray; + DGVAsyncUtil.syncAddCol(itemDGV,chxCol); + //创建显性列属性 + foreach (string attr in viewAttrs) + { + int viewOrder = LocalRecordMHub.getViewOrder(DataSourceHolder.DataSource, attr);//返回属性显示位序 + log.Debug("##"+attr+"->"+viewOrder); + if (viewOrder < CustomTColMap.MaxMainViewCount) + { + CustomTColDef ctcd = LocalRecordMHub.getCustomTColDef(DataSourceHolder.DataSource,attr); + Type colType = RecordControlTypeConverter.getDGVColType(ctcd.AttrType); + DataGridViewColumn dgvCol = Activator.CreateInstance(colType) as DataGridViewColumn; + dgvCol.Name = ctcd.Attr; + dgvCol.HeaderText = CVNameConverter.toViewName(ctcd.Attr); + if(attr.Equals(CTDRecordA.CTD_RID)|| attr.Equals(CTDRecordA.CTD_PLID) || attr.Equals(CTDRecordA.CTD_LID)){ + dgvCol.Visible = false; + dgvCol.Width = 0; + } + DGVAsyncUtil.syncAddCol(itemDGV, dgvCol); + if (viewOrder != dgvCol.Index) + LocalRecordMHub.updateViewOrder(DataSourceHolder.DataSource,attr, dgvCol.Index); + } + } + } + /// + /// 加载附加注解字段名展示 + /// + /// + /// + private void loadReferences(List viewAttrs) + { + //清理tabControl控件 + foreach (TabPage tp in attachTC.TabPages) + { + foreach (Control ictl in tp.Controls) + { + ictl.Dispose(); + } + } + //重新build references Page + TabPage tabPage = attachTC.TabPages["references"]; + int idx = 0; + foreach (string attr in viewAttrs) + { + if (LocalRecordMHub.getViewOrder(DataSourceHolder.DataSource, attr) < CustomTColMap.MaxMainViewCount) + { + ++idx; + continue; + } + CustomTColDef ctcd = LocalRecordMHub.getCustomTColDef(DataSourceHolder.DataSource, attr); + Panel panel = new Panel(); + panel.Name = "referPanel_" + idx; + panel.Dock = DockStyle.Top; + panel.Margin = new Padding(0, 5, 0, 0); + panel.BorderStyle = System.Windows.Forms.BorderStyle.None; + panel.Height = 45; + //panel.BorderStyle = BorderStyle.FixedSingle; + TextBox label = new TextBox(); + label.ReadOnly = true; + label.BorderStyle = System.Windows.Forms.BorderStyle.None; + label.BackColor = Color.WhiteSmoke; + label.Name = "referLabel_" + ctcd.Attr; + string pattr =CVNameConverter.toViewName(ctcd.Attr); + label.Text = pattr; + label.Font = new Font(label.Font, label.Font.Style ^ FontStyle.Bold); + label.Height = 14; + label.Dock = DockStyle.Top; + panel.Controls.Add(label); + Type ctype = RecordControlTypeConverter.getControlType(ctcd.AttrType); + Control control = Activator.CreateInstance(ctype) as Control; + if (control is TextBox) + { + (control as TextBox).BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + } + control.Name = pattr; + control.Dock = DockStyle.Bottom; + control.Height = 20; + control.Margin = new Padding(0, 1, 0, 0); + control.TextChanged += Refers_record_TextChanged; + panel.Controls.Add(control); + tabPage.Controls.Add(panel); + ++idx; + } + Label ridLabel = new Label(); + ridLabel.Name = "ctd_rid_Label"; + ridLabel.Visible = false; + ridLabel.Height = 0; + ridLabel.Dock = DockStyle.Top; + ridLabel.Margin = new Padding(0, 0, 0, 0); + tabPage.Controls.Add(ridLabel); + } + /// + /// 根据指定的数据行置空所有附加的属性信息 + /// + /// + public void resetReferences(List viewAttrs) + { + showReferences(viewAttrs, null); + } + /// + /// 根据指定的数据行更新显示附加的属性信息 + /// + /// + /// + /// dr为null则等效于清空表单操作 + public void showReferences(List viewAttrs, DataRow dr = null)//参数是所有属性名称集合 + { + TabPage tabPage = attachTC.TabPages["references"]; + if (dr != null) + { + (tabPage.Controls["ctd_rid_Label"] as Label).Text = dr[CTDRecordA.CTD_RID].ToString(); + } + foreach (Control ctl in tabPage.Controls)//获取选项卡内所有集合 + { + if (ctl is Panel)//如果空间是面板 + { + //获取,选择项卡中的集合名称从referPanel_开始处的索引 + int idx = Convert.ToInt32(ctl.Name.Substring("referPanel_".Length)); + + //从viewAttrs[idx]第一位开始,viewAttrs[idx]-2个长度的字符串 + string attr =CVNameConverter.toViewName(viewAttrs[idx]);//注意: + Control ictl = ctl.Controls[attr]; + if (ictl != null) + { + if (ictl is TextBox) + { + (ictl as TextBox).Text = dr == null ? "" : dr[attr].ToString(); + } + else if (ictl is ComboBox) + { + (ictl as ComboBox).FormatString = dr == null ? "" : dr[attr].ToString(); + } + else if (ictl is DateTimePicker) + { + (ictl as DateTimePicker).CustomFormat = dr == null ? "" : dr[attr].ToString(); + } + } + } + } + } + public DataGridViewCell quickSearch(string findTerm) + { + if (findTerm.Length > 0) + { + DataGridViewCell ncell = null; + if (itemDGV.SelectedCells != null && itemDGV.SelectedCells.Count > 0) + { + if(itemDGV.SelectedCells[0].Displayed) + ncell = itemDGV.SelectedCells[0]; + } + while ((ncell = nextTextCell(ncell)) != null) + { + string cellval = DGVUtil.getCellValue(ncell,""); + if (cellval.ToLower().Contains(findTerm.ToLower())) + { + return ncell; + } + } + if (ncell == null) + { + MessageBox.Show("It's reached the end, and no subsequent matches."); + } + } + return null; + } + public void doDBDataSearch(string whereCmd) + { + //unimplemented + } + /// + /// 下一个单元格定位,如定位失败返回null + /// + /// + private DataGridViewCell nextTextCell(DataGridViewCell cell = null) + { + DataGridViewCell ncell = null; + int rowCount = DGVUtil.getRowCount(itemDGV); + int columnCount = DGVUtil.getTextColumnCount(itemDGV); + int rowIndex = cell == null ? 0 : cell.RowIndex; + int colIndex = cell == null ? 0 : cell.ColumnIndex + 1; + if (colIndex >= columnCount) + { + rowIndex = rowIndex + 1; + colIndex = 0; + } + if (colIndex < columnCount && rowIndex + /// 添加新纪录,自动生成默认的数据字段值 + /// + /// + public void addNewRecord() + { + long nuid = LocalRecordMHub.addNewRecord(DataSourceHolder.DataSource,CUR_LID, CURRENT_PLID); + if (nuid > 0) + { + int idx = itemDGV.Rows.Add(); + itemDGV.Rows[idx].Cells[CTDRecordA.CTD_RID].Value = nuid; + itemDGV.Rows[idx].Cells[CTDRecordA.CTD_LID].Value = CUR_LID; + itemDGV.Rows[idx].Cells[CTDRecordA.CTD_PLID].Value = CURRENT_PLID; + } + } + + /// + /// 伴随用户修改操作同步更新记录属性信息 + /// + /// + /// + public static void Refers_record_TextChanged(object sender, EventArgs e) + { + if ((sender as Control).Focused) + { + string rid = null; + string attrName = null; + string cellVal = null; + if (sender is TextBox) + { + TextBox tb = (sender as TextBox); + rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; + attrName = tb.Name; + cellVal = tb.Text.Trim(); + } + else if (sender is ComboBox) + { + ComboBox tb = (sender as ComboBox); + rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; + attrName = tb.Name; + cellVal = tb.FormatString.Trim(); + } + else if (sender is DateTimePicker) + { + DateTimePicker tb = (sender as DateTimePicker); + rid = (tb.Parent.Parent.Controls["ctd_rid_Label"] as Label).Text; + attrName = tb.Name; + cellVal = tb.Text.Trim(); + } + if (rid.Length > 0 && cellVal.Length > 0) + { + LocalRecordMHub.updateAttrVal(DataSourceHolder.DataSource,rid, cellVal, "[" + attrName + "]"); + } + } + } + /// + /// 解析指定的Excel文档,验证数据转换的属性映射条件. + /// + /// + /// + public bool checkForExcelImport(string fpath, ref Dictionary dataMapping, Form pForm) + { + if (fpath == null || fpath.Length < 1) + return false; + string fullPath = System.IO.Path.GetFullPath(fpath); + IWorkbook workbook = null; + try + { + using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) + { + workbook = WorkbookFactory.Create(fs); + ISheet dataSheet = workbook.GetSheet("Core Datasets"); + if (dataSheet == null) + dataSheet = workbook.GetSheetAt(0); + return fetchSheetMappingInfo(dataSheet, ref dataMapping, pForm) && dataMapping.Count > 0; + } + } + catch (Exception ex) + { + log.Info("ERROR: Excel文件导入失败! ", ex); + MessageBox.Show("ERROR: Excel文件导入失败! " + ex.Message + "\n" + ex.StackTrace); + } + return false; + } + /// + /// 通过NPOI读取Excel文档,转换可识别内容至本地数据库中 + /// + /// + /// + private bool fetchSheetMappingInfo(ISheet sheet, ref Dictionary dataMapping,Form pForm) + { + int skipIdx = 1; + if (sheet == null || sheet.LastRowNum < skipIdx) //no data + return false; + ///////////////////////////////////////////////////////// + IRow titleRow = sheet.GetRow(skipIdx - 1); + int columnSize = titleRow.LastCellNum; + int rowSize = sheet.LastRowNum; + List xlscols = new List(columnSize); + for (int i = titleRow.FirstCellNum; i < columnSize; i++) + { + ICell titleCell = titleRow.GetCell(i); + if (titleCell != null && titleCell.ToString().Length > 0) + { + string cellData = titleCell.ToString(); + xlscols.Add(CVNameConverter.toViewName(cellData.Trim().ToLower())); + } + else + { + xlscols.Add(null); + } + } + /////////////////////////////////////////////////////////////// + using (AttrMapOptionDlg amoDlg = new AttrMapOptionDlg()) + { + amoDlg.BringToFront(); + amoDlg.setInitCols(xlscols, LocalRecordMHub.getViewAttrs(DataSourceHolder.DataSource,false), ref dataMapping); + amoDlg.ShowDialog(); + /////////////////////////////////////////// + if (amoDlg.DialogResult == DialogResult.OK) + return true; + } + return false; + } + private DataGridView itemDGV; + + public DataGridView ItemDGV + { + get { return itemDGV; } + } + private TabControl attachTC; + + public TabControl AttachTC + { + get { return attachTC; } + } + private static NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); + /// + /// 本地表单数据视图控件的独占保持的共享锁对象 + /// + public static object LocalDataGridView_Lock = new object(); + } +} diff --git a/IDCM/IDCM/ViewManager/GCMViewManager.cs b/IDCM/IDCM/ViewManager/GCMViewManager.cs index 6b5bcce..55607c8 100644 --- a/IDCM/IDCM/ViewManager/GCMViewManager.cs +++ b/IDCM/IDCM/ViewManager/GCMViewManager.cs @@ -1,189 +1,189 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using IDCM.AppContext; -using IDCM.Forms; -using IDCM.Service.Utils; -using IDCM.Service; -using IDCM.Service.Common; -using IDCM.Service.BGHandler; -using IDCM.Core; -using IDCM.Modules; -using IDCM.Data.Base; -using IDCM.Service.UIM; - -namespace IDCM.ViewManager -{ - public class GCMViewManager : ManagerA - { - #region 构造&析构 - public GCMViewManager() - { - gcmView = new GCMView(); - gcmView.Shown += OnGcmView_Shown; - gcmView.getItemGridView().CellClick += OnGcmDataGridViewItems_CellClick; - gcmView.getRecordTree().NodeMouseClick += OnGcmTreeViewRecord_NodeMouseClick; - frontFindDlg = new GCMFrontFindDlg(gcmView.getItemGridView()); - frontFindDlg.setCellHit += new GCMFrontFindDlg.SetHit(DGVUtil.setDGVCellHit); - frontFindDlg.cancelCellHit += new GCMFrontFindDlg.CancelHit(DGVUtil.cancelDGVCellHit); - datasetBuilder = new GCMDataSetBuilder(gcmView.getItemGridView()); - searchBuilder = new GCMSearchBuilder(gcmView.getSearchPanel(), gcmView.getSearchSpliter()); - BackProgressIndicator.addIndicatorBar(gcmView.getProgressBar());//有待完善 - } - - ~GCMViewManager() - { - dispose(); - } - #endregion - #region 实例对象保持部分 - - - //页面窗口实例 - private volatile GCMView gcmView = null; - private volatile GCMDataSetBuilder datasetBuilder = null; - private volatile GCMSearchBuilder searchBuilder = null; - private GCMFrontFindDlg frontFindDlg = null; - - #endregion - #region 接口实例化部分 - public override void dispose() - { - _isDisposed = true; - if (datasetBuilder != null) - { - datasetBuilder.Dispose(); - datasetBuilder = null; - } - if (searchBuilder != null) - { - searchBuilder.Dispose(); - searchBuilder = null; - } - if (gcmView != null && !gcmView.IsDisposed) - { - BackProgressIndicator.removeIndicatorBar(gcmView.getProgressBar()); - gcmView.Close(); - gcmView.Dispose(); - gcmView = null; - } - if (frontFindDlg != null && !frontFindDlg.IsDisposed) - { - frontFindDlg.Close(); - frontFindDlg.Dispose(); - frontFindDlg = null; - } - } - /// - /// 对象实例化初始化方法 - /// - /// - public override bool initView(bool activeShow = true) - { - if (gcmView == null || gcmView.IsDisposed) - { - gcmView = new GCMView(); - gcmView.Shown += OnGcmView_Shown; - gcmView.getItemGridView().CellClick += OnGcmDataGridViewItems_CellClick; - gcmView.getRecordTree().NodeMouseClick += OnGcmTreeViewRecord_NodeMouseClick; - datasetBuilder = new GCMDataSetBuilder(gcmView.getItemGridView()); - BackProgressIndicator.addIndicatorBar(gcmView.getProgressBar()); - searchBuilder = new GCMSearchBuilder(gcmView.getSearchPanel(), gcmView.getSearchSpliter()); - } - if (activeShow) - { - gcmView.WindowState = FormWindowState.Maximized; - gcmView.Show(); - gcmView.Activate(); - } - else - { - gcmView.Hide(); - } - return true; - } - public override void setMaxToNormal() - { - if (gcmView.WindowState.Equals(FormWindowState.Maximized)) - gcmView.WindowState = FormWindowState.Normal; - } - public override void setToMaxmize(bool activeFront = false) - { - gcmView.WindowState = FormWindowState.Maximized; - if (activeFront) - { - gcmView.Show(); - gcmView.Activate(); - } - } - public override void setMdiParent(Form pForm) - { - gcmView.MdiParent = pForm; - } - public override bool isDisposed() - { - if (_isDisposed==false) - { - _isDisposed= (gcmView==null || gcmView.Disposing || gcmView.IsDisposed); - } - return _isDisposed; - } - public override bool isActive() - { - if (gcmView == null || gcmView.Disposing || gcmView.IsDisposed) - return false; - else - return gcmView.Visible; - } - #endregion - /// - /// 载入数据显示 - /// - public void loadDataSetView() - { - LoadGCMDataHandler lgdh = new LoadGCMDataHandler(DataSourceHolder.GCMHolder, gcmView.getItemGridView(), gcmView.getRecordTree(), gcmView.getRecordList(), datasetBuilder.getLoadedNoter()); - DWorkMHub.callAsyncHandle(lgdh); - } - /// - /// activeHomeView - /// - /// - public void OnGcmView_Shown(object sender, EventArgs e) - { - //加载默认的数据报表展示 - loadDataSetView(); - //resize for data view - gcmView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); - gcmView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.None); - gcmView.getItemGridView().AllowUserToResizeColumns = true; - } - - public void OnGcmDataGridViewItems_CellClick(object sender, DataGridViewCellEventArgs e) - { - DataGridViewRow dgvRow = gcmView.getItemGridView().CurrentRow; - String strainid = dgvRow.Cells["id"].FormattedValue.ToString(); - LoadGCMStrainViewHandler lsvh = new LoadGCMStrainViewHandler(DataSourceHolder.GCMHolder,strainid, gcmView.getRecordTree(), gcmView.getRecordList()); - DWorkMHub.callAsyncHandle(lsvh); - } - - public void OnGcmTreeViewRecord_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) - { - LoadGCMRecordNodeDetail.loadData(e.Node, gcmView.getRecordList()); - } - - internal void frontDataSearch() - { - if (frontFindDlg == null || frontFindDlg.IsDisposed) - { - frontFindDlg = new GCMFrontFindDlg(gcmView.getItemGridView()); - frontFindDlg.setCellHit += new GCMFrontFindDlg.SetHit(DGVUtil.setDGVCellHit); - frontFindDlg.cancelCellHit += new GCMFrontFindDlg.CancelHit(DGVUtil.cancelDGVCellHit); - } - frontFindDlg.Show(); - frontFindDlg.Visible = true; - frontFindDlg.Activate(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using IDCM.AppContext; +using IDCM.Forms; +using IDCM.Service.Utils; +using IDCM.Service; +using IDCM.Service.Common; +using IDCM.Service.BGHandler; +using IDCM.Core; +using IDCM.Modules; +using IDCM.Data.Base; +using IDCM.Service.UIM; + +namespace IDCM.ViewManager +{ + public class GCMViewManager : ManagerA + { + #region 构造&析构 + public GCMViewManager() + { + gcmView = new GCMView(); + gcmView.Shown += OnGcmView_Shown; + gcmView.getItemGridView().CellClick += OnGcmDataGridViewItems_CellClick; + gcmView.getRecordTree().NodeMouseClick += OnGcmTreeViewRecord_NodeMouseClick; + frontFindDlg = new GCMFrontFindDlg(gcmView.getItemGridView()); + frontFindDlg.setCellHit += new GCMFrontFindDlg.SetHit(DGVUtil.setDGVCellHit); + frontFindDlg.cancelCellHit += new GCMFrontFindDlg.CancelHit(DGVUtil.cancelDGVCellHit); + datasetBuilder = new GCMDataSetBuilder(gcmView.getItemGridView()); + searchBuilder = new GCMSearchBuilder(gcmView.getSearchPanel(), gcmView.getSearchSpliter()); + BackProgressIndicator.addIndicatorBar(gcmView.getProgressBar());//有待完善 + } + + ~GCMViewManager() + { + dispose(); + } + #endregion + #region 实例对象保持部分 + + + //页面窗口实例 + private volatile GCMView gcmView = null; + private volatile GCMDataSetBuilder datasetBuilder = null; + private volatile GCMSearchBuilder searchBuilder = null; + private GCMFrontFindDlg frontFindDlg = null; + + #endregion + #region 接口实例化部分 + public override void dispose() + { + _isDisposed = true; + if (datasetBuilder != null) + { + datasetBuilder.Dispose(); + datasetBuilder = null; + } + if (searchBuilder != null) + { + searchBuilder.Dispose(); + searchBuilder = null; + } + if (gcmView != null && !gcmView.IsDisposed) + { + BackProgressIndicator.removeIndicatorBar(gcmView.getProgressBar()); + gcmView.Close(); + gcmView.Dispose(); + gcmView = null; + } + if (frontFindDlg != null && !frontFindDlg.IsDisposed) + { + frontFindDlg.Close(); + frontFindDlg.Dispose(); + frontFindDlg = null; + } + } + /// + /// 对象实例化初始化方法 + /// + /// + public override bool initView(bool activeShow = true) + { + if (gcmView == null || gcmView.IsDisposed) + { + gcmView = new GCMView(); + gcmView.Shown += OnGcmView_Shown; + gcmView.getItemGridView().CellClick += OnGcmDataGridViewItems_CellClick; + gcmView.getRecordTree().NodeMouseClick += OnGcmTreeViewRecord_NodeMouseClick; + datasetBuilder = new GCMDataSetBuilder(gcmView.getItemGridView()); + BackProgressIndicator.addIndicatorBar(gcmView.getProgressBar()); + searchBuilder = new GCMSearchBuilder(gcmView.getSearchPanel(), gcmView.getSearchSpliter()); + } + if (activeShow) + { + gcmView.WindowState = FormWindowState.Maximized; + gcmView.Show(); + gcmView.Activate(); + } + else + { + gcmView.Hide(); + } + return true; + } + public override void setMaxToNormal() + { + if (gcmView.WindowState.Equals(FormWindowState.Maximized)) + gcmView.WindowState = FormWindowState.Normal; + } + public override void setToMaxmize(bool activeFront = false) + { + gcmView.WindowState = FormWindowState.Maximized; + if (activeFront) + { + gcmView.Show(); + gcmView.Activate(); + } + } + public override void setMdiParent(Form pForm) + { + gcmView.MdiParent = pForm; + } + public override bool isDisposed() + { + if (_isDisposed==false) + { + _isDisposed= (gcmView==null || gcmView.Disposing || gcmView.IsDisposed); + } + return _isDisposed; + } + public override bool isActive() + { + if (gcmView == null || gcmView.Disposing || gcmView.IsDisposed) + return false; + else + return gcmView.Visible; + } + #endregion + /// + /// 载入数据显示 + /// + public void loadDataSetView() + { + LoadGCMDataHandler lgdh = new LoadGCMDataHandler(DataSourceHolder.GCMHolder, gcmView.getItemGridView(), gcmView.getRecordTree(), gcmView.getRecordList(), datasetBuilder.getLoadedNoter()); + DWorkMHub.callAsyncHandle(lgdh); + } + /// + /// activeHomeView + /// + /// + public void OnGcmView_Shown(object sender, EventArgs e) + { + //加载默认的数据报表展示 + loadDataSetView(); + //resize for data view + gcmView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); + gcmView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.None); + gcmView.getItemGridView().AllowUserToResizeColumns = true; + } + + public void OnGcmDataGridViewItems_CellClick(object sender, DataGridViewCellEventArgs e) + { + DataGridViewRow dgvRow = gcmView.getItemGridView().CurrentRow; + String strainid = dgvRow.Cells["id"].FormattedValue.ToString(); + LoadGCMStrainViewHandler lsvh = new LoadGCMStrainViewHandler(DataSourceHolder.GCMHolder,strainid, gcmView.getRecordTree(), gcmView.getRecordList()); + DWorkMHub.callAsyncHandle(lsvh); + } + + public void OnGcmTreeViewRecord_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + LoadGCMRecordNodeDetail.loadData(e.Node, gcmView.getRecordList()); + } + + internal void frontDataSearch() + { + if (frontFindDlg == null || frontFindDlg.IsDisposed) + { + frontFindDlg = new GCMFrontFindDlg(gcmView.getItemGridView()); + frontFindDlg.setCellHit += new GCMFrontFindDlg.SetHit(DGVUtil.setDGVCellHit); + frontFindDlg.cancelCellHit += new GCMFrontFindDlg.CancelHit(DGVUtil.cancelDGVCellHit); + } + frontFindDlg.Show(); + frontFindDlg.Visible = true; + frontFindDlg.Activate(); + } + } +} diff --git a/IDCM/IDCM/ViewManager/HomeViewManager.cs b/IDCM/IDCM/ViewManager/HomeViewManager.cs index 0b42f72..348632e 100644 --- a/IDCM/IDCM/ViewManager/HomeViewManager.cs +++ b/IDCM/IDCM/ViewManager/HomeViewManager.cs @@ -1,448 +1,448 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using IDCM.AppContext; -using IDCM.Forms; -using IDCM.Service.Common; -using IDCM.Data.Base; -using IDCM.Service; -using IDCM.Modules; -using IDCM.Service.BGHandler; -using IDCM.Service.Utils; -using IDCM.Core; -using IDCM.Service.UIM; - -namespace IDCM.ViewManager -{ - /// - /// HomeView布局管理器及动态表现事务调度中心 - /// @author JiahaiWu 2014-10-15 - /// - public class HomeViewManager : ManagerA - { - #region 构造&析构 - public HomeViewManager() - { - homeView = new HomeView(); - homeView.setManager(this); - - homeView.Load += OnHomeView_Load; - homeView.Shown += OnHomeView_Shown; - - frontFindDlg = new LocalFrontFindDlg(homeView.getItemGridView()); - frontFindDlg.setCellHit += new LocalFrontFindDlg.SetHit(setDGVCellHit); - frontFindDlg.cancelCellHit += new LocalFrontFindDlg.CancelHit(cancelDGVCellHit); - - catBuilder = new LocalCatBuilder(homeView.getBaseTree(), homeView.getLibTree()); - datasetBuilder = new LocalDataSetBuilder(homeView.getItemGridView(), homeView.getAttachTabControl()); - searchBuilder = new LocalDBSearchBuilder(homeView.getDBSearchPanel(), homeView.getSearchSpliter()); - BackProgressIndicator.addIndicatorBar(homeView.getProgressBar()); - } - - ~HomeViewManager() - { - dispose(); - } - #endregion - #region 实例对象保持部分 - - - //页面窗口实例 - private volatile HomeView homeView = null; - private volatile LocalCatBuilder catBuilder = null; - private volatile LocalDataSetBuilder datasetBuilder = null; - private volatile LocalDBSearchBuilder searchBuilder = null; - private LocalFrontFindDlg frontFindDlg = null; - - #endregion - #region 接口实例化部分 - public override void dispose() - { - _isDisposed = true; - if (catBuilder != null) - { - catBuilder.Dispose(); - catBuilder = null; - } - if (datasetBuilder != null) - { - datasetBuilder.Dispose(); - datasetBuilder = null; - } - if (searchBuilder != null) - { - searchBuilder.Dispose(); - searchBuilder = null; - } - if (homeView != null && !homeView.IsDisposed) - { - BackProgressIndicator.removeIndicatorBar(homeView.getProgressBar()); - homeView.Close(); - homeView.Dispose(); - homeView = null; - } - if (frontFindDlg != null && !frontFindDlg.IsDisposed) - { - frontFindDlg.Close(); - frontFindDlg.Dispose(); - frontFindDlg = null; - } - } - /// - /// 对象实例化初始化方法 - /// - /// - public override bool initView(bool activeShow = true) - { - if (homeView == null || homeView.IsDisposed) - { - homeView = new HomeView(); - homeView.setManager(this); - catBuilder = new LocalCatBuilder(homeView.getBaseTree(), homeView.getLibTree()); - datasetBuilder = new LocalDataSetBuilder(homeView.getItemGridView(), homeView.getAttachTabControl()); - searchBuilder = new LocalDBSearchBuilder(homeView.getDBSearchPanel(), homeView.getSearchSpliter()); - } - if (DataSourceHolder.InWorking) - { - if (activeShow) - { - homeView.WindowState = FormWindowState.Maximized; - homeView.Show(); - homeView.Activate(); - } - else - { - homeView.Hide(); - } - return true; - } - dispose(); - return false; - } - public override void setMaxToNormal() - { - if (homeView.WindowState.Equals(FormWindowState.Maximized)) - homeView.WindowState = FormWindowState.Normal; - } - public override void setToMaxmize(bool activeFront = false) - { - homeView.WindowState = FormWindowState.Maximized; - if (activeFront) - { - homeView.Show(); - homeView.Activate(); - } - } - public override void setMdiParent(Form pForm) - { - homeView.MdiParent = pForm; - } - public override bool isDisposed() - { - if (_isDisposed == false) - { - _isDisposed = (homeView == null || homeView.Disposing || homeView.IsDisposed); - } - return _isDisposed; - } - public override bool isActive() - { - if (homeView == null || homeView.Disposing || homeView.IsDisposed) - return false; - else - return homeView.Visible; - } - #endregion - #region 接管视图组件的关键的事件处理区 - public void OnHomeView_Load(object sender, EventArgs e) - { - //加载默认的分类目录树展示 - catBuilder.loadTreeSet(); - updateCatRecCount(); - } - public void OnHomeView_Shown(object sender, EventArgs e) - { - //加载用数据记录 - loadDataSetView(homeView.getBaseTree().Nodes[0]); - //resize for data view - homeView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); - //dataGridView_items.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.None); - homeView.getItemGridView().AllowUserToResizeColumns = true; - } - - #endregion - public void loadDataSetView(TreeNode tnode) - { - datasetBuilder.loadDataSetView(); - noteCurSelectedNode(tnode); - } - /// - /// 导入数据文档 - /// - /// - public void importData(string fpath) - { - if (fpath.ToLower().EndsWith("xls") || fpath.ToLower().EndsWith(".xlsx")) - { - Dictionary dataMapping = new Dictionary(); - if (datasetBuilder.checkForExcelImport(fpath, ref dataMapping,homeView)) - { - ExcelImportHandler eih = new ExcelImportHandler(DataSourceHolder.DataSource,fpath,ref dataMapping, CatalogNode.REC_UNFILED, CatalogNode.REC_ALL); - eih.addHandler(new UpdateHomeDataViewHandler(DataSourceHolder.DataSource, catBuilder.RootNode_unfiled, homeView.getItemGridView())); - UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); - eih.addHandler(uhlch); - uhlch.addHandler(new SelectDataRowHandler(DataSourceHolder.DataSource, homeView.getItemGridView(), homeView.getAttachTabControl())); - DWorkMHub.callAsyncHandle(eih); - } - } - } - /// - /// 导出数据文档 - /// - /// - public void exportData(ExportType etype, string fpath) - { - KeyValuePair lastQuery = LocalRecordMHub.getLastDGVRQuery(); - AbsHandler handler = null; - switch (etype) - { - case ExportType.Excel: - handler = new ExcelExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value); - DWorkMHub.callAsyncHandle(handler); - break; - case ExportType.JSONList: - handler = new JSONListExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value); - DWorkMHub.callAsyncHandle(handler); - break; - case ExportType.TSV: - handler = new TextExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, "\t"); - DWorkMHub.callAsyncHandle(handler); - break; - case ExportType.CSV: - handler = new TextExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, ","); - DWorkMHub.callAsyncHandle(handler); - break; - case ExportType.XML: - handler = new XMLExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, ","); - DWorkMHub.callAsyncHandle(handler); - break; - default: - MessageBox.Show("Unsupport export type!"); - break; - } - } - /// - /// 更新分类目录关联文档数显示 - /// - /// - public void updateCatRecCount(TreeNode focusNode = null) - { - UpdateHomeLibCountHandler ulch = null; - if (focusNode == null) - ulch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); - else - ulch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, focusNode); - DWorkMHub.callAsyncHandle(ulch); - } - public void selectViewRecord(DataGridViewRow dgvr) - { - datasetBuilder.selectViewRecord(dgvr); - } - public void trashDataSet(TreeNode filteNode, int newlid = CatalogNode.REC_TRASH) - { - if (filteNode.Equals(catBuilder.RootNode_trash)) - { - datasetBuilder.dropDataSet(filteNode); - } - else - { - datasetBuilder.trashDataSet(filteNode, newlid); - } - UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource, filteNode, homeView.getItemGridView()); - UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); - uhdvh.addHandler(uhlch); - DWorkMHub.callAsyncHandle(uhdvh); - } - public void deleteNode(TreeNode treeNode) - { - datasetBuilder.trashDataSet(treeNode, CatalogNode.REC_TRASH); - catBuilder.deleteNode(treeNode); - UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource,catBuilder.RootNode_all, homeView.getItemGridView()); - UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); - uhdvh.addHandler(uhlch); - DWorkMHub.callAsyncHandle(uhdvh); - } - public void addGroup(TreeNode treeNode) - { - catBuilder.addGroup(treeNode); - } - public void addGroupSet(TreeNode treeNode) - { - catBuilder.addGroupSet(treeNode); - } - public void renameNode(TreeNode treeNode, string label) - { - catBuilder.renameNode(treeNode, label); - } - - public void noteCurSelectedNode(TreeNode node) - { - bool needUpdateData = catBuilder.noteCurSelectedNode(node); - if (needUpdateData) - { - updateDataSet(node); - } - } - public void CopyClipboard() - { - DataObject d = homeView.getItemGridView().GetClipboardContent(); - Clipboard.SetDataObject(d); - } - /// - /// This will be moved to the util class so it can service any paste into a DGV - /// - public void PasteClipboard() - { - datasetBuilder.PasteClipboard(); - } - /// - /// 根据指定的数据集合加载数据报表显示 - /// - public void updateDataSet(TreeNode filterNode) - { - datasetBuilder.noteDataSetLib(filterNode); //待考虑顺序问题/////////// - UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource,filterNode, homeView.getItemGridView()); - uhdvh.addHandler(new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, filterNode)); - uhdvh.addHandler(new SelectDataRowHandler(DataSourceHolder.DataSource, homeView.getItemGridView(), homeView.getAttachTabControl())); - DWorkMHub.callAsyncHandle(uhdvh); - } - public void showDBDataSearch() - { - searchBuilder.showDBDataSearch(); - } - public void doDBDataSearch() - { - string whereCmd = searchBuilder.buildWhereCmd(); - datasetBuilder.doDBDataSearch(whereCmd); - } - private void setDGVCellHit(DataGridViewCell cell) - { - if (cell.Visible == false) - return; - cell.DataGridView.EndEdit(); - int colCount = DGVUtil.getTextColumnCount(cell.DataGridView); - DataGridViewCell rightCell = cell.DataGridView.Rows[cell.RowIndex].Cells[colCount - 1]; - while (rightCell.Visible == false && rightCell.ColumnIndex > -1) - { - rightCell = rightCell.OwningRow.Cells[rightCell.ColumnIndex - 1]; - } - cell.DataGridView.CurrentCell = rightCell; - cell.DataGridView.CurrentCell = cell; - cell.Selected = true; - cell.DataGridView.BeginEdit(true); - } - private void cancelDGVCellHit(DataGridViewCell cell) - { - if (cell.Visible == false) - return; - cell.DataGridView.EndEdit(); - cell.Selected = false; - } - public void frontDataSearch() - { - if (frontFindDlg == null || frontFindDlg.IsDisposed) - { - frontFindDlg = new LocalFrontFindDlg(homeView.getItemGridView()); - frontFindDlg.setCellHit += new LocalFrontFindDlg.SetHit(setDGVCellHit); - frontFindDlg.cancelCellHit += new LocalFrontFindDlg.CancelHit(cancelDGVCellHit); - } - frontFindDlg.Show(); - frontFindDlg.Visible = true; - frontFindDlg.Activate(); - } - /// - /// 更新目标记录的归档目录属性信息 - /// - /// - /// - /// - /// - public int updateCTCRecordLid(int newlid, int newplid = CatalogNode.REC_UNFILED, long rid = -1) - { - return LocalRecordMHub.updateCTCRecordLid(DataSourceHolder.DataSource, newlid, newplid, rid); - } - /// - /// 删除记录 - /// - /// - public int deleteRec(long rid) - { - return LocalRecordMHub.deleteRec(DataSourceHolder.DataSource, rid); - } - /// - /// 根据当前焦点的TreeNode筛选可用的右键菜单显示列表项 - /// - /// - /// - public void filterContextMenuItems(ContextMenuStrip cms, TreeNode snode) - { - LocalCatBuilder.filterContextMenuItems(cms, snode); - } - /// - /// 更新数据记录 - /// - /// - /// - /// - /// - public int updateAttrVal(string rid, string cellVal, string attrName) - { - return LocalRecordMHub.updateAttrVal(DataSourceHolder.DataSource, rid, cellVal, attrName); - } - public void activeGCMView() - { - DWorkMHub.note(AsyncMessage.RequestGCMView); - } - public void quickSearch(string findTerm) - { - DataGridViewCell ncell = datasetBuilder.quickSearch(findTerm); - if (ncell != null) - setDGVCellHit(ncell); - } - public void frontSearchNext() - { - frontFindDlg.findDown(); - } - public void frontSearchPrev() - { - frontFindDlg.findRev(); - } - - public void addNewRecord() - { - datasetBuilder.addNewRecord(); - } - public TreeNode SelectedNode_Current - { - get { return catBuilder != null ? catBuilder.SelectedNode_Current : null; } - } - public long CURRENT_RID - { - get { return datasetBuilder.CURRENT_RID; } - set { datasetBuilder.CURRENT_RID=value; } - } - public long CURRENT_LID - { - get { return datasetBuilder.CURRENT_LID; } - } - public TreeNode RootNode_unfiled - { - get - { - return catBuilder.RootNode_unfiled; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using IDCM.AppContext; +using IDCM.Forms; +using IDCM.Service.Common; +using IDCM.Data.Base; +using IDCM.Service; +using IDCM.Modules; +using IDCM.Service.BGHandler; +using IDCM.Service.Utils; +using IDCM.Core; +using IDCM.Service.UIM; + +namespace IDCM.ViewManager +{ + /// + /// HomeView布局管理器及动态表现事务调度中心 + /// @author JiahaiWu 2014-10-15 + /// + public class HomeViewManager : ManagerA + { + #region 构造&析构 + public HomeViewManager() + { + homeView = new HomeView(); + homeView.setManager(this); + + homeView.Load += OnHomeView_Load; + homeView.Shown += OnHomeView_Shown; + + frontFindDlg = new LocalFrontFindDlg(homeView.getItemGridView()); + frontFindDlg.setCellHit += new LocalFrontFindDlg.SetHit(setDGVCellHit); + frontFindDlg.cancelCellHit += new LocalFrontFindDlg.CancelHit(cancelDGVCellHit); + + catBuilder = new LocalCatBuilder(homeView.getBaseTree(), homeView.getLibTree()); + datasetBuilder = new LocalDataSetBuilder(homeView.getItemGridView(), homeView.getAttachTabControl()); + searchBuilder = new LocalDBSearchBuilder(homeView.getDBSearchPanel(), homeView.getSearchSpliter()); + BackProgressIndicator.addIndicatorBar(homeView.getProgressBar()); + } + + ~HomeViewManager() + { + dispose(); + } + #endregion + #region 实例对象保持部分 + + + //页面窗口实例 + private volatile HomeView homeView = null; + private volatile LocalCatBuilder catBuilder = null; + private volatile LocalDataSetBuilder datasetBuilder = null; + private volatile LocalDBSearchBuilder searchBuilder = null; + private LocalFrontFindDlg frontFindDlg = null; + + #endregion + #region 接口实例化部分 + public override void dispose() + { + _isDisposed = true; + if (catBuilder != null) + { + catBuilder.Dispose(); + catBuilder = null; + } + if (datasetBuilder != null) + { + datasetBuilder.Dispose(); + datasetBuilder = null; + } + if (searchBuilder != null) + { + searchBuilder.Dispose(); + searchBuilder = null; + } + if (homeView != null && !homeView.IsDisposed) + { + BackProgressIndicator.removeIndicatorBar(homeView.getProgressBar()); + homeView.Close(); + homeView.Dispose(); + homeView = null; + } + if (frontFindDlg != null && !frontFindDlg.IsDisposed) + { + frontFindDlg.Close(); + frontFindDlg.Dispose(); + frontFindDlg = null; + } + } + /// + /// 对象实例化初始化方法 + /// + /// + public override bool initView(bool activeShow = true) + { + if (homeView == null || homeView.IsDisposed) + { + homeView = new HomeView(); + homeView.setManager(this); + catBuilder = new LocalCatBuilder(homeView.getBaseTree(), homeView.getLibTree()); + datasetBuilder = new LocalDataSetBuilder(homeView.getItemGridView(), homeView.getAttachTabControl()); + searchBuilder = new LocalDBSearchBuilder(homeView.getDBSearchPanel(), homeView.getSearchSpliter()); + } + if (DataSourceHolder.InWorking) + { + if (activeShow) + { + homeView.WindowState = FormWindowState.Maximized; + homeView.Show(); + homeView.Activate(); + } + else + { + homeView.Hide(); + } + return true; + } + dispose(); + return false; + } + public override void setMaxToNormal() + { + if (homeView.WindowState.Equals(FormWindowState.Maximized)) + homeView.WindowState = FormWindowState.Normal; + } + public override void setToMaxmize(bool activeFront = false) + { + homeView.WindowState = FormWindowState.Maximized; + if (activeFront) + { + homeView.Show(); + homeView.Activate(); + } + } + public override void setMdiParent(Form pForm) + { + homeView.MdiParent = pForm; + } + public override bool isDisposed() + { + if (_isDisposed == false) + { + _isDisposed = (homeView == null || homeView.Disposing || homeView.IsDisposed); + } + return _isDisposed; + } + public override bool isActive() + { + if (homeView == null || homeView.Disposing || homeView.IsDisposed) + return false; + else + return homeView.Visible; + } + #endregion + #region 接管视图组件的关键的事件处理区 + public void OnHomeView_Load(object sender, EventArgs e) + { + //加载默认的分类目录树展示 + catBuilder.loadTreeSet(); + updateCatRecCount(); + } + public void OnHomeView_Shown(object sender, EventArgs e) + { + //加载用数据记录 + loadDataSetView(homeView.getBaseTree().Nodes[0]); + //resize for data view + homeView.getItemGridView().AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); + //dataGridView_items.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.None); + homeView.getItemGridView().AllowUserToResizeColumns = true; + } + + #endregion + public void loadDataSetView(TreeNode tnode) + { + datasetBuilder.loadDataSetView(); + noteCurSelectedNode(tnode); + } + /// + /// 导入数据文档 + /// + /// + public void importData(string fpath) + { + if (fpath.ToLower().EndsWith("xls") || fpath.ToLower().EndsWith(".xlsx")) + { + Dictionary dataMapping = new Dictionary(); + if (datasetBuilder.checkForExcelImport(fpath, ref dataMapping,homeView)) + { + ExcelImportHandler eih = new ExcelImportHandler(DataSourceHolder.DataSource,fpath,ref dataMapping, CatalogNode.REC_UNFILED, CatalogNode.REC_ALL); + eih.addHandler(new UpdateHomeDataViewHandler(DataSourceHolder.DataSource, catBuilder.RootNode_unfiled, homeView.getItemGridView())); + UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); + eih.addHandler(uhlch); + uhlch.addHandler(new SelectDataRowHandler(DataSourceHolder.DataSource, homeView.getItemGridView(), homeView.getAttachTabControl())); + DWorkMHub.callAsyncHandle(eih); + } + } + } + /// + /// 导出数据文档 + /// + /// + public void exportData(ExportType etype, string fpath) + { + KeyValuePair lastQuery = LocalRecordMHub.getLastDGVRQuery(); + AbsHandler handler = null; + switch (etype) + { + case ExportType.Excel: + handler = new ExcelExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value); + DWorkMHub.callAsyncHandle(handler); + break; + case ExportType.JSONList: + handler = new JSONListExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value); + DWorkMHub.callAsyncHandle(handler); + break; + case ExportType.TSV: + handler = new TextExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, "\t"); + DWorkMHub.callAsyncHandle(handler); + break; + case ExportType.CSV: + handler = new TextExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, ","); + DWorkMHub.callAsyncHandle(handler); + break; + case ExportType.XML: + handler = new XMLExportHandler(DataSourceHolder.DataSource, fpath, lastQuery.Key, lastQuery.Value, ","); + DWorkMHub.callAsyncHandle(handler); + break; + default: + MessageBox.Show("Unsupport export type!"); + break; + } + } + /// + /// 更新分类目录关联文档数显示 + /// + /// + public void updateCatRecCount(TreeNode focusNode = null) + { + UpdateHomeLibCountHandler ulch = null; + if (focusNode == null) + ulch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); + else + ulch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, focusNode); + DWorkMHub.callAsyncHandle(ulch); + } + public void selectViewRecord(DataGridViewRow dgvr) + { + datasetBuilder.selectViewRecord(dgvr); + } + public void trashDataSet(TreeNode filteNode, int newlid = CatalogNode.REC_TRASH) + { + if (filteNode.Equals(catBuilder.RootNode_trash)) + { + datasetBuilder.dropDataSet(filteNode); + } + else + { + datasetBuilder.trashDataSet(filteNode, newlid); + } + UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource, filteNode, homeView.getItemGridView()); + UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); + uhdvh.addHandler(uhlch); + DWorkMHub.callAsyncHandle(uhdvh); + } + public void deleteNode(TreeNode treeNode) + { + datasetBuilder.trashDataSet(treeNode, CatalogNode.REC_TRASH); + catBuilder.deleteNode(treeNode); + UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource,catBuilder.RootNode_all, homeView.getItemGridView()); + UpdateHomeLibCountHandler uhlch = new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, homeView.getLibTree(), homeView.getBaseTree()); + uhdvh.addHandler(uhlch); + DWorkMHub.callAsyncHandle(uhdvh); + } + public void addGroup(TreeNode treeNode) + { + catBuilder.addGroup(treeNode); + } + public void addGroupSet(TreeNode treeNode) + { + catBuilder.addGroupSet(treeNode); + } + public void renameNode(TreeNode treeNode, string label) + { + catBuilder.renameNode(treeNode, label); + } + + public void noteCurSelectedNode(TreeNode node) + { + bool needUpdateData = catBuilder.noteCurSelectedNode(node); + if (needUpdateData) + { + updateDataSet(node); + } + } + public void CopyClipboard() + { + DataObject d = homeView.getItemGridView().GetClipboardContent(); + Clipboard.SetDataObject(d); + } + /// + /// This will be moved to the util class so it can service any paste into a DGV + /// + public void PasteClipboard() + { + datasetBuilder.PasteClipboard(); + } + /// + /// 根据指定的数据集合加载数据报表显示 + /// + public void updateDataSet(TreeNode filterNode) + { + datasetBuilder.noteDataSetLib(filterNode); //待考虑顺序问题/////////// + UpdateHomeDataViewHandler uhdvh = new UpdateHomeDataViewHandler(DataSourceHolder.DataSource,filterNode, homeView.getItemGridView()); + uhdvh.addHandler(new UpdateHomeLibCountHandler(DataSourceHolder.DataSource, filterNode)); + uhdvh.addHandler(new SelectDataRowHandler(DataSourceHolder.DataSource, homeView.getItemGridView(), homeView.getAttachTabControl())); + DWorkMHub.callAsyncHandle(uhdvh); + } + public void showDBDataSearch() + { + searchBuilder.showDBDataSearch(); + } + public void doDBDataSearch() + { + string whereCmd = searchBuilder.buildWhereCmd(); + datasetBuilder.doDBDataSearch(whereCmd); + } + private void setDGVCellHit(DataGridViewCell cell) + { + if (cell.Visible == false) + return; + cell.DataGridView.EndEdit(); + int colCount = DGVUtil.getTextColumnCount(cell.DataGridView); + DataGridViewCell rightCell = cell.DataGridView.Rows[cell.RowIndex].Cells[colCount - 1]; + while (rightCell.Visible == false && rightCell.ColumnIndex > -1) + { + rightCell = rightCell.OwningRow.Cells[rightCell.ColumnIndex - 1]; + } + cell.DataGridView.CurrentCell = rightCell; + cell.DataGridView.CurrentCell = cell; + cell.Selected = true; + cell.DataGridView.BeginEdit(true); + } + private void cancelDGVCellHit(DataGridViewCell cell) + { + if (cell.Visible == false) + return; + cell.DataGridView.EndEdit(); + cell.Selected = false; + } + public void frontDataSearch() + { + if (frontFindDlg == null || frontFindDlg.IsDisposed) + { + frontFindDlg = new LocalFrontFindDlg(homeView.getItemGridView()); + frontFindDlg.setCellHit += new LocalFrontFindDlg.SetHit(setDGVCellHit); + frontFindDlg.cancelCellHit += new LocalFrontFindDlg.CancelHit(cancelDGVCellHit); + } + frontFindDlg.Show(); + frontFindDlg.Visible = true; + frontFindDlg.Activate(); + } + /// + /// 更新目标记录的归档目录属性信息 + /// + /// + /// + /// + /// + public int updateCTCRecordLid(int newlid, int newplid = CatalogNode.REC_UNFILED, long rid = -1) + { + return LocalRecordMHub.updateCTCRecordLid(DataSourceHolder.DataSource, newlid, newplid, rid); + } + /// + /// 删除记录 + /// + /// + public int deleteRec(long rid) + { + return LocalRecordMHub.deleteRec(DataSourceHolder.DataSource, rid); + } + /// + /// 根据当前焦点的TreeNode筛选可用的右键菜单显示列表项 + /// + /// + /// + public void filterContextMenuItems(ContextMenuStrip cms, TreeNode snode) + { + LocalCatBuilder.filterContextMenuItems(cms, snode); + } + /// + /// 更新数据记录 + /// + /// + /// + /// + /// + public int updateAttrVal(string rid, string cellVal, string attrName) + { + return LocalRecordMHub.updateAttrVal(DataSourceHolder.DataSource, rid, cellVal, attrName); + } + public void activeGCMView() + { + DWorkMHub.note(AsyncMessage.RequestGCMView); + } + public void quickSearch(string findTerm) + { + DataGridViewCell ncell = datasetBuilder.quickSearch(findTerm); + if (ncell != null) + setDGVCellHit(ncell); + } + public void frontSearchNext() + { + frontFindDlg.findDown(); + } + public void frontSearchPrev() + { + frontFindDlg.findRev(); + } + + public void addNewRecord() + { + datasetBuilder.addNewRecord(); + } + public TreeNode SelectedNode_Current + { + get { return catBuilder != null ? catBuilder.SelectedNode_Current : null; } + } + public long CURRENT_RID + { + get { return datasetBuilder.CURRENT_RID; } + set { datasetBuilder.CURRENT_RID=value; } + } + public long CURRENT_LID + { + get { return datasetBuilder.CURRENT_LID; } + } + public TreeNode RootNode_unfiled + { + get + { + return catBuilder.RootNode_unfiled; + } + } + } +} diff --git a/IDCM/IDCM/ViewManager/IDCMFormManger.cs b/IDCM/IDCM/ViewManager/IDCMFormManger.cs index 6490f3b..a69e8ac 100644 --- a/IDCM/IDCM/ViewManager/IDCMFormManger.cs +++ b/IDCM/IDCM/ViewManager/IDCMFormManger.cs @@ -1,408 +1,408 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using IDCM.AppContext; -using IDCM.Forms; -using IDCM.Service.Common; -using IDCM.Service.Common.Core; -using IDCM.Service; -using IDCM.Data.Base; -using IDCM.Core; -using IDCM.Service.UIM; - -/******************************** - * Individual Data Center of Microbial resources (IDCM) - * A desktop software package for microbial resources researchers. - * - * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - * - * @Contact NO.1 Beichen West Road, Chaoyang District, Beijing 100101, Email: office@im.ac.cn - */ -namespace IDCM.ViewManager -{ - /// - /// IDCM用户交互界面主控管理器的实现类 - /// 说明: - /// 1. 用户交互界面主控管理器持有一个或多个Form/View/Dialog的界面句柄资源,同时包含相应的界面组件域的实际托管类实现对象实例。 - /// 对于用户交互呈现资源包括Form/View/Dialog三类表现形式,View嵌套在Form中作为子视图,Dialog作为动态创建的子例程。 - /// 2.在界面布局中包含若干动态展示性部件,其具体动态交互事务实现由对应的界面组件域的实际托管类维护,在用户界面主控管理器中侧重集中式的事务控制中转过程。 - /// 3. - /// @author JiahaiWu 2014-10-30 - /// - class IDCMFormManger - { - #region 构造&析构 - /// - /// 用户交互界面主控管理器构造方法 - /// - public IDCMFormManger() - { - mainForm = new IDCMForm(); //创建主框架界面实例对象 - DWorkMHub.note(mainForm); - mainForm.Shown += IDCMForm_Shown; - mainForm.setManager(this); //通知界面实例对象绑定事件控制中转例程 - } - /// - /// 用于共享成员实例获取当前用户交互界面主控管理器 - /// 注意: - /// 该静态方法获取实例对象可能为空,调用方法需负责检测获取实例失败的特例情形。 - /// - /// - public static IDCMFormManger getInstance() - { - return IDCMAppContext.MainManger; - } - /// - /// 用户交互界面主控管理器析构方法 - /// - ~IDCMFormManger() - { - Dispose(); - } - /// - /// 立即释放当前主控管理器的实例资源 - /// 注意: - /// 1.调用该方法意味着当前实例不再可用,目标状态即是将被自动销毁。 - /// 在后台任务轮询监视器的心跳检测事件处理中会根据此状态自动释放对当前实例句柄的引用。 - /// 2.该方法的实现务必保证冗余调用许可性,容错性,资源释放状态判定务必保持同步可用。 - /// - public void Dispose() - { - if (mainForm != null && !mainForm.IsDisposed) //释放主窗口界面实例资源 - { - mainForm.Close(); - mainForm.Dispose(); - mainForm = null; - } - ViewManagerHolder.Dispose(); - } - #endregion - #region 实例对象保持部分 - //声明释放主窗口界面实例 - internal IDCMForm mainForm = null; - #endregion - - /// - /// 主窗体初始化方法,用于激活新(或旧)实例的界面资源及其动态动态显示 - /// 注意: - /// 1.该方法的实现务必保证冗余调用许可性,容错性,资源释放状态判定务必保持同步可用。 - /// - /// 激活界面用户可见性(可选) - /// 初始化成功与否状态 - public bool initForm(bool activeShow = true) - { - mainForm.WindowState = FormWindowState.Maximized; - if (activeShow) - { - mainForm.Show(); - } - else - mainForm.Hide(); - return true; - } - -#region 接管视图组件的关键的事件处理区 - /// - /// IDCMForm主界面第一次显示后,打开默认的登录启动页面展示 - /// - /// - /// - private void IDCMForm_Shown(object sender, EventArgs e) - { - //启动欢迎页面 - startWorkSpace(); - } - - /// - /// 再次打开默认的登录启动页面展示 - /// - /// - /// - internal void OnRetryQuickStartConnect(object sender, IDCMAsyncEventArgs e) - { - ViewManagerHolder.activeChildView(typeof(HomeViewManager), true); - } - /// - /// 数据源预处理流程完成事件处理方法 - /// - /// - /// - internal void OnDataPrepared(object sender, IDCMAsyncEventArgs e) - { - Form waitingForm = new WaitingForm(); - waitingForm.MdiParent = mainForm; - waitingForm.Show(); - waitingForm.BringToFront(); - waitingForm.Update(); - ViewManagerHolder.activeChildView(typeof(HomeViewManager), false); - DWorkMHub.note(AsyncMessage.RequestHomeView); - waitingForm.Close(); - waitingForm.Dispose(); - } - internal void OnActiveHomeView(object sender, IDCMAsyncEventArgs e) - { - ViewManagerHolder.activeChildView(typeof(HomeViewManager), true); - } - internal void OnActiveGCMView(object sender, IDCMAsyncEventArgs e) - { - ////////////////////////////////////////////////////////////// - //判断用户登陆成功后方可激活GCM视图 - if (DataSourceHolder.GCMHolder.getSignedAuthInfo() == null) - { - MessageBox.Show("Please sign in before open the GCMView."); - return; - } - ////////////////////////////////////////////////////////////// - ViewManagerHolder.activeChildView(typeof(GCMViewManager), true); - } - internal void OnRetryDataPrepare(object sender, IDCMAsyncEventArgs e) - { - //Unimplement! - } - /// - /// 更新用户登录状态,到目标窗口视图中去 - /// - /// - /// - internal void OnUpdateGCMSignTip(object sender, IDCMAsyncEventArgs e) - { - updateUserStatus((e.values != null && e.values.Count()>0)? e.values[0].ToString():null); - } - internal void OnStartBackProgress(object sender, IDCMAsyncEventArgs e) - { - BackProgressIndicator.startBackProgress(); - } - internal void OnEndBackProgress(object sender, IDCMAsyncEventArgs e) - { - BackProgressIndicator.endBackProgress(); - } -#endregion - internal ManagerI getHomeViewManager() - { - return ViewManagerHolder.getManager(typeof(HomeViewManager)); - } - internal ManagerI getGCMViewManager() - { - return ViewManagerHolder.getManager(typeof(GCMViewManager)); - } - - /// - /// 启动当前工作空间 - /// 说明: - /// 1.startWorkSpace和reopenWorkSpace方法实现基本一致,但界面数据有所差异。 - /// - /// - public bool startWorkSpace() - { - if (DataSourceHolder.InWorking) - { - DialogResult res = MessageBox.Show("A workspace is in working, you need close it first.", "Close Workspace Notice", MessageBoxButtons.OK); - return false; - } - ManagerI view = ViewManagerHolder.getManager(typeof(StartRetainer)); - return view.initView(true); - } - /// - /// 启动一个新工作空间 - /// 说明: - /// 1.startWorkSpace和reopenWorkSpace方法实现基本一致,但界面数据有所差异。 - /// - /// 是否包含历史启动目录信息 - /// - public bool reopenWorkSpace(bool includeHistoryInfo=false) - { - if (DataSourceHolder.InWorking) - { - DialogResult res = MessageBox.Show("A workspace is in working, you need close it first.", "Close Workspace Notice", MessageBoxButtons.OK); - return false; - } - StartRetainer view = ViewManagerHolder.getManager(typeof(StartRetainer)) as StartRetainer; - if (includeHistoryInfo==false) - view.resetStartInfo(new Service.POO.StartInfo()); - else - view.resetAsDefaultWorkspace(false); - return view.initView(true); - } - /// - /// 关闭当前工作空间,仅保留主框架窗口 - /// - /// - public bool closeWorkSpace() - { - if (DataSourceHolder.InWorking) - { - ViewManagerHolder.Dispose(); - return DataSourceHolder.close(); - } - return true; - } - /// - /// 更新用户身份认证状态 - /// - /// - public void updateUserStatus(string uname = null) - { - string tip = "Off Line"; - if (uname != null) - tip = "On Line: " + uname; - mainForm.setLoginTip(tip); - } - public bool activeTemplateView() - { - ManagerI view = ViewManagerHolder.getManager(typeof(LibFieldManager)); - return view.initView(true); - } - /// - /// 显示用户登录或已登录用户的身份信息 - /// - /// - public bool activeAuthView() - { - AuthInfo authInfo = DataSourceHolder.getLoginAuthInfo(); - if (authInfo != null && authInfo.LoginFlag == true) //登录成功 - { - LoginStatusDlg loginStatus = new LoginStatusDlg(); - loginStatus.setSignInInfo(authInfo.Username, authInfo.Timestamp); - loginStatus.ShowDialog(); - loginStatus.Dispose(); - } - else - { - SignInDlg signin = new SignInDlg(); - signin.setReferAuthInfo(authInfo); - DialogResult res = signin.ShowDialog(); - authInfo = DataSourceHolder.getLoginAuthInfo(); - signin.Dispose(); - } - string tip = authInfo.LoginFlag ? authInfo.Username : null; - DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); - return true; - } - /// - /// 显示后台运行任务的概要信息 - /// - /// - public bool activeBackTaskInfoView() - { - TaskInfoDlg taskInfoDlg = new TaskInfoDlg(); - taskInfoDlg.Show(); - return true; - } - - public void showDBDataSearch() - { - ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); - if (mi != null) - { - HomeViewManager hvManager = (HomeViewManager)mi; - if (hvManager != null) - { - if (hvManager.isActive()) - { - hvManager.showDBDataSearch(); - } - } - } - } - public void frontDataSearch() - { - bool useHomeView = false; - ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); - if (mi != null) - { - HomeViewManager hvManager = (HomeViewManager)mi; - if (hvManager != null) - { - if (hvManager.isActive()) - { - useHomeView = true; - hvManager.frontDataSearch(); - } - } - } - if (useHomeView == false) - { - mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); - if (mi != null) - { - GCMViewManager gcmvManager = (GCMViewManager)mi; - if (gcmvManager != null) - { - if (gcmvManager.isActive()) - { - gcmvManager.frontDataSearch(); - } - } - } - } - } - public void frontSearchNext() - { - bool useHomeView = false; - ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); - if (mi != null) - { - HomeViewManager hvManager = (HomeViewManager)mi; - if (hvManager != null) - { - if (hvManager.isActive()) - { - useHomeView = true; - hvManager.frontSearchNext(); - } - } - } - if (useHomeView == false) - { - mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); - if (mi != null) - { - GCMViewManager gcmvManager = (GCMViewManager)mi; - if (gcmvManager != null) - { - if (gcmvManager.isActive()) - { - ////////////////////////////// - //gcmvManager.frontSearchNext(); - } - } - } - } - } - public void frontSearchPrev() - { - bool useHomeView = false; - ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); - if (mi != null) - { - HomeViewManager hvManager = (HomeViewManager)mi; - if (hvManager != null) - { - if (hvManager.isActive()) - { - useHomeView = true; - hvManager.frontSearchPrev(); - } - } - } - if (useHomeView == false) - { - mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); - if (mi != null) - { - GCMViewManager gcmvManager = (GCMViewManager)mi; - if (gcmvManager != null) - { - if (gcmvManager.isActive()) - { - ////////////////////////////// - //gcmvManager.frontSearchPrev(); - } - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using IDCM.AppContext; +using IDCM.Forms; +using IDCM.Service.Common; +using IDCM.Service.Common.Core; +using IDCM.Service; +using IDCM.Data.Base; +using IDCM.Core; +using IDCM.Service.UIM; + +/******************************** + * Individual Data Center of Microbial resources (IDCM) + * A desktop software package for microbial resources researchers. + * + * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + * + * @Contact NO.1 Beichen West Road, Chaoyang District, Beijing 100101, Email: office@im.ac.cn + */ +namespace IDCM.ViewManager +{ + /// + /// IDCM用户交互界面主控管理器的实现类 + /// 说明: + /// 1. 用户交互界面主控管理器持有一个或多个Form/View/Dialog的界面句柄资源,同时包含相应的界面组件域的实际托管类实现对象实例。 + /// 对于用户交互呈现资源包括Form/View/Dialog三类表现形式,View嵌套在Form中作为子视图,Dialog作为动态创建的子例程。 + /// 2.在界面布局中包含若干动态展示性部件,其具体动态交互事务实现由对应的界面组件域的实际托管类维护,在用户界面主控管理器中侧重集中式的事务控制中转过程。 + /// 3. + /// @author JiahaiWu 2014-10-30 + /// + class IDCMFormManger + { + #region 构造&析构 + /// + /// 用户交互界面主控管理器构造方法 + /// + public IDCMFormManger() + { + mainForm = new IDCMForm(); //创建主框架界面实例对象 + DWorkMHub.note(mainForm); + mainForm.Shown += IDCMForm_Shown; + mainForm.setManager(this); //通知界面实例对象绑定事件控制中转例程 + } + /// + /// 用于共享成员实例获取当前用户交互界面主控管理器 + /// 注意: + /// 该静态方法获取实例对象可能为空,调用方法需负责检测获取实例失败的特例情形。 + /// + /// + public static IDCMFormManger getInstance() + { + return IDCMAppContext.MainManger; + } + /// + /// 用户交互界面主控管理器析构方法 + /// + ~IDCMFormManger() + { + Dispose(); + } + /// + /// 立即释放当前主控管理器的实例资源 + /// 注意: + /// 1.调用该方法意味着当前实例不再可用,目标状态即是将被自动销毁。 + /// 在后台任务轮询监视器的心跳检测事件处理中会根据此状态自动释放对当前实例句柄的引用。 + /// 2.该方法的实现务必保证冗余调用许可性,容错性,资源释放状态判定务必保持同步可用。 + /// + public void Dispose() + { + if (mainForm != null && !mainForm.IsDisposed) //释放主窗口界面实例资源 + { + mainForm.Close(); + mainForm.Dispose(); + mainForm = null; + } + ViewManagerHolder.Dispose(); + } + #endregion + #region 实例对象保持部分 + //声明释放主窗口界面实例 + internal IDCMForm mainForm = null; + #endregion + + /// + /// 主窗体初始化方法,用于激活新(或旧)实例的界面资源及其动态动态显示 + /// 注意: + /// 1.该方法的实现务必保证冗余调用许可性,容错性,资源释放状态判定务必保持同步可用。 + /// + /// 激活界面用户可见性(可选) + /// 初始化成功与否状态 + public bool initForm(bool activeShow = true) + { + mainForm.WindowState = FormWindowState.Maximized; + if (activeShow) + { + mainForm.Show(); + } + else + mainForm.Hide(); + return true; + } + +#region 接管视图组件的关键的事件处理区 + /// + /// IDCMForm主界面第一次显示后,打开默认的登录启动页面展示 + /// + /// + /// + private void IDCMForm_Shown(object sender, EventArgs e) + { + //启动欢迎页面 + startWorkSpace(); + } + + /// + /// 再次打开默认的登录启动页面展示 + /// + /// + /// + internal void OnRetryQuickStartConnect(object sender, IDCMAsyncEventArgs e) + { + ViewManagerHolder.activeChildView(typeof(HomeViewManager), true); + } + /// + /// 数据源预处理流程完成事件处理方法 + /// + /// + /// + internal void OnDataPrepared(object sender, IDCMAsyncEventArgs e) + { + Form waitingForm = new WaitingForm(); + waitingForm.MdiParent = mainForm; + waitingForm.Show(); + waitingForm.BringToFront(); + waitingForm.Update(); + ViewManagerHolder.activeChildView(typeof(HomeViewManager), false); + DWorkMHub.note(AsyncMessage.RequestHomeView); + waitingForm.Close(); + waitingForm.Dispose(); + } + internal void OnActiveHomeView(object sender, IDCMAsyncEventArgs e) + { + ViewManagerHolder.activeChildView(typeof(HomeViewManager), true); + } + internal void OnActiveGCMView(object sender, IDCMAsyncEventArgs e) + { + ////////////////////////////////////////////////////////////// + //判断用户登陆成功后方可激活GCM视图 + if (DataSourceHolder.GCMHolder.getSignedAuthInfo() == null) + { + MessageBox.Show("Please sign in before open the GCMView."); + return; + } + ////////////////////////////////////////////////////////////// + ViewManagerHolder.activeChildView(typeof(GCMViewManager), true); + } + internal void OnRetryDataPrepare(object sender, IDCMAsyncEventArgs e) + { + //Unimplement! + } + /// + /// 更新用户登录状态,到目标窗口视图中去 + /// + /// + /// + internal void OnUpdateGCMSignTip(object sender, IDCMAsyncEventArgs e) + { + updateUserStatus((e.values != null && e.values.Count()>0)? e.values[0].ToString():null); + } + internal void OnStartBackProgress(object sender, IDCMAsyncEventArgs e) + { + BackProgressIndicator.startBackProgress(); + } + internal void OnEndBackProgress(object sender, IDCMAsyncEventArgs e) + { + BackProgressIndicator.endBackProgress(); + } +#endregion + internal ManagerI getHomeViewManager() + { + return ViewManagerHolder.getManager(typeof(HomeViewManager)); + } + internal ManagerI getGCMViewManager() + { + return ViewManagerHolder.getManager(typeof(GCMViewManager)); + } + + /// + /// 启动当前工作空间 + /// 说明: + /// 1.startWorkSpace和reopenWorkSpace方法实现基本一致,但界面数据有所差异。 + /// + /// + public bool startWorkSpace() + { + if (DataSourceHolder.InWorking) + { + DialogResult res = MessageBox.Show("A workspace is in working, you need close it first.", "Close Workspace Notice", MessageBoxButtons.OK); + return false; + } + ManagerI view = ViewManagerHolder.getManager(typeof(StartRetainer)); + return view.initView(true); + } + /// + /// 启动一个新工作空间 + /// 说明: + /// 1.startWorkSpace和reopenWorkSpace方法实现基本一致,但界面数据有所差异。 + /// + /// 是否包含历史启动目录信息 + /// + public bool reopenWorkSpace(bool includeHistoryInfo=false) + { + if (DataSourceHolder.InWorking) + { + DialogResult res = MessageBox.Show("A workspace is in working, you need close it first.", "Close Workspace Notice", MessageBoxButtons.OK); + return false; + } + StartRetainer view = ViewManagerHolder.getManager(typeof(StartRetainer)) as StartRetainer; + if (includeHistoryInfo==false) + view.resetStartInfo(new Service.POO.StartInfo()); + else + view.resetAsDefaultWorkspace(false); + return view.initView(true); + } + /// + /// 关闭当前工作空间,仅保留主框架窗口 + /// + /// + public bool closeWorkSpace() + { + if (DataSourceHolder.InWorking) + { + ViewManagerHolder.Dispose(); + return DataSourceHolder.close(); + } + return true; + } + /// + /// 更新用户身份认证状态 + /// + /// + public void updateUserStatus(string uname = null) + { + string tip = "Off Line"; + if (uname != null) + tip = "On Line: " + uname; + mainForm.setLoginTip(tip); + } + public bool activeTemplateView() + { + ManagerI view = ViewManagerHolder.getManager(typeof(LibFieldManager)); + return view.initView(true); + } + /// + /// 显示用户登录或已登录用户的身份信息 + /// + /// + public bool activeAuthView() + { + AuthInfo authInfo = DataSourceHolder.getLoginAuthInfo(); + if (authInfo != null && authInfo.LoginFlag == true) //登录成功 + { + LoginStatusDlg loginStatus = new LoginStatusDlg(); + loginStatus.setSignInInfo(authInfo.Username, authInfo.Timestamp); + loginStatus.ShowDialog(); + loginStatus.Dispose(); + } + else + { + SignInDlg signin = new SignInDlg(); + signin.setReferAuthInfo(authInfo); + DialogResult res = signin.ShowDialog(); + authInfo = DataSourceHolder.getLoginAuthInfo(); + signin.Dispose(); + } + string tip = authInfo.LoginFlag ? authInfo.Username : null; + DWorkMHub.note(new AsyncMessage(AsyncMessage.UpdateGCMSignTip, tip == null ? null : new string[] { tip })); + return true; + } + /// + /// 显示后台运行任务的概要信息 + /// + /// + public bool activeBackTaskInfoView() + { + TaskInfoDlg taskInfoDlg = new TaskInfoDlg(); + taskInfoDlg.Show(); + return true; + } + + public void showDBDataSearch() + { + ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); + if (mi != null) + { + HomeViewManager hvManager = (HomeViewManager)mi; + if (hvManager != null) + { + if (hvManager.isActive()) + { + hvManager.showDBDataSearch(); + } + } + } + } + public void frontDataSearch() + { + bool useHomeView = false; + ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); + if (mi != null) + { + HomeViewManager hvManager = (HomeViewManager)mi; + if (hvManager != null) + { + if (hvManager.isActive()) + { + useHomeView = true; + hvManager.frontDataSearch(); + } + } + } + if (useHomeView == false) + { + mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); + if (mi != null) + { + GCMViewManager gcmvManager = (GCMViewManager)mi; + if (gcmvManager != null) + { + if (gcmvManager.isActive()) + { + gcmvManager.frontDataSearch(); + } + } + } + } + } + public void frontSearchNext() + { + bool useHomeView = false; + ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); + if (mi != null) + { + HomeViewManager hvManager = (HomeViewManager)mi; + if (hvManager != null) + { + if (hvManager.isActive()) + { + useHomeView = true; + hvManager.frontSearchNext(); + } + } + } + if (useHomeView == false) + { + mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); + if (mi != null) + { + GCMViewManager gcmvManager = (GCMViewManager)mi; + if (gcmvManager != null) + { + if (gcmvManager.isActive()) + { + ////////////////////////////// + //gcmvManager.frontSearchNext(); + } + } + } + } + } + public void frontSearchPrev() + { + bool useHomeView = false; + ManagerI mi = ViewManagerHolder.getManager(typeof(HomeViewManager)); + if (mi != null) + { + HomeViewManager hvManager = (HomeViewManager)mi; + if (hvManager != null) + { + if (hvManager.isActive()) + { + useHomeView = true; + hvManager.frontSearchPrev(); + } + } + } + if (useHomeView == false) + { + mi = ViewManagerHolder.getManager(typeof(GCMViewManager)); + if (mi != null) + { + GCMViewManager gcmvManager = (GCMViewManager)mi; + if (gcmvManager != null) + { + if (gcmvManager.isActive()) + { + ////////////////////////////// + //gcmvManager.frontSearchPrev(); + } + } + } + } + } + } +} diff --git a/IDCM/IDCM/ViewManager/StartRetainer.cs b/IDCM/IDCM/ViewManager/StartRetainer.cs index 345eb34..4b7403e 100644 --- a/IDCM/IDCM/ViewManager/StartRetainer.cs +++ b/IDCM/IDCM/ViewManager/StartRetainer.cs @@ -1,164 +1,164 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using IDCM.AppContext; -using IDCM.Service; -using IDCM.Service.POO; -using IDCM.Forms; -using System.Windows.Forms; -using IDCM.Service.Common.Core; -using IDCM.Service.Common; -using System.Configuration; -using IDCM.Data.Base; -using IDCM.Core; -using IDCM.Service.DataTransfer; - -namespace IDCM.ViewManager -{ - /// - /// 初始化载入信息管理 - /// 说明: - /// 1.每次初始化显示欢迎登陆页面,主要包含数据文件地址、访问用户及其密码三部分。 - /// 2.默认情况下每次启动都将显示欢迎页面,当有用户设置了默认的工作空间生效后,则会在启动过程中快速跳过用户输入的环节。 - /// 3.用户登录名称建议使用与GCM上注册通过的账号,以便可以有效实现数据同步功能。使用无效用户名,将仅能实现本地数据库访问管理。 - /// 4.这里的登录用户名将作为本地数据库访问的校验码,数据库实例成功加载要求正确的输入登录用户名(初始数据库指定用户名例外)。 - /// 5.这里的登录密码对应的是GCM上注册账号的密码,该密码不在本地数据库中发挥作用,主要用于GCM网络数据资源访问的登录验证的条件。 - /// 6.在输入登录密码的时候,登录用户名不可为空,否则登录用户名和登录密码均可以空值设定。 - /// 7.GCM注册账号的有效性验证并不会阻止用户进入本地数据库管理界面,但正确输入可以及时打开GCM网络数据资源同步服务。 - /// - class StartRetainer:ManagerA - { - - #region 构造&析构 - public StartRetainer() - { - startInfo = IDCMEnvironment.getLastStartInfo(); - startView = new StartView(); - startView.FormClosed += OnStartViewClosed; - startView.OnRequestHelp += OnStartViewRequestHelp; - } - - public static StartRetainer getInstance() - { - ManagerI am = ViewManagerHolder.getManager(typeof(StartRetainer)); - return am == null ? null : (am as StartRetainer); - } - ~StartRetainer() - { - dispose(); - } - #endregion - #region 实例对象保持部分 - - private StartInfo startInfo =null; - private StartView startView = null; - #endregion - #region 接口实例化部分 - public override void dispose() - { - base.dispose(); - startInfo = null; - } - public override void setMdiParent(Form pForm) - { - if(!isDisposed()) - startView.MdiParent = pForm; - } - public override void setMaxToNormal() - { - } - public override void setToMaxmize(bool activeFront = false) - { - } - /// - /// 重置一个数据源的启动对象实例 - /// - /// - public void resetStartInfo(StartInfo si) - { - startInfo = si; - } - /// - /// 重置一个数据源的启动对象实例的默认启动行为 - /// - /// - public void resetAsDefaultWorkspace(bool asDefault=false) - { - startInfo.asDefaultWorkspace=asDefault; - } - /// - /// 对象实例化,显示用户界面方法 - /// - /// - /// - public override bool initView(bool activeShow = true) - { - if (activeShow) - { - startView.setReferStartInfo(ref startInfo); - startView.Show(); - } - return true; - } - /// - /// 当用户操作确认后窗口关闭,触发必要的数据加载流程和显示Loding进程状态 - /// - /// - /// - public void OnStartViewClosed(object sender, FormClosedEventArgs e) - { - CloseReason res = e.CloseReason; - DialogResult dres = startView.DialogResult; - if (res.Equals(CloseReason.UserClosing) || dres.Equals(DialogResult.OK)) - { - if (startInfo.Location != null && startInfo.LoginName != null) - { - Form waitingForm = new WaitingForm(); - waitingForm.MdiParent = startView.MdiParent; - waitingForm.Show(); - waitingForm.BringToFront(); - waitingForm.Update(); - if (DataSourceHolder.connectWorkspace(startInfo.Location, startInfo.LoginName)) - { - if (startInfo.GCMPassword != null) - { - DataSourceHolder.connectGCM(startInfo.LoginName, startInfo.GCMPassword); - } - IDCMEnvironment.noteStartInfo(startInfo.Location, startInfo.asDefaultWorkspace, startInfo.LoginName, startInfo.rememberPassword ? startInfo.GCMPassword : null); - DataSourceHolder.prepareInstance(); - DWorkMHub.note(AsyncMessage.DataPrepared); - } - else - { - MessageBox.Show("DataSource Open Failed."); //MessageBox.Show("DataSource Open Failed. You can input again by 'Open' menu item in 'File' menu item."); - DWorkMHub.note(AsyncMessage.RetryQuickStartConnect); - } - waitingForm.Close(); - waitingForm.Dispose(); - } - } - //else if(dres.Equals(DialogResult.Cancel)) - //{ - // DialogResult cres= MessageBox.Show("Close IDCM Application?", MessageBoxButtons.YesNo); - // if(cres.Equals(DialogResult.Yes)) - // DWorkMHub.note(AsyncMessage.RequestCloseIDCMForm); - //} - } - public void OnStartViewRequestHelp(object sender, HelpEventArgs e) - { - HelpDocRequester.requestHelpDoc(HelpDocConstants.StartViewTag); - } - - public override bool isDisposed() - { - if (_isDisposed == false) - { - _isDisposed = (startView == null || startView.Disposing || startView.IsDisposed); - } - return _isDisposed; - } - #endregion - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using IDCM.AppContext; +using IDCM.Service; +using IDCM.Service.POO; +using IDCM.Forms; +using System.Windows.Forms; +using IDCM.Service.Common.Core; +using IDCM.Service.Common; +using System.Configuration; +using IDCM.Data.Base; +using IDCM.Core; +using IDCM.Service.DataTransfer; + +namespace IDCM.ViewManager +{ + /// + /// 初始化载入信息管理 + /// 说明: + /// 1.每次初始化显示欢迎登陆页面,主要包含数据文件地址、访问用户及其密码三部分。 + /// 2.默认情况下每次启动都将显示欢迎页面,当有用户设置了默认的工作空间生效后,则会在启动过程中快速跳过用户输入的环节。 + /// 3.用户登录名称建议使用与GCM上注册通过的账号,以便可以有效实现数据同步功能。使用无效用户名,将仅能实现本地数据库访问管理。 + /// 4.这里的登录用户名将作为本地数据库访问的校验码,数据库实例成功加载要求正确的输入登录用户名(初始数据库指定用户名例外)。 + /// 5.这里的登录密码对应的是GCM上注册账号的密码,该密码不在本地数据库中发挥作用,主要用于GCM网络数据资源访问的登录验证的条件。 + /// 6.在输入登录密码的时候,登录用户名不可为空,否则登录用户名和登录密码均可以空值设定。 + /// 7.GCM注册账号的有效性验证并不会阻止用户进入本地数据库管理界面,但正确输入可以及时打开GCM网络数据资源同步服务。 + /// + class StartRetainer:ManagerA + { + + #region 构造&析构 + public StartRetainer() + { + startInfo = IDCMEnvironment.getLastStartInfo(); + startView = new StartView(); + startView.FormClosed += OnStartViewClosed; + startView.OnRequestHelp += OnStartViewRequestHelp; + } + + public static StartRetainer getInstance() + { + ManagerI am = ViewManagerHolder.getManager(typeof(StartRetainer)); + return am == null ? null : (am as StartRetainer); + } + ~StartRetainer() + { + dispose(); + } + #endregion + #region 实例对象保持部分 + + private StartInfo startInfo =null; + private StartView startView = null; + #endregion + #region 接口实例化部分 + public override void dispose() + { + base.dispose(); + startInfo = null; + } + public override void setMdiParent(Form pForm) + { + if(!isDisposed()) + startView.MdiParent = pForm; + } + public override void setMaxToNormal() + { + } + public override void setToMaxmize(bool activeFront = false) + { + } + /// + /// 重置一个数据源的启动对象实例 + /// + /// + public void resetStartInfo(StartInfo si) + { + startInfo = si; + } + /// + /// 重置一个数据源的启动对象实例的默认启动行为 + /// + /// + public void resetAsDefaultWorkspace(bool asDefault=false) + { + startInfo.asDefaultWorkspace=asDefault; + } + /// + /// 对象实例化,显示用户界面方法 + /// + /// + /// + public override bool initView(bool activeShow = true) + { + if (activeShow) + { + startView.setReferStartInfo(ref startInfo); + startView.Show(); + } + return true; + } + /// + /// 当用户操作确认后窗口关闭,触发必要的数据加载流程和显示Loding进程状态 + /// + /// + /// + public void OnStartViewClosed(object sender, FormClosedEventArgs e) + { + CloseReason res = e.CloseReason; + DialogResult dres = startView.DialogResult; + if (res.Equals(CloseReason.UserClosing) || dres.Equals(DialogResult.OK)) + { + if (startInfo.Location != null && startInfo.LoginName != null) + { + Form waitingForm = new WaitingForm(); + waitingForm.MdiParent = startView.MdiParent; + waitingForm.Show(); + waitingForm.BringToFront(); + waitingForm.Update(); + if (DataSourceHolder.connectWorkspace(startInfo.Location, startInfo.LoginName)) + { + if (startInfo.GCMPassword != null) + { + DataSourceHolder.connectGCM(startInfo.LoginName, startInfo.GCMPassword); + } + IDCMEnvironment.noteStartInfo(startInfo.Location, startInfo.asDefaultWorkspace, startInfo.LoginName, startInfo.rememberPassword ? startInfo.GCMPassword : null); + DataSourceHolder.prepareInstance(); + DWorkMHub.note(AsyncMessage.DataPrepared); + } + else + { + MessageBox.Show("DataSource Open Failed."); //MessageBox.Show("DataSource Open Failed. You can input again by 'Open' menu item in 'File' menu item."); + DWorkMHub.note(AsyncMessage.RetryQuickStartConnect); + } + waitingForm.Close(); + waitingForm.Dispose(); + } + } + //else if(dres.Equals(DialogResult.Cancel)) + //{ + // DialogResult cres= MessageBox.Show("Close IDCM Application?", MessageBoxButtons.YesNo); + // if(cres.Equals(DialogResult.Yes)) + // DWorkMHub.note(AsyncMessage.RequestCloseIDCMForm); + //} + } + public void OnStartViewRequestHelp(object sender, HelpEventArgs e) + { + HelpDocRequester.requestHelpDoc(HelpDocConstants.StartViewTag); + } + + public override bool isDisposed() + { + if (_isDisposed == false) + { + _isDisposed = (startView == null || startView.Disposing || startView.IsDisposed); + } + return _isDisposed; + } + #endregion + + } +} diff --git a/IDCM/dgmls/IDCM_outline.dgml b/IDCM/dgmls/IDCM_outline.dgml index 116da2c..2b0a8b4 100644 --- a/IDCM/dgmls/IDCM_outline.dgml +++ b/IDCM/dgmls/IDCM_outline.dgml @@ -1,785 +1,785 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/IDCM/docs/\347\263\273\347\273\237\350\256\276\350\256\241\351\203\250\345\210\206\345\233\276\344\276\213.vsd" "b/IDCM/docs/\347\263\273\347\273\237\350\256\276\350\256\241\351\203\250\345\210\206\345\233\276\344\276\213.vsd" new file mode 100644 index 0000000000000000000000000000000000000000..f3dfa350eb3704e3138ab44984bfa1f4031772fd GIT binary patch literal 200192 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