吉日嘎啦通用权限管理系统解读及重构升华--高度封装的编辑窗体

吉日嘎拉,一个专注于通用权限管理系统的开发狂热者,在博客园是一个有争议的人物,不过从其文章数量及内容介绍,专注肯定不是浪得虚名,一个人把东西做的专注,也就意味着更多的投入及考虑,可以作为后来者更多的借鉴。

本人获其友情赠送一套源码,用作深入分析及提炼使用,初一接触,整个体系架构还是比较庞大,如下所示。 

 

本文思路是源自对Winform窗体的分析研究,发现其中不少优点,很多闪亮的地方,结合本人在Winform方面的积累及研究,对即日嘎拉的代码进行进一步的提炼,于是撰写了本文,本文主要介绍继承窗体的封装使用。 

我们先来分析下吉日嘎拉其对窗体的设计代码,一步步进行深入的研究。

首先其也是设计一个窗体基类BaseForm, 其他窗体继承自BaseForm基类,这也是一种常用的设计。

 代码

         ///   <summary>
        
///  加载窗体
        
///   </summary>
         private   void  FormOnLoad()
        {
            
//  多语言国际化加载
             this .Localization( this );
            
//  获得权限
             this .GetPermission();
            
//  设置焦点
             this .ActiveControl  =   this .txtCode;
            
this .txtCode.Focus();
        }
        
#endregion

        
private   void  FrmItemDetailsAdd_Load( object  sender, EventArgs e)
        {
            
if  ( ! this .DesignMode)
            {
                
//  设置鼠标繁忙状态
                 this .Cursor  =  Cursors.WaitCursor;
                
try
                {
                    
this .FormOnLoad();
                }
                
catch  (Exception ex)
                {
                    
this .ProcessException(ex);
                }
                
finally
                {
                    
//  设置鼠标默认状态
                     this .Cursor  =  Cursors.Default;
                }
            }
        }

        
#region  private void SaveEntity(bool close)
        
///   <summary>
        
///  保存
        
///   </summary>
        
///   <param name="close"> 关闭窗体 </param>
         private   void  SaveEntity( bool  close)
        {
            
//  检查输入的有效性
             if  ( this .CheckInput())
            {
                
//  设置鼠标繁忙状态
                 this .Cursor  =  Cursors.WaitCursor;
                
try
                {
                    
if  ( this .SaveEntity())
                    {
                        
if  (close)
                        {
                            
//  关闭窗口
                             this .Close();
                        }
else
                        {
                            
this .ClearScreen();
                        }
                    }
                }
                
catch  (Exception ex)
                {
                    
this .ProcessException(ex);
                }
                
finally
                {
                    
//  设置鼠标默认状态
                     this .Cursor  =  Cursors.Default;
                }
            } 
        }
        
#endregion

        
private   void  btnAdd_Click( object  sender, EventArgs e)
        {
            
this .SaveEntity( false );
        }

        
private   void  btnSave_Click( object  sender, EventArgs e)
        {
            
this .SaveEntity( true );
        }

        
private   void  btnCancel_Click( object  sender, EventArgs e)
        {
            
this .Close();
        }  

 

 

从其中的封装调用我们看到,吉日嘎拉已经把很多变化的代码抽象出来,也不失为一个较好的设计,另外对窗体的输入回车转Tab也做了一个通用的转换,如下所示:

 代码

         private   void  FrmItemDetailsAdd_KeyDown( object  sender, KeyEventArgs e)
        {
            
string  keyCode  =  e.KeyCode.ToString();
            
switch  (keyCode)
            {
                
case   " Enter " :
                
case   " Return " :
                    
if  ( this .ActiveControl  is  TextBox)
                    {
                        
if  ( ! ((TextBox) this .ActiveControl).Multiline)
                        {
                            SendKeys.Send(
" {TAB} " );
                        }
                    }
                    
break ;
            }
            
switch  (e.KeyValue)
            {
                
case   116 :
                    
//  点击了F5按钮
                     this .FormOnLoad();
                    
break ;
            }
        }

 

 

闪亮之处还有很多,本文暂时在此打住,介绍一下其中可以重构更好的地方。

由于吉日嘎拉的窗体设计,对于一般常用到的编辑数据、新增数据窗体,分开了两个不同的窗体进行处理,而且由于BaseForm窗体没有对通用的函数进行进一步的抽象,因此,编辑及新增窗体多了很多重复累赘的代码,其实可以把新增、编辑合并一个窗体,然后根据新增、编辑两种不同的条件进行处理即可。

由于BaseForm一般需要在大多数的窗体中,而新增编辑数据窗体一般较为特殊一点,可以再增加一个基类BaseEditForm,用来做新增编辑窗体的基类,该基类继承自BaseForm类,工程代码如下所示。

 

 其中运行例子的效果如下所示:

 

 

 

 编辑以及新增我们整合在一个窗体中,先看看该基类的设计视图,我们在其中添加了3个按钮(常用的添加、保存、关闭按钮)。

 

