初学时,有了想法却完全不知道该从何下指,此序列将抛砖引玉,与大家共同学习进步。

  一个程序的初始,必然是启动。

  我的要求:

  1、应用程序保持单例;

  2、从配置文件加载一些基础数据进行初始化;

  3、显示软件的LOGO页面;

  4、判断应用程序是否有更新;

  4、进入用户登录界面;

  5、用户成功登录后显示主界面。

  

  如上图,基本达成目标,这个项目也是很简单的结构:

看窗体名称就知道各自的用途了。主要的Program.cs代码如下:

  1. static class Program
  2. {
  3. public static bool 切换用户 = false;
  4.  
  5. /// <summary>
  6. /// 主体框架应用程序的主入口点。
  7. /// </summary>
  8. [STAThread]
  9. static void Main()
  10. {
  11. string 实例标识 = Assembly.GetExecutingAssembly().GetName().Name + "_SingtonB20";
  12. Mutex mutex = new Mutex(true, 实例标识, out bool 单实例);
  13. if (!单实例)
  14. {
  15. 唤醒进程(实例标识);
  16. return;
  17. }
  18.  
  19. Application.EnableVisualStyles();
  20. Application.SetCompatibleTextRenderingDefault(false);
  21. Application.DoEvents();
  22.  
  23. //初始化全局DS
  24. if (GlbInfo.DSGlb == null) GlbInfo.DSGlb = new System.Data.DataSet();
  25. else
  26. {
  27. GlbInfo.DSGlb.Clear();
  28. GlbInfo.DSGlb.Tables.Clear();
  29. }
  30.  
  31. //加载全局多语言资源
  32. try
  33. {
  34. AppInit.CreateDT_MulLang(AppInfo.GetFile(AppInfo.AppFile.MulMessage), "Message_Core");
  35. AppInit.CreateDT_MulLang(AppInfo.GetFile(AppInfo.AppFile.MulSurface), "Surface_Core");
  36. }
  37. catch (Exception ex)
  38. {
  39. MessageBox.Show(ex.Message);
  40. Environment.Exit();
  41. }
  42.  
  43. //展示闪屏窗体
  44. Fm20Splash 闪屏窗 = new Fm20Splash();
  45. 闪屏窗.ShowDialog();
  46.  
  47. //系统检测正常则显示登录界面,否则退出应用
  48. if (闪屏窗.DialogResult == DialogResult.OK)
  49. {
  50. 显示登录:
  51. 切换用户 = false;
  52. Fm20Login fmLogin = new Fm20Login();
  53. fmLogin.ShowDialog();
  54. if (fmLogin.DialogResult == DialogResult.OK)
  55. {
  56. Application.Run(new Fm20Main());
  57. }
  58. else
  59. {
  60. Application.Exit();
  61. }
  62. //当关闭主程序的时候会执行这个代码,在关闭主程序的时候需要给IsLogin 设置成true
  63. //重新回到登录窗口.
  64. if (切换用户)
  65. {
  66. goto 显示登录;
  67. }
  68.  
  69. }
  70. else
  71. {
  72. Application.Exit();
  73. }
  74.  
  75. }
  76. public static void 唤醒进程(string 进程名称)
  77. {
  78. try
  79. {
  80. Process proc = Process.GetCurrentProcess();
  81.  
  82. string assemblyName = Assembly.GetExecutingAssembly().GetName().Name + 进程名称;
  83.  
  84. foreach (Process 进程 in Process.GetProcessesByName(进程名称))
  85. {
  86. if (proc.Id != 进程.Id)
  87. {
  88. IntPtr hWnd = 进程.MainWindowHandle;
  89. if (WinAPI.IsIconic(hWnd))
  90. {
  91. WinAPI.ShowWindowAsync(hWnd, WinAPIConst.SW_RESTORE);
  92. }
  93. WinAPI.SetForegroundWindow(hWnd);
  94. return;
  95. }
  96. }
  97. }
  98. catch
  99. {
  100. }
  101. }
  102.  
  103. }

Program.cs

