zoukankan      html  css  js  c++  java
  • 总结的一些经验

    从开发的软件《备件仓库管理系统》

    本人做Winform开发多年,孜孜不倦,略有小成,其中收集或者自己开发一些常用的东西,基本上在各个项目都能用到的一些开发经验及知识积累,现逐步介绍一些,以飨读者,共同进步。

     1、窗口【×】关闭按钮变为最小化,并在托盘提示信息

    一般有些管理系统,为了防止客户随意关闭程序或者基于其他原因,一般会把 窗口【×】关闭按钮变为最小化,如大家熟悉的飞信、MSN等等,但是有些不是很熟悉的客户,最小化到托盘的时候,却不知道程序到了那里去了,因此,最小化的时候,伴随一个气泡提示信息,显得有一定的必要,如下截图所示。

     

    首先在主窗体的设计界面中添加一个NotifyIcon控件,然后实现相关的代码即可。 

    下面列出一些关键的代码出来,大家看了应该就知道如何实现了

             private void notifyMenu_Show_Click(object sender, EventArgs e)
            {
                
    if (this.WindowState == FormWindowState.Minimized)
                {
                    
    this.WindowState = FormWindowState.Maximized;
                    
    this.Show();
                    
    this.BringToFront();
                    
    this.Activate();
                    
    this.Focus();
                }
                
    else
                {
                    
    this.WindowState = FormWindowState.Minimized;
                    
    this.Hide();
                }
            }

           
    private void notifyMenu_Exit_Click(object sender, EventArgs e)
            {
                
    try
                {
                    
    this.ShowInTaskbar = false;
                    Portal.gc.Quit();
                }
                
    catch
                {
                    
    // Nothing to do.
                }
            }

            
    private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
            {
                notifyMenu_Show_Click(sender, e);
            }

            
    private void MainForm_MaximizedBoundsChanged(object sender, EventArgs e)
            {
                
    this.Hide();
            }

            
    /// <summary>
            
    /// 缩小到托盘中,不退出
            
    /// </summary>
            private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
            {

                
    //如果我们操作【×】按钮,那么不关闭程序而是缩小化到托盘,并提示用户.
                if (this.WindowState != FormWindowState.Minimized)
                {
                    e.Cancel 
    = true;//不关闭程序

                    
    //最小化到托盘的时候显示图标提示信息,提示用户并未关闭程序
                    this.WindowState = FormWindowState.Minimized;
                    notifyIcon1.ShowBalloonTip(
    3000"程序最小化提示",
                         
    "图标已经缩小到托盘,打开窗口请双击图标即可。",
                         ToolTipIcon.Info);
                }
            }

            
    private void MainForm_Move(object sender, EventArgs e)
            {
                
    if (this == null)
                {
                    
    return;
                }

                
    //最小化到托盘的时候显示图标提示信息
                if (this.WindowState == FormWindowState.Minimized)
                {
                    
    this.Hide();
                    notifyIcon1.ShowBalloonTip(
    3000"程序最小化提示",
                        
    "图标已经缩小到托盘,打开窗口请双击图标即可。",
                        ToolTipIcon.Info);
                }
            }
     2、只允许允许一个程序实例,即使是通过虚拟桌面方式连接过来的,也是只允许一个人运行。

     这个已经封装好代码了,只需要在Main函数里面调用一下函数即可,允许多个实例会出现下面的对话框提示信息,提示不允许多实例运行,如下所示:

     

    代码如下所示。

            /// <summary>
            
    /// 应用程序的主入口点。
            
    /// </summary>
            [STAThread]
            
    private static void Main()
            {
                GlobalMutex();

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(
    false);

                
    //******启动代码**********
            }

            
    private static Mutex mutex = null;
            
    private static void GlobalMutex()
            {
                
    // 是否第一次创建mutex
                bool newMutexCreated = false;
                
    string mutexName = "Global\\" + "WareHouseMis";//系统名称,Global为全局,表示即使通过通过虚拟桌面连接过来,也只是允许运行一次
                
    try
                {
                    mutex 
    = new Mutex(false, mutexName, out newMutexCreated);
                }
                
    catch (Exception ex)
                {
                    Console.Write(ex.Message);
                    System.Threading.Thread.Sleep(
    1000);
                    Environment.Exit(
    1);
                }

                
    // 第一次创建mutex
                if (newMutexCreated)
                {
                    Console.WriteLine(
    "程序已启动");
                    
    //todo:此处为要执行的任务
                }
                
    else
                {
                    MessageUtil.ShowTips(
    "另一个窗口已在运行,不能重复运行。");
                    System.Threading.Thread.Sleep(
    1000);
                    Environment.Exit(
    1);//退出程序
                }

            } 

    3、使用NotifyWindow给用户提示信息

     可以通过NotifyWindow类(最后附件中有),做一些信息的提示,方便用户了解一些重要信息的提示,界面较为友好,如下所示:

     

     提示信息的代码使用如下:

            /// <summary>
            
    /// 弹出提示消息窗口
            
    /// </summary>
            public void Notify(string caption, string content)
            {
                Notify(caption, content, 
    4002005000);
            }

            
    /// <summary>
            
    /// 弹出提示消息窗口
            
    /// </summary>
            public void Notify(string caption, string content, int width, int height, int waitTime)
            {
                NotifyWindow notifyWindow 
    = new NotifyWindow(caption, content);
                notifyWindow.TitleClicked 
    += new System.EventHandler(notifyWindowClick);
                notifyWindow.TextClicked 
    += new EventHandler(notifyWindowClick);
                notifyWindow.SetDimensions(width, height);
                notifyWindow.WaitTime 
    = waitTime;
                notifyWindow.Notify();
            }

            
    private void notifyWindowClick(object sender, EventArgs e)
            {
                
    //SystemMessageInfo info = BLLFactory<SystemMessage>.Instance.FindLast();
                
    //if (info != null)
                
    //{
                
    //    //FrmEditMessage dlg = new FrmEditMessage();
                
    //    //dlg.ID = info.ID;
                
    //    //dlg.ShowDialog();
                
    //}
            } 

    4、使用SearchCondion控件,简化查询条件的转化

    不管在Winform或者在WebForm中,查询构造条件总是非常繁琐的事情,使用该控件能有效简化代码,提高操作的准确及方便行,这个控件我完成了几年了,一直伴随我处理各种查询操作。

            private string GetConditionSql()
            {
                SearchCondition condition 
    = new SearchCondition();
                condition.AddCondition(
    "ItemName"this.txtName.Text, SqlOperator.Like)
                    .AddCondition(
    "ItemBigType"this.txtBigType.Text, SqlOperator.Like)
                    .AddCondition(
    "ItemType"this.txtItemType.Text, SqlOperator.Like)
                    .AddCondition(
    "Specification"this.cmbSpecNumber.Text, SqlOperator.Like)
                    .AddCondition(
    "MapNo"this.txtMapNo.Text, SqlOperator.Like)
                    .AddCondition(
    "Material"this.txtMaterial.Text, SqlOperator.Like)
                    .AddCondition(
    "Source"this.txtSource.Text, SqlOperator.Like)
                    .AddCondition(
    "Note"this.txtNote.Text, SqlOperator.Like)
                    .AddCondition(
    "Manufacture"this.txtManufacture.Text, SqlOperator.Like)
                    .AddCondition(
    "ItemNo"this.txtItemNo.Text, SqlOperator.LikeStartAt);
                
    string where = condition.BuildConditionSql().Replace("Where""");

                
    return where;
            } 

    可以构造条件后,传入查询函数,实现数据的查询。

                string where = GetConditionSql();
                List
    <ItemDetailInfo> list = BLLFactory<ItemDetail>.Instance.Find(wherethis.winGridViewPager1.PagerInfo);
                
    this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<ItemDetailInfo>(list);
                this.winGridViewPager1.PrintTitle = Portal.gc.gAppUnit + " -- " + "备件信息报表"; 


    最后呈上代码用到的一些类库及控件:https://files.cnblogs.com/wuhuacong/WinformTips.rar   

    最近做了一个备件仓库管理软件,虽然只是一个不太复杂的仓库管理业务的软件,附带产出一些相关的报表,而且有之前做过的送水管理系统、酒店管理系统等软件的基础及技术储备,不过做起来发现还是有很多细节及新的东西,在客户不断提出修改意见以及改进建议的同时,逐步吸收优化新的知识,现大概总结一些相关的开发心得,以飨读者。

    首先来看看整个软件的主体界面,如下所示,软件的功能主要集备件信息管理、备件入库、备件出库、库存查询、库房管理、业务报表、权限管理、数据字典管理、备件及库存导入等功能于一体。

    鼠标单击可查看大图

     
    现大致就主体界面介绍一些相关的知识:

    1、使用OutLook样式的工具栏,提高界面的美观及易用性,这个在我的早期文章中已经有介绍,该控件集成美观的图标,可能很好提高界面的友好性及可操作性,可以令界面增色不少,详细请查看《WinForm界面开发之“OutLookBar”工具条》 在此不再赘述,只是介绍下并略为带过即可。

     

    2、使用“WeifenLuo.WinFormsUI.Docking”控件来设计多文档界面效果,可以方便多个界面进行操作,这个控件也有相关的文章进行介绍使用了,请参考《WinForm界面开发之布局控件"WeifenLuo.WinFormsUI.Docking"的使用》 和《再谈布局控件"WeifenLuo.WinFormsUI.Docking"的使用--如何控制自动停靠窗口的大小》。

     

    3、 尽可能使用已经在共享软件中广泛性使用我自己的分页控件,该分页控件集成了数据分页、内容提示、数据打印、数据导出、表头中文转义等很多功能,由于集成性很好,省却很多功夫,专注客户的业务及变化即可,否则一项表头的中文转换就够呛,还不说数据的分页,由于整合性、一致性、稳定性等特点,客户使用感觉比较好。最新的版本整合了优秀的Aspose.Cell控件来进行Excel数据的导出,速度非常快,而且默认表头冻结,非常方便。

     

    4、 使用Apose.Cell控件的强大功能,实现自定义模板报表的定制导出。

    使用普通的二维表,虽然能满足大多数的情况,不过在一般的业务中,自定义模板的报表根据贴近实际,符合客户的要求,虽然自定义模板的报表,比普通的二维报表复杂一些,不过利用Apose.Cell控件,并在预设模板中预设变量,可以生成很复杂的报表。详细历程可以参考我介绍Apose.Cell控件的使用文章,《使用Aspose.Cell控件实现Excel高难度报表的生成(一)》、《使用Aspose.Cell控件实现Excel高难度报表的生成(二)》。利用Apose.Cell可以生成下面几类自定义模板的报表:

      
     其他设计模板如下所示:

     
    实际生成的报表如下所示:

     

    5、利用现成独立的数据字典模块代码。由于一般复杂一点的系统,都需要有数据字典的模块,由于我在较早已经在这块已经做了一些开发,因此直接拿过来使用即可,该数据字典模块功能相对比较独立,因此是一个非常使用的模块,数据通过字典排序可以实现合理的排序,支持无限多级字典分类。

     

     实际使用的时候,也是非常方便,首先我们封装一下获取字典项目的方法如下所示:

             /// <summary>

            /// 根据字典类型获取对应的CListItem集合
            
    /// </summary>
            
    /// <param name="dictTypeName"></param>
            
    /// <returns></returns>
            public static CListItem[] GetDictByDictType(string dictTypeName)
            {
                List
    <CListItem> itemList = new List<CListItem>();
                Dictionary
    <stringstring> dict = BLLFactory<DictData>.Instance.GetDictByDictType(dictTypeName);
                
    foreach (string key in dict.Keys)
                {
                    itemList.Add(
    new CListItem(key, dict[key]));
                }
                
    return itemList.ToArray();
            }

     然后再窗体初始化的时候,添加字典的初始化代码即可,如下所示:

            private void InitDictItem()
            {
                
    this.txtManufacture.Items.Clear();
                
    this.txtManufacture.Items.AddRange(DictItemUtil.GetDictByDictType("供货商"));

                
    this.txtBigType.Items.Clear();
                
    this.txtBigType.Items.AddRange(DictItemUtil.GetDictByDictType("备件属类"));

                
    this.txtItemType.Items.Clear();
                
    this.txtItemType.Items.AddRange(DictItemUtil.GetDictByDictType("备件类别"));

                
    this.txtUnit.Items.Clear();
                
    this.txtUnit.Items.AddRange(DictItemUtil.GetDictByDictType("单位"));

                
    this.txtSource.Items.Clear();
                
    this.txtSource.Items.AddRange(DictItemUtil.GetDictByDictType("来源"));

                
    this.txtUsagePos.Items.Clear();
                
    this.txtUsagePos.Items.AddRange(DictItemUtil.GetDictByDictType("使用位置"));
                
    this.txtUsagePos.SelectedIndex = 0;

                
    this.txtBelongDept.Items.Clear();
                
    this.txtBelongDept.Items.AddRange(DictItemUtil.GetDictByDictType("部门"));

                
    this.txtBelongWareHouse.Items.Clear();
                
    this.txtBelongWareHouse.Items.AddRange(Portal.gc.ManagedWareHouse.ToArray());
                
    this.txtBelongWareHouse.SelectedIndex = 0;
           } 

    通过数据字典大类无限级分类以及对字典内容的管理,基本上可以满足绝大多数的需要。

    6、使用独立又具整合性的权限管理系统,既相互独立,有相互整合,方便重用,又不需重新开发,非常方便、更提高效率。 由于权限系统精简而又能满足日常绝大多数的需要,不会复杂的难于管理,而且也是基于角色的授权访问机制(RBAC),最重要是非常适合软件的整合使用。

     


    用户角色功能维护界面如下:


    编辑角色对应的权限界面如下:

    如果我们在开发的系统中要集成现有的权限系统,操作代码如下所示:

            /// <summary>
            
    /// 从数据库中列出相关用户
            
    /// </summary>
            private void InitLoginName()
            {
                User userBLL 
    = new User();
                List
    <UserInfo> userList = userBLL.GetAll();
                
    this.cmbzhanhao.Items.Clear();
                
    foreach (UserInfo info in userList)
                {
                    
    this.cmbzhanhao.Items.Add(info.Name);
                }
            } 


    登录的时候,只需要把该客户能操作的功能点放到内存列表中,如下所示:

                   string loginName = this.cmbzhanhao.Text.Trim();
                    User userBLL 
    = new User();
                    
    string identity = userBLL.VerifyUser(loginName, this.tbPass.Text, Guid.NewGuid().ToString());
                    
    if (!string.IsNullOrEmpty(identity))
                    {
                        UserInfo info 
    = userBLL.GetUserByName(loginName);

                        
    #region 获取用户的功能列表

                        Function functionBLL 
    = new Function();
                        List
    <FunctionInfo> list = functionBLL.GetFunctionsByUser(info.ID, "WareMis");
                        
    if (list != null && list.Count > 0)
                        {
                            
    foreach (FunctionInfo functionInfo in list)
                            {
                                
    if (!Portal.gc.FunctionDict.ContainsKey(functionInfo.ControlID))
                                {
                                    Portal.gc.FunctionDict.Add(functionInfo.ControlID, functionInfo);
                                }
                            }
                        }

                        
    #endregion
                   } 


     用户对某个功能点授权判断,只需要判断某功能点是否在已有集合中即可,如下所示:

             /// <summary>

            /// 根据权限屏蔽功能
            
    /// </summary>
            private void InitAuthorizedUI()
            {
                
    this.tool_Report.Enabled = Portal.gc.HasFunction("Report");
                
    this.tool_Dict.Enabled= Portal.gc.HasFunction("Dictionary");
                
    this.tool_ItemDetail.Enabled = Portal.gc.HasFunction("ItemDetail");
                
    this.tool_Purchase.Enabled = Portal.gc.HasFunction("Purchase");
                
    this.tool_StockSearch.Enabled = Portal.gc.HasFunction("StockSearch");
                
    this.tool_TakeOut.Enabled = Portal.gc.HasFunction("TakeOut");

                
    this.menu_WareHouse.Enabled = Portal.gc.HasFunction("WareHouse");
                
    this.menu_Dictionary.Enabled = Portal.gc.HasFunction("Dictionary");
                
    this.menu_run_systemLog.Enabled = Portal.gc.HasFunction("LoginLog");
                
    this.menu_Parameters.Enabled = Portal.gc.HasFunction("Parameters");
                
    this.menu_MonthlyStatistic.Enabled = Portal.gc.HasFunction("MonthlyStatistic");
                
    this.menu_AnnualStatistic.Enabled = Portal.gc.HasFunction("AnnualStatistic");
                
    this.menu_ClearAll.Enabled = Portal.gc.HasFunction("ClearAllData");
                
    this.menu_ImportItemDetail.Enabled = Portal.gc.HasFunction("ImportItemDetail");
            }

    因此,文章到这里先小结一下,就是利用现有成熟、稳定、集成性好的控件或者模块,或者利用合适易用的控件,既能事半功倍的完成任务,又能快速响应客户的需求变化 ,还能在界面整体上给客户留下好的印象,一举三得,何乐不为? 欢迎与大家一起探讨Winform开发的点点滴滴或者相互合作交流。 

    主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
        
      转载请注明出处:
    撰写人:伍华聪  http:
    //www.iqidi.com 
  • 相关阅读:
    设计师用的几个网站
    微信小程序开发框架
    数据模型
    数据库系统
    大话设计模式读书笔记(一)
    关于数据统计时的效率
    orcale同一条语句运行速度差异问题
    使用plspl创建orcale作业
    正则表达式(一)
    oracle游标小试
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2013160.html
Copyright © 2011-2022 走看看