窗体的代码我大类采用了可重载的虚函数,留给子类窗体进行实现不同的处理操作,如窗体加载显示操作、显示数据到控件的操作、保存、新增等函数都是需要实现的,而调用逻辑以及一些通用的处理,则在基类BaseEditForm中实现,子类不用重复这些代码,按钮控件(添加、保存、关闭)的事件处理也已经进行了逻辑封装,如下所示。 

 代码

         public   override   void  FormOnLoad()
        {
            
base .FormOnLoad();
            
if  ( ! this .DesignMode)
            {
                
if  ( ! string .IsNullOrEmpty(ID))
                {
                    
this .Text  =   " 编辑  "   +   this .Text;
                    
this .btnAdd.Visible  =   false ; // 如果是编辑,则屏蔽添加按钮
                }
                
else
                {
                    
this .Text  =   " 新建  "   +   this .Text;
                }
                
                DisplayData();
            }
        }

       
///   <summary>
        
///  显示数据到控件上
        
///   </summary>
         public   virtual   void  DisplayData()
        {
        } 
        
        
///   <summary>
        
///  检查输入的有效性
        
///   </summary>
        
///   <returns> 有效 </returns>
         public   virtual   bool  CheckInput()
        {
            
return   true ;
        }
               
        
///   <summary>
        
///  清除屏幕
        
///   </summary>
         public   virtual   void  ClearScreen()
        {
            
this .ID  =   "" ; /// /需要设置为空,表示新增
            ClearControlValue( this );
            
this .FormOnLoad();
        }
       
        
///   <summary>
        
///  保存数据(新增和编辑的保存)
        
///   </summary>
         public   virtual   bool  SaveEntity()
        {
            
bool  result  =   false ;
            
if ( ! string .IsNullOrEmpty(ID))
            {
                
// 编辑的保存
                result  =  SaveUpdated();
            }
            
else
            {
                
// 新增的保存
                result  =  SaveAddNew();
            }

            
return  result;
        }

        
///   <summary>
        
///  更新已有的数据
        
///   </summary>
        
///   <returns></returns>
         public   virtual   bool  SaveUpdated()
        {
            
return   true ;
        }

        
///   <summary>
        
///  保存新增的数据
        
///   </summary>
        
///   <returns></returns>
         public   virtual   bool  SaveAddNew()
        {
            
return   true ;
        }

        
///   <summary>
        
///  保存
        
///   </summary>
        
///   <param name="close"> 关闭窗体 </param>
         private   void  SaveEntity( bool  close)
        {
            
//  检查输入的有效性
             if  ( this .CheckInput())
            {
                
//  设置鼠标繁忙状态
                 this .Cursor  =  Cursors.WaitCursor;
                
try
                {
                    
if  ( this .SaveEntity())
                    {
                        MessageUtil.ShowTips(
" 保存成功 " );
                        
if  (close)
                        {
                            
this .DialogResult  =  DialogResult.OK;
                            
this .Close();
                        }
                        
else
                        {
                            
this .ClearScreen();
                        }                           
                    }
                }
                
catch  (Exception ex)
                {
                    
this .ProcessException(ex);
                }
                
finally
                {
                    
//  设置鼠标默认状态
                     this .Cursor  =  Cursors.Default;
                }
            }
        }

        
private   void  btnAdd_Click( object  sender, EventArgs e)
        {
            
this .SaveEntity( false );
        }

        
private   void  btnOK_Click( object  sender, EventArgs e)
        {
            
this .SaveEntity( true );
        }

        
private   void  btnCancel_Click( object  sender, EventArgs e)
        {
            
this .DialogResult  =  DialogResult.Cancel;
            
this .Close();
        }

 

 