一、第一个被运行的窗体(闪屏窗口):

  1. /// <summary>
  2. /// Splash闪屏窗体
  3. /// </summary>
  4. public partial class Fm20Splash : Fm11Base
  5. {
  6. /// <summary>
  7. /// 创建闪屏窗体
  8. /// </summary>
  9. public Fm20Splash()
  10. {
  11. InitializeComponent();
  12. OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  13. GlbInfo.Language = oINI.ReadString("Global", "CurrentLang", "LL");
  14. string licCompany = oINI.ReadString("Global", "License_To_" + GlbInfo.Language, "所有人");
  15. LabLicTo.Text = MultiLang.Surface(this, "LabLicTo", "授权给: ") + licCompany;
  16. if (GlbInfo.Language == "LL") LabSysTitle.Text = "IMES (智能制造执行系统)"; else LabSysTitle.Text= "IMES (Intelligent Manufacturing Execution System)";
  17. }
  18.  
  19. private void Fm20Splash_MouseDown(object sender, MouseEventArgs e)
  20. {
  21. WinAPI.ReleaseCapture();
  22. WinAPI.SendMessage(Handle, WinAPIConst.WM_SYSCOMMAND, WinAPIConst.SC_MOVE + WinAPIConst.HTCAPTION, );
  23. }
  24.  
  25. private static bool Delay(int delayTime)
  26. {
  27. DateTime now = DateTime.Now;
  28. int s;
  29. do
  30. {
  31. TimeSpan spand = DateTime.Now - now;
  32. s = spand.Seconds;
  33. Application.DoEvents();
  34. }
  35. while (s < delayTime);
  36. return true;
  37. }
  38.  
  39. private void Fm20Splash_Shown(object sender, EventArgs e)
  40. {
  41. //开始检测系统配置是否符合要求
  42. //检测1:FRAMEWORK
  43. //检测2:检查组件资源
  44. #region 检测1:检测更新
  45. SetMainStatus(MultiLang.Surface(this, "ChkAppVersion","正在检查系统版本..."));
  46. Delay();
  47.  
  48. string localPath = AppDomain.CurrentDomain.BaseDirectory;
  49. localPath = localPath.Substring(, localPath.Length - );
  50. string updateTxtFile = localPath + @"\UpdateLog.txt";
  51. //当更新指引文件不存在(如调试时),将跳过自动更新检测.
  52. if (File.Exists(updateTxtFile))
  53. {
  54. string[] allLines = File.ReadAllLines(localPath + @"\UpdateLog.txt");
  55.  
  56. string remotePath = string.Empty;
  57. foreach (string line in allLines)
  58. {
  59. if (line.IndexOf("UpdatePath=") >= )
  60. {
  61. remotePath = line.Substring(line.IndexOf("UpdatePath=") + );
  62. break;
  63. }
  64. }
  65.  
  66. if (NeedUpdate(localPath, remotePath))
  67. {
  68. File.Delete(localPath + "\\" + @"A19.exe");
  69. File.Copy(remotePath + "\\" + @"A19.exe", localPath + "\\" + @"A19.exe", true);
  70.  
  71. string updFile = AppDomain.CurrentDomain.BaseDirectory + @"A19.exe";
  72. Process.Start(updFile);
  73. DialogResult = DialogResult.Cancel;
  74. Application.Exit();
  75. }
  76. }
  77. #endregion
  78.  
  79. #region 清理过期插件版本,只保留最近的一项
  80. //根目录下不存在DLL或EXE原文件,则查找日期最后面的文件作为加载文件
  81. //查找M开头的exe和dll文件,规划M2-M8为模组EXE命名区域.如M22,M88
  82. var modFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory).Select(f => new FileInfo(f)).Where(f => ((f.Name.IndexOf("M") == ) && f.Name.IndexOf("--") == ) && (f.Name.IndexOf(".exe") >= || f.Name.IndexOf(".dll") >= )).OrderBy(f => f.Name);
  83. string prevFileSpl = string.Empty;
  84. FileInfo ofi = null;
  85. foreach (var s in modFiles)
  86. {
  87. if (!string.IsNullOrEmpty(prevFileSpl))
  88. {
  89. if (s.Name.Substring(, s.Name.IndexOf("--")) == prevFileSpl.Substring(, prevFileSpl.IndexOf("--")))
  90. {
  91. if (s.LastWriteTime >= ofi.LastWriteTime)
  92. {
  93. ofi.Delete();
  94. }
  95. else
  96. {
  97. s.Delete();
  98. }
  99. }
  100. }
  101. ofi = s;
  102. prevFileSpl = s.Name;
  103. }
  104.  
  105. #endregion
  106.  
  107. DialogResult = DialogResult.OK;
  108. }
  109. /// <summary>
  110. /// 判断程序是否需要更新
  111. /// </summary>
  112. /// <param name="localPath"></param>
  113. /// <param name="remotePath"></param>
  114. /// <returns></returns>
  115. private bool NeedUpdate(string localPath, string remotePath)
  116. {
  117. try
  118. {
  119. FileInfo fiUL = new FileInfo(localPath + @"\UpdateLog.txt");
  120. FileInfo fiUR = new FileInfo(remotePath + @"\UpdateLog.txt");
  121. if (fiUL.LastWriteTime == fiUR.LastWriteTime)
  122. {
  123. SetMainStatus(MultiLang.Surface(this, "ChkAppVersion","正在检查系统版本...") + "OK!");
  124. return false;
  125. }
  126. else
  127. {
  128. return true;
  129. }
  130. }
  131. catch (Exception)
  132. {
  133. //出错将返回false,比如:没有设置好更新路径。
  134. return false;
  135. }
  136. }
  137. }

