基于Cef内核的多店铺登录器(含源码)
公司是做电商的,在速卖通平台上开了若干店铺,每天都需要登录店铺打理,如:发货提交、获取运单号等。多个店铺的情况下,同时使用浏览器就会非常繁琐,如:要记住帐户名和密码,还要在不同店铺间切换。如果能够制作一个多店铺登录器,就可以解决上述问题。好了,背景描述完毕,下面开干
-----------------------------------------------------------------------------
博客搬家啦,新地址:
-----------------------------------------------------------------------------
首先想到的是微信原生的WebBrowser组件,第一轮开发结束测试,发现帐户间会互相干扰,就是店铺A登录成功后,再登录店铺B的话,店铺A的数据会被冲掉。此控件直接pass,继续新尝试
后来又找到一个将WebBrowser二次封装的控件,好像不能解决弹出页面,第二轮也宣告失败,继续尝试
第三轮,尝试使用Cef控件,这是基于Google浏览器的内核,开发完成测试,发现基本能满足所要求的功能
先来看看界面是啥样子?
代码本身并不多,关键的技术点有以下
1, Winform应用启动时,args参数使用
2, 双击树控件结点时,判断此结点的地址是否已打开,若未打开,则再启动一个exe程序
3, 登录帐号和页面大小和位置能够随时记录,保证下次登录时,和上次一样
下面逐个技术点说明
1, args参数
解析代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | //3,打开应用程序.注:根据外部传入参数.默认登录器 //登录器格式:功能类型 内外网 登录用户 选中店铺 if (args != null && args.Length > 0) { //FormUIHelper.ShowMessage("args参数:" + JsonHelper.GetJsonByObject(args)); if (args.Length >= 1) { //默认登录器 string actionTypeTemp = args[0]; int logonType = StringHelper.ObjectToInt(actionTypeTemp, 1); BaseHelper.ActionType = logonType; } if (args.Length >= 2) { List< string > listP = new List< string >() { "In" , "Out" }; string logonType = args[1]; if (!listP.Contains(logonType)) { logonType = "Out" ; } BaseHelper.LogonType = EnumHelper.ToEnumObject<MetaCodeEnum.LogonType>(logonType); } if (args.Length >= 3) { CurrentUserInfo.UserCode = args[2]; CurrentUserInfo.UserName = args[2]; CurrentUserInfo.UserInfo = new UserInfo() { UserCode = CurrentUserInfo.UserCode, UserName = CurrentUserInfo.UserName }; } if (args.Length >= 4) { CurrentAppInfo.ShopCode = args[3]; } if (args.Length >= 5) { CurrentAppInfo.ItemSnapUrl = args[4]; } } else { //默认登录器 BaseHelper.ActionType = 1; } |
调用代码如下
1 2 3 4 5 | //若没有找到,则直接打开exe文件 string message = string .Empty; string fileName = CurrentAppInfo.AppPath + @"\" + CurrentAppInfo.AppName; string args = BaseHelper.ActionType + " " + BaseHelper.LogonType.ToString() + " " + CurrentUserInfo.UserCode + " " + shopCode; SystemHelper.OpenFile(fileName, args); |
2, 启动exe程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | foreach (TreeNode node in treeShop.Nodes) { foreach (TreeNode cilNode in node.Nodes) { if (cilNode.Text != shopName) { string title = shopName + " " + cilNode.Text; IntPtr handleID1 = SystemHelper.FindWindow( null , title); if (handleID1.ToInt64() > 0) { //窗体最小化 SystemHelper.ShowWindow(handleID1, 2); } } } } //再判断页面标题是此标题的页面是否已经打开 IntPtr handleID = SystemHelper.FindWindow( null , formTitle); if (handleID.ToInt64() > 0) { //说明已经打开 SystemHelper.SwitchToThisWindow(handleID, true ); } else { //若没有找到,则直接打开exe文件 string message = string .Empty; string fileName = CurrentAppInfo.AppPath + @"\" + CurrentAppInfo.AppName; string args = BaseHelper.ActionType + " " + BaseHelper.LogonType.ToString() + " " + CurrentUserInfo.UserCode + " " + shopCode; SystemHelper.OpenFile(fileName, args); } |
3, 记录用户配置项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #region (OK)窗体Resize,位置保存相关代码 private void FormLogonerMain_ResizeBegin( object sender, EventArgs e) { //窗体Resize开始,拖动调整窗体大小时触发 resizing = true ; } private void FormLogonerMain_ResizeEnd( object sender, EventArgs e) { //窗体Resize结束,保存最新的窗体大小和位置 this .lonService.SetUserSettingsValue( "x" , this .Location.X.ToString()); this .lonService.SetUserSettingsValue( "y" , this .Location.Y.ToString()); this .lonService.SetUserSettingsValue( "Width" , this .Size.Width.ToString()); this .lonService.SetUserSettingsValue( "Height" , this .Size.Height.ToString()); resizing = false ; } private void FormLogonerMain_SizeChanged( object sender, EventArgs e) { //窗体状态变化处理 if (WindowState == FormWindowState.Maximized) { this .lonService.SetUserSettingsValue( "Maximize" , "true" ); } else if (WindowState == FormWindowState.Normal) { this .lonService.SetUserSettingsValue( "Maximize" , "false" ); if (resizing == false ) { if ( this .lonService.CheckUserConfigValue()) { int width = int .Parse( this .lonService.GetUserSettingsValue( "Width" )); int height = int .Parse( this .lonService.GetUserSettingsValue( "Height" )); int x = int .Parse( this .lonService.GetUserSettingsValue( "x" )); int y = int .Parse( this .lonService.GetUserSettingsValue( "y" )); this .Location = new Point(x, y); this .Size = new Size(width, height); } else { resizing = true ; string swidthRateTemp = ConfigHelper.GetAppSettingsValue( "WidthRate" ); string sheightRateTemp = ConfigHelper.GetAppSettingsValue( "HeightRate" ); double douWidthRate = StringHelper.ObjectToDouble(swidthRateTemp, 0.95); double douHeightRate = StringHelper.ObjectToDouble(sheightRateTemp, 0.95); FormUIHelper.SetFormSizeAndLocationCenter( this , douWidthRate, douHeightRate); this .lonService.SetUserSettingsValue( "x" , this .Location.X.ToString()); this .lonService.SetUserSettingsValue( "y" , this .Location.Y.ToString()); this .lonService.SetUserSettingsValue( "Width" , this .Size.Width.ToString()); this .lonService.SetUserSettingsValue( "Height" , this .Size.Height.ToString()); resizing = false ; } } } } private void FormLogonerMain_Activated( object sender, EventArgs e) { //在窗体激活时,将蓝色的当前店铺置为选中店铺 foreach (TreeNode node in treeShop.Nodes) { foreach (TreeNode cilNode in node.Nodes) { if (cilNode.ForeColor == Color.Blue) { treeShop.SelectedNode = cilNode; } } } } #endregion |
核心代码就是这些,程序本身已经封装成一个产品,使用方法参考下面的地址,而且永久免费!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述