其中值得介绍的是,窗体的控件数据清空在基类窗体中通过遍历实现了通用的数据清空操作,该部分代码引用了“潇湘隐者的博客(http://www.cnblogs.com/kerrycode/archive/2010/02/05/1664267.html),对此感谢。

另外,基类窗体还实现了Tab键的转换,这个思路来源于即日嘎拉的代码,但由于是基类实现,有些不同,他的放在每个具体的子类中,因此通用性有些限制。

我们重载了ProcessCmdKey(ref Message msg, Keys keyData) 函数后,就可以实现统一的回车键转换了。

代码
         protected   override   bool  ProcessCmdKey( ref  Message msg, Keys keyData)
        {       
            
if  (keyData  ==  Keys.F5)
            {
                
this .FormOnLoad();
            }

            
if  (( ! (ActiveControl  is  Button))  &&
                (keyData 
==  Keys.Up  ||  keyData  ==  Keys.Down  ||  keyData  ==  Keys.Enter))
            {
                
if  (keyData  ==  Keys.Enter)
                {
                    System.Windows.Forms.SendKeys.Send(
" {TAB} " );
                    
return   true ;
                }
                
if  (keyData  ==  Keys.Down)
                {
                    System.Windows.Forms.SendKeys.Send(
" {TAB} " );
                }
                
else
                {
                    SendKeys.Send(
" +{Tab} " );
                }

                
return   true ;
            }
            
else
            {
                
return   base .ProcessCmdKey( ref  msg, keyData);
            }
        }

 

 

 最后,我们看看具体的子类窗体,看新增编辑界面需要实现的代码,如下所示,其中大部分是原子级别的操作,逻辑操作已经在基类中实现了哦:

 代码

     public   partial   class  FrmEditCustomer : BaseUI.BaseEditForm
    {
        
public  FrmEditCustomer()
        {
            InitializeComponent();
        }

        
///   <summary>
        
///  实现控件输入检查的函数
        
///   </summary>
        
///   <returns></returns>
         public   override   bool  CheckInput()
        {
            
bool  result  =   true ;

            
#region  输入验证
            
if  ( this .txtName.Text.Length  ==   0 )
            {
                MessageUtil.ShowTips(
" 宾客名称不能为空 " );
                
this .txtName.Focus();
                result 
=   false ;
            }
            
else   if  ( this .txtIDNumber.Text.Length  ==   0 )
            {
                MessageUtil.ShowTips(
" 证件号码不能为空 " );
                
this .txtIDNumber.Focus();
                result 
=   false ;
            }

            
#endregion

            
return  result;
        }

        
///   <summary>
        
///  编辑或者保存状态下取值函数
        
///   </summary>
        
///   <param name="info"></param>
         private   void  SetInfo(CustomerInfo info)
        {
            info.Address 
=  txtAddress.Text;
            info.CompanyName 
=  txtCompany.Text;
            info.IDCarType 
=  cmbIDCarType.Text;
            info.Name 
=  txtName.Text;
            info.Note 
=  txtNote.Text;
            info.IDNumber 
=  txtIDNumber.Text;
            info.Telephone 
=  txtTelephone.Text;
            info.Source 
=  cmbSource.Text;
            info.CustomerType 
=  cmbType.Text;
            info.Sex 
=  cmbSex.Text;
        }

        
///   <summary>
        
///  数据字典加载
        
///   </summary>
         private   void  InitDictItem()
        {
            
this .cmbSource.Items.Clear();
            
this .cmbSource.Items.AddRange(DictItemUtil.GetCustomerSource());

            
this .cmbType.Items.Clear();
            
this .cmbType.Items.AddRange(DictItemUtil.GetCustomerType());

            
this .cmbIDCarType.Items.Clear();
            
this .cmbIDCarType.Items.AddRange(DictItemUtil.GetIDCarType());
        }

        
///   <summary>
        
///  数据显示的函数
        
///   </summary>
         public   override   void  DisplayData()
        {
            
// 数据字典加载(公用)
            InitDictItem();

            
if  ( ! string .IsNullOrEmpty(ID))
            {
                
// 编辑状态下的数据显示
                CustomerInfo info  =  BLLFactory < Customer > .Instance.FindByID(ID);
                
if  (info  !=   null )
                {
                    
#region  显示客户信息
                    txtAddress.Text 
=  info.Address;
                    txtCompany.Text 
=  info.CompanyName;
                    txtName.Text 
=  info.Name;
                    txtNote.Text 
=  info.Note;
                    txtIDNumber.Text 
=  info.IDNumber;
                    txtTelephone.Text 
=  info.Telephone;
                    cmbSource.Text 
=  info.Source;
                    cmbType.Text 
=  info.CustomerType;
                    cmbSex.Text 
=  info.Sex;
                    cmbIDCarType.Text 
=  info.IDCarType;
                    lblCreateDate.Text 
=  info.RegistrationDate.ToString();

                    
#endregion
                }
            }
            
else
            {
                
// 新增状态的数据显示
                lblCreateDate.Text  =  DateTime.Now.ToString();
            }
        }

        
///   <summary>
        
///  新增状态下的数据保存
        
///   </summary>
        
///   <returns></returns>
         public   override   bool  SaveAddNew()
        {
            CustomerInfo info 
=   new  CustomerInfo();
            SetInfo(info);
            info.RegistrationDate 
=  DateTime.Now;
            
bool  succeed  =  BLLFactory < Customer > .Instance.Insert(info);
            
return  succeed;
        }

        
///   <summary>
        
///  编辑状态下的数据保存
        
///   </summary>
        
///   <returns></returns>
         public   override   bool  SaveUpdated()
        {
            CustomerInfo info 
=  BLLFactory < Customer > .Instance.FindByID(ID);
            
if  (info  !=   null )
            {
                SetInfo(info);
                
bool  succeed  =  BLLFactory < Customer > .Instance.Update(info, info.ID.ToString());
                
return  succeed;
            }
            
return   false ;
        }
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值