Fm20Splash.cs

它继承自一个基类窗体Fm11Base,默认会做一些例如加载多语言文本的事情,没这个需求直接继承Form也可以。

二、这个页面通过后(有更新的话会跳到自动更新程序,可以忽略),会进入到登录窗体:

  1. /// <summary>
  2. /// 登录窗体
  3. /// </summary>
  4. public partial class Fm20Login : Fm11Base
  5. {
  6. bool IsLogin = false;
  7. protected internal string SelAccountNO ;
  8. protected internal string SelAccountName ;
  9. private static readonly string DftAESKeyOfDlls = @"James/Wang/";
  10.  
  11. private bool m_aeroEnabled;
  12. private static Fm20LoginTitle fm20LoginTitle;
  13.  
  14. public string UserID
  15. {
  16. get { return TxtUserID.Text; }
  17. set { TxtUserID.Text = value; }
  18. }
  19.  
  20. public Fm20Login()
  21. {
  22. m_aeroEnabled = false;
  23. InitializeComponent();
  24. fm20LoginTitle = new Fm20LoginTitle();
  25.  
  26. }
  27.  
  28. #region 无边框窗体处理
  29. /// <summary>
  30. /// 拖动无边框窗体
  31. /// </summary>
  32. /// <param name="sender"></param>
  33. /// <param name="e"></param>
  34. private void OnFormDrag(object sender, MouseEventArgs e)
  35. {
  36. WinAPI.ReleaseCapture();
  37. WinAPI.SendMessage(Handle, WinAPIConst.WM_SYSCOMMAND, WinAPIConst.SC_MOVE + WinAPIConst.HTCAPTION, );
  38. }
  39.  
  40. protected override CreateParams CreateParams
  41. {
  42. get
  43. {
  44. m_aeroEnabled = CheckAeroEnabled();
  45. CreateParams cp = base.CreateParams;
  46. if (!m_aeroEnabled)
  47. cp.ClassStyle |= WinAPIConst.CS_DropSHADOW;
  48. return cp;
  49. }
  50. }
  51.  
  52. private bool CheckAeroEnabled()
  53. {
  54. if (Environment.OSVersion.Version.Major >= )
  55. {
  56. int enabled = ;
  57. WinAPI.DwmIsCompositionEnabled(ref enabled);
  58. return (enabled == ) ? true : false;
  59. }
  60. return false;
  61. }
  62.  
  63. protected override void WndProc(ref Message m)
  64. {
  65. base.WndProc(ref m);
  66.  
  67. switch (m.Msg)
  68. {
  69. case WinAPIConst.WM_NCPAINT:
  70. if (m_aeroEnabled)
  71. {
  72. var v = ;
  73. WinAPI.DwmSetWindowAttribute(this.Handle, , ref v, );
  74. WinAPIConst.MARGINS margins = new WinAPIConst.MARGINS()
  75. {
  76. bottomHeight = ,
  77. leftWidth = ,
  78. rightWidth = ,
  79. topHeight =
  80. };
  81. WinAPI.DwmExtendFrameIntoClientArea(this.Handle, ref margins);
  82.  
  83. }
  84. break;
  85. default:
  86. break;
  87. }
  88.  
  89. if (m.Msg == WinAPIConst.WM_NCHITTEST && (int)m.Result == WinAPIConst.HTCLIENT)
  90. m.Result = (IntPtr)WinAPIConst.HTCAPTION;
  91.  
  92. }
  93.  
  94. #endregion
  95.  
  96. private void MitClose_Click(object sender, EventArgs e)
  97. {
  98. DialogResult = DialogResult.Cancel;
  99. }
  100.  
  101. private void MitMini_Click(object sender, EventArgs e)
  102. {
  103. WindowState = FormWindowState.Minimized;
  104. }
  105.  
  106. private void Fm20Login_Shown(object sender, EventArgs e)
  107. {
  108. if (!fm20LoginTitle.Visible)
  109. {
  110. fm20LoginTitle.Show(this);
  111. }
  112. else
  113. {
  114. fm20LoginTitle.BringToFront();
  115. }
  116. fm20LoginTitle.Left = this.Left + this.Width / - fm20LoginTitle.Width / ;
  117. fm20LoginTitle.Top = this.Top + SplPnlMain.Panel1.Height - fm20LoginTitle.Height / ;
  118. }
  119.  
  120. private void Fm20Login_Move(object sender, EventArgs e)
  121. {
  122. fm20LoginTitle.Left = this.Left + this.Width / - fm20LoginTitle.Width / ;
  123. fm20LoginTitle.Top = this.Top + SplPnlMain.Panel1.Height - fm20LoginTitle.Height / ;
  124. }
  125.  
  126. private void Fm20Login_Load(object sender, EventArgs e)
  127. {
  128. try
  129. {
  130. LabStsVersion.Text = "Version: " + this.ProductVersion;
  131. TstMILangLL.Checked = (GlbInfo.Language == "LL");
  132. TstMILangLI.Checked = !TstMILangLL.Checked;
  133. PicLogo.Image = Image.FromFile(AppInfo.GetPath(AppInfo.AppPath.Image) + @"\App\LoginLd.png");
  134. //读取上一次记住的用户名
  135. OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  136. TxtUserID.Text = oPIniFile.ReadString("Login", "LastUserID", string.Empty);
  137. SetMainStatus("..");
  138. }
  139. catch (Exception)
  140. {
  141. }
  142. }
  143.  
  144. private void TxtUserCode_TextChanged(object sender, EventArgs e)
  145. {
  146. CmdClearUser.Visible = !(string.IsNullOrEmpty(TxtUserID.Text.Trim()));
  147. }
  148.  
  149. private void TxtUserCode_Enter(object sender, EventArgs e)
  150. {
  151. PicFeedUser.BackgroundImage= Properties.Resources.LoginUserB;
  152. }
  153.  
  154. private void TxtUserCode_Leave(object sender, EventArgs e)
  155. {
  156. PicFeedUser.BackgroundImage = Properties.Resources.LoginUserH;
  157. }
  158.  
  159. private void TxtUserPass_TextChanged(object sender, EventArgs e)
  160. {
  161. CmdClearPwd.Visible = !(string.IsNullOrEmpty(TxtUserPass.Text.Trim()));
  162. }
  163.  
  164. private void TxtUserPass_Enter(object sender, EventArgs e)
  165. {
  166. PicFeedLock.BackgroundImage = Properties.Resources.LoginPwdB;
  167. }
  168.  
  169. private void TxtUserPass_Leave(object sender, EventArgs e)
  170. {
  171. PicFeedLock.BackgroundImage = Properties.Resources.LoginPwdH;
  172. }
  173.  
  174. private void CmdClearUser_Click(object sender, EventArgs e)
  175. {
  176. TxtUserID.Clear();
  177. }
  178.  
  179. private void CmdClearPwd_Click(object sender, EventArgs e)
  180. {
  181. TxtUserPass.Clear();
  182. }
  183. private void SetLanguage(string tagLang)
  184. {
  185. try
  186. {
  187. OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  188. oINI.WriteString("Global", "CurrentLang", tagLang);
  189. TstMILangLL.Checked = (tagLang == "LL");
  190. TstMILangLI.Checked = !TstMILangLL.Checked;
  191. GlbInfo.Language = tagLang;
  192. InitObjectsText(this);
  193. }
  194. catch (Exception)
  195. {
  196. throw;
  197. }
  198. }
  199. private void TstMILangLL_Click(object sender, EventArgs e)
  200. {
  201. SetLanguage("LL");
  202. }
  203.  
  204. private void TstMILangLI_Click(object sender, EventArgs e)
  205. {
  206. SetLanguage("LI");
  207.  
  208. }
  209.  
  210. private void CmdLogin_Click(object sender, EventArgs e)
  211. {
  212. string tmpSts1 = MultiLang.Surface(this, "VeriUser", "正在验证用户...");
  213. SetMainStatus(tmpSts1);
  214.  
  215. try
  216. {
  217. string postUserID = TxtUserID.Text;
  218. string postUserPass = TxtUserPass.Text;
  219. if (string.IsNullOrEmpty(postUserID) || string.IsNullOrEmpty(postUserPass))
  220. {
  221. MyMsg.Information("T.201001/用户名和密码不能为空.");
  222. TxtUserID.Focus();
  223. return;
  224. }
  225. if ((SelAccountNO == "DEMOH") )
  226. {
  227. MyMsg.Warning("T.201002/此帐套尚未开放,请选择其它帐套.");
  228. return;
  229. }
  230.  
  231. if (SelAccountNO == "DEMO")
  232. {
  233. MyMsg.Warning("T.201003/您登录的是演示库,数据可能随时丢失,如需正式作业,请登录NORMAL正式库.");
  234. }
  235. string connStrCurAct = GetConnStrFromCfg(SelAccountNO, "ConnStr");
  236. string connStrExt1 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt1");
  237. string connStrExt2 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt2");
  238. string connStrExt3 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt3");
  239. string connStrExt4 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt4");
  240. string connStrExt5 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt5");
  241. this.Cursor = Cursors.WaitCursor;
  242. #region 用户ERP登录验证部分
  243. DBContext dBContext = new DBContext(connStrCurAct);
  244. if (!dBContext.IsConnected)
  245. {
  246. MyMsg.Error("T.1010/数据库连接已经创建,但无法开启!", dBContext.ConnectErrorMessage);
  247. return;
  248. }
  249.  
  250. postUserPass = OCrypto.AES16Encrypt(postUserPass, DftAESKeyOfDlls);
  251. SqlParameter[] paras = new SqlParameter[]
  252. {
  253. new SqlParameter("@UserID", postUserID),
  254. new SqlParameter("@PasswordHash", postUserPass)
  255. };
  256. string sqlText= "SELECT U.*, D.DeptCode, D.DeptNameLL, D.DeptNameLI FROM SYS_User AS U LEFT OUTER JOIN Base_Department AS D ON U.DeptRKEY = D.DeptRKEY WHERE (U.UserID= @UserID) AND (U.PasswordHash= @PasswordHash)";
  257. DataTable tmpDTUInfo = dBContext.SqlToDT(sqlText, paras);
  258. if (tmpDTUInfo.Rows.Count > )
  259. {
  260. DataRow drUser = tmpDTUInfo.Rows[];
  261. if (!OString.NZ2Bool(drUser["IActived"]))
  262. {
  263. IsLogin = false;
  264. SetMainStatus(MultiLang.Surface(this, "LoginFail1", "登录失败(帐号未激活),请联系管理员!"));
  265. }
  266. else if (OString.NZ2Bool(drUser["ILocked"]))
  267. {
  268. IsLogin = false;
  269. SetMainStatus(MultiLang.Surface(this, "LoginFail2", "登录失败(帐号被锁定),请联系管理员!"));
  270. }
  271. else
  272. {
  273. GlbInfo.User.UserID = OString.NZ2Str(drUser["UserID"]);
  274. GlbInfo.User.UserNameLL = OString.NZ2Str(drUser["UserNameLL"]);
  275. GlbInfo.User.IsAdmin = OString.NZ2Bool(drUser["Hero"]);
  276. GlbInfo.User.RolesUserIDS = OString.NZ2Str(drUser["RolesUserIDS"]);
  277. GlbInfo.User.RightsList.Clear();
  278. IsLogin = true;
  279. }
  280. }
  281. else
  282. {
  283. IsLogin = false;
  284. SetMainStatus(MultiLang.Surface(this, "LoginFail3", "登录失败(帐号不存在),请重新尝试!"));
  285. }
  286.  
  287. if (IsLogin)
  288. {
  289. GlbInfo.ActNO = SelAccountNO;
  290. GlbInfo.ActName = SelAccountName;
  291. GlbInfo.ConnStrCurAct = connStrCurAct;
  292. GlbInfo.ConnStrExt1 = connStrExt1;
  293. GlbInfo.ConnStrExt2 = connStrExt2;
  294. GlbInfo.ConnStrExt3 = connStrExt3;
  295. GlbInfo.ConnStrExt4 = connStrExt4;
  296. GlbInfo.ConnStrExt5 = connStrExt5;
  297. fm20LoginTitle.Close();
  298. if (ChkRemember.Checked)
  299. {
  300. try
  301. {
  302. //记录下登录用户,以便下次不必输入用户名
  303. OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  304. oPIniFile.WriteString("Login", "LastUserID", postUserID);
  305. }
  306. catch (Exception)
  307. {
  308. }
  309. }
  310.  
  311. DialogResult = DialogResult.OK;
  312. }
  313. else
  314. {
  315. TxtUserPass.Text = string.Empty;
  316. TxtUserPass.Focus();
  317. MyMsg.Warning("T.201004/用户名或密码错误,请检查.");
  318. }
  319. #endregion
  320.  
  321. }
  322. catch (Exception ex)
  323. {
  324. SetMainStatus(tmpSts1 + "出现异常!");
  325. MyMsg.Exclamation(ex.Message);
  326. }
  327. finally
  328. {
  329. this.Cursor = Cursors.Default;
  330. }
  331. }
  332.  
  333. /// <summary>
  334. /// 从配置文件中获取指定帐套数据库连接字符串(已加密)
  335. /// </summary>
  336. /// <param name="actNO">帐套代码</param>
  337. /// <param name="tKey">定义的连接串Key</param>
  338. /// <returns></returns>
  339. private string GetConnStrFromCfg(string actNO, string tKey)
  340. {
  341. try
  342. {
  343. StringCollection Idents = new StringCollection();
  344. OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  345. return oINI.ReadString("Account:" + actNO, tKey, string.Empty);
  346. }
  347. catch (Exception ex)
  348. {
  349. MyMsg.Error(ex.Message);
  350. return string.Empty;
  351. }
  352. }
  353.  
  354. private void LabChkRemember_DoubleClick(object sender, EventArgs e)
  355. {
  356. try
  357. {
  358. //记录下登录用户,以便下次不必输入用户名
  359. OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
  360. oPIniFile.WriteString("Login", "LastUserID", string.Empty);
  361. MyMsg.Information("已经清除登录历史,下次登录将不再显示当前帐号名称.");
  362. }
  363. catch (Exception)
  364. {
  365. }
  366. }
  367. }

