zoukankan      html  css  js  c++  java
  • 解析大型.NET ERP系统 界面与逻辑分离

    Windows Forms程序实现界面与逻辑分离的关键是数据绑定技术(Data Binding),这与微软推出的ASP.NET MVC的原理相同,分离业务代码与界面层,提高系统的可维护性。

    数据绑定 Data Binding

    数据绑定技术的主要内容:数据源(Data Source),控件(Control),绑定方式(Binding)。通过绑定控件,将数据源中的属性绑定到界面控件中,并可以实现双向的数据绑定。当界面控件中的值发生改变时,可以通过数据绑定控件,更新控件绑定的对象,当通过代码直接改变对象值后,数据绑定控件可以将值更新到它所绑定的界面控件中。

    ERP系统选择LLBL Gen ORM框架作为数据访问技术基础,数据源为实体类型。主要绑定以下几种类型:

    IEntity  数据库表的实体映射,每个属性。绑定时,控件的类型与实体的属性类型严格匹配与验证。

    /// <summary> The TotLdiscAmt property of the Entity PurchaseOrder<br/>
    /// Mapped on  table field: "PUORDH"."TOT_LDISC_AMT"<br/>
    /// Table field type characteristics (type, precision, scale, length): Decimal, 16, 2, 0<br/>
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false<br/><br/>
    /// ReadOnly: <br/></summary>
    /// <remarks>Mapped on  table field: "PUORDH"."TOT_LDISC_AMT"<br/>
    /// Table field type characteristics (type, precision, scale, length): Decimal, 16, 2, 0<br/>
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
    public virtual System.Decimal  SalesAmount
    {
        get { return (System.Decimal)GetValue((int)PurchaseOrderFieldIndex.TotLdiscAmt, true); }
        set    { SetValue((int)PurchaseOrderFieldIndex.TotLdiscAmt, value); }
    }
    
    /// <summary> The TotAtaxAmt property of the Entity PurchaseOrder<br/>
    /// Mapped on  table field: "PUORDH"."TOT_ATAX_AMT"<br/>
    /// Table field type characteristics (type, precision, scale, length): Decimal, 16, 2, 0<br/>
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false<br/><br/>
    /// ReadOnly: <br/></summary>
    /// <remarks>Mapped on  table field: "PUORDH"."TOT_ATAX_AMT"<br/>
    /// Table field type characteristics (type, precision, scale, length): Decimal, 16, 2, 0<br/>
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
    public virtual System.String CustomerNo
    {
        get { return (System.Decimal)GetValue((int)PurchaseOrderFieldIndex.TotAtaxAmt, true); }
        set    { SetValue((int)PurchaseOrderFieldIndex.TotAtaxAmt, value); }
    }

    上面的代码例子定义了二个属性:数值类型的销售金额,字符串类型的客户编号。在做数据绑定设计时,需要分别选择NumbericEditor和TextEditor。

    控件Control  简单的数据绑定,比如TextEditor,NumbericEditor,CheckedEdidtor只绑定一个属性,复杂的数据定比如Grid绑定一个对象的多个属性,根据实体的属性自动设定绑定控件的属性。

    数据源控件BindingSource  负责将控件的属性和对象的属性关联起来。对象的属性值会被自动传递个控件的属性,而控件的属性值更改后也会直接传回对象的属性(双向绑定)。
    简单绑定绑定  下面的代码的含义是将客户编号绑定到txtCustomerNo控件的Text属性。

    CustomerEntity customer=......
    txtCustomerNo.DataBindings.Add("Text", customer, "CustomerNo");  
     

    复杂数据绑定 下面的代码将客户集合(EntityCollection)绑定到网格控件。

    EntityCollection<CustomerEntity> customers=......
    customerBindingSource.DataSource = customers;
    gridCustomer.SetDataBinding(customerBindingSource, "Customer", true, true);
     

    下拉选择框(Combox)的数据绑定,下面是绑定到枚举类型的例子:

    comboDepartment.InitializeValueFromEnum<CustomerType>();

    代码中将枚举的值反射出来,创建为ValueList绑定到下拉框中。

    业务逻辑 Business Logic

    从ERP的技术层面考虑,ERP包含以下四种逻辑:

    1 自动赋值逻辑。在采购订单输入窗体中,输入供应商编号,自动带入供应商名称,供应商付款货币和付款条款的值到当前采购订单单据中。

    //PurchaseOrderEntity.cs
    private void OnChangeVendorNo(string originalValue)
    {
             if (string.CompareOrdinal(this.VendorNo, originalValue) == 0)
                  return;
    
              IVendorManager vendorMan = ClientProxyFactory.CreateProxyInstance<IVendorManager>();
              VendorEntity vendor = vendorMan.GetValidVendor(Shared.CurrentUserSessionId, this.VendorNo);
    
              this.VendorName = vendor.VendorName.;
              this.PayTerms = vendor.PayTerms;
              this.PayCurrency = vendor.PayCurrency;
    }

    2 计算逻辑。输入单价和数量后,自动计算出物料金额金额,再输入折扣率后,计算出折扣金额和应付款金额。

    //PurchaseOrderEntity.cs
    private void OnChangeQty(decimal? originalValue)
    {
            if (!originalValue.HasValue || this.Qty != originalValue.Value)
            {
                  this.Amount=this.Qty * this.UnitPrice;
             }
    }

    3 数据验证。出仓时,库存余额不能是负数。付款金额必须大于等于订单金额时,订单才能完成付款。

    //Shipment.cs
    public bool ValidateQtyShiped(ShipmentEntity shipment, decimal value)
    {
       IInventoryBalanceManager  balanceManager = CreateProxyInstance<IInventoryBalanceManager>();
       decimal  qtyRemaining =  balanceManager.GetItemBalance(shipment.ItemNo);
       if (qtyRemaining < 0| qtyRemaining<value )
              throw new FieldValidationException("Negative item balance detected");
    
       return true;
    }

    4 业务关联。送货单要依据销售订单的订单数量为依据来送货,采购验货的结果中,合格和不合格数量要等于采购订单要验货的数量。

    //PurchaseInspectionEntity.cs
    private void OnChangeGrnNo(string originalValue)
    {
          if (Shared.StringCompare(this.GrnNo, originalValue) == 0) 
                    return;
    
          IPrefetchPath2 prefetchPath = new PrefetchPath2(EntityType.GrnEntity);
          prefetchPath.Add(GrnEntity.PrefetchPathGrnOrderDetails);
    
          IGrnManager grnManager =CreateProxyInstance<IGrnManager>();
          GrnEntity grn = grnManager.GetGrn(Shared.CurrentUserSessionId, this.GrnNo, prefetchPath);
    
          //待检验数量= 订单数量 - 已检验数量
          this.Qty=grn.QtyOrder -  grn.QtyInspected;
    }
     

    界面设计 Interface Design

    几乎所有的界面绑定业务实体到控件中的方法都一致,参考下面的方法:

    protected override void BindControls(EntityBase2 entity)
    {
           base.BindControls(entity);
           this.purchaseOrderBindingSource.DataSource = entity;
    }

    界面中读取数据的方法LoadData,读取数据后绑定到数据源控件BindingSource控件中。

    //PurchaseOrderEntry.cs 
    protected override EntityBase2 LoadData(Dictionary<string, string> refNo)
    {      
        string orderNo;
        if (refNo.TryGetValue("OrderNo", out orderNo))
        {
              PurchaseOrderEntity result = _purchaseOrderManager.GetPurchaseOrder(orderNo);
              this._purchaseOrder=result;
        }
    
        return _purchaseOrder;
    }
     

    以上是界面层中数据绑定的两个核心方法,读取数据并将数据绑定到界面控件中。注意到方法是通过参数实体EntityBase2操作的,所以它是通用的方法实现,被框架调用实现界面与逻辑分离。

  • 相关阅读:
    java网络爬虫爬虫小栗子
    浮点数精确表示
    使用yum安装CDH Hadoop集群
    判断奇数,java陷阱
    Long型整数,缄默溢出
    java基础知识点
    java常用指令
    Codeforces Round #275 (Div. 2) D
    区间dp的感悟
    Codeforces Round #386 (Div. 2) C D E G
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/4709699.html
Copyright © 2011-2022 走看看