Login.cs

登录界面是一个起点,涉及到文件操作以及数据库的连接/存取,下次再分解。

C# Winform下一个热插拔的MIS/MRP/ERP框架11(启航)的更多相关文章

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架13(窗体基类)

    作为一个ERP数据处理框架,大部分的开发场景都差不多. 理想中,对于通用数据处理,我的步骤如下: 1.为窗体指定数据来源(数据表/查询等): 2.拖入编辑控件,指定绑定字段: 3.结束. 为此,我设计 ...

  2. C# Winform下一个热插拔的MIS/MRP/ERP框架15(窗体基类场景1)

    最基础的窗体基类其实是通过应用场景反推的结构. 以下是场景一: 单表应用,普通的数据,比如单位/颜色/特殊字典等使用者少的,无需过多控制的可以使用一个数据表格来管理. 和Excel表格差不多,批量修改 ...

  3. C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)

    对于软件来说,启用自动更新是非常必要的. 根据软件的应用场景,我们可以设计不同的更新模型. 目前,IMES框架运行在.Net framework 4.0下面,使用的Win系统版本在Win7,域内管控, ...

  4. C# Winform下一个热插拔的MIS/MRP/ERP框架12(数据处理基类)

    作为ERP等数据应用程序,数据库的处理是重中之重. 在框架中,我封装了一个数据库的基类,在每个模组启动或窗体启动过程中,实例化一个基类即可调用CRUD操作(create 添加read读取 update ...

  5. C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)

    一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  7. C# Winform下一个热插拔的MIS/MRP/ERP框架(多语言方案)

    个别时候,我们需要一种多语种切换方案. 我的方案是这样的: 1.使用文本文本存储多语言元素,应用程序启动时加载到内存表中: 2.应用程序启动时从配置文件加载语种定义: 3.所有窗体继承自一个Base基 ...

  8. C# Winform下一个热插拔的MIS/MRP/ERP框架16(窗体基类场景2)

    如果没有特别需求,和场景1一样只变更表名,主键字段,检测字段等名称,不需要写其它代码了. * 清单列表+单笔编辑/保存,适用于大多数基础资料管理以及简单的单据资料录入(当然,排版是要改一改的): * ...

  9. [C#]Winform下回车或Tab键自动切换下一个控件焦点

    满足用户体验,在数据录入时,能在输入完一个信息后通过回车或Tab键自动的切换到下一个控件(字段). 在界面控件设计时,默认可以通过设置控件的TabIndex来实现.但在布局调整时或者是对输入的内容有选 ...

随机推荐

  1. 处理大数据对象clob数据和blob数据

    直接上下代码: package com.learn.jdbc.chap06; import java.io.File; import java.io.FileInputStream; import j ...

  2. JavaScript高级程序设计学习

    1.变量 变量使用var操作符定义,var message,定义一个message变量,可用来保存任何类型的变量.未经初始化的变量值为undifided: 如果没变量没有被var定义,那么被执行后会成 ...

  3. jenkins 学习记录2

    主题 在之前的学习中(http://www.cnblogs.com/abcwt112/p/6274575.html)我已经学会怎么打包了..这篇文章记录分享我学习如何利用jenkins将打完的包发布到 ...

  4. Eclipse中建立Maven项目后,Java Resources资源文件下没有src/main/java文件夹

    当建立好一个Maven项目后,在Java Resources资源文件夹下没有看到src/main/java文件夹,然后手动去创建Source Folder时,提示该文件已存在,如图: 有一个解决办法: ...

  5. springBean之BeanFactory与ApplicationContext

    一.主要区别: 两者都是通过xml配置文件加载bean,ApplicationContext和BeanFacotry相比,提供了更多的扩展功能,但其主要区别在于后者是延迟加载,如果Bean的某一个属性 ...

  6. Python嵌套、递归、高阶函数

    一.嵌套函数 1.嵌套函数简单的理解可以看作是在函数的内部再定义函数,实现函数的“私有”. 2.特点: <1> 函数内部可以再次定义函数. <2> 只有被调用时才会执行(外部函 ...

  7. Texture Filter

    [Texture Filter] 我们的纹理是要贴到三维图形表面的,而三维图形上的pixel中心和纹理上的texel中心并不一至(pixel不一定对应texture上的采样中心texel),大小也不一 ...

  8. SpringMVC简单的文件上传

    引入依赖包: <!-- 文件上传的依赖 --> <dependency> <groupId>commons-fileupload</groupId> & ...

  9. Leetcode:Longest Substring Without Repeating Characters分析和实现

    题目大意是传入一条字符串,计算出这样的这样一条子字符串,要求子字符串是原字符串的连续的某一段,且子字符串内不包含两个或两个以上的重复字符.求符合上面条件的字符串中最长的那一条的长度. 首先注意到任意一 ...

  10. zend studio在线安装svn的插件

    这个,其实真的很简单 ,但是让我纠结了很久. 安装步骤: 1.确保电脑能够上网: 2.打开zend studio,然后选择help->welcome会弹出一个欢迎页面; 3.等待几秒后可以看到右 ...