EPR类企业管理系统

在我们现有系统基础上或全新开发,提供定制服务
为您的企业高效快速实施ERP,WMS,MES,CRM管理系统
全面管控物料仓库、销售业务、采购业务、仓库业务
生产过程、质量检验、组织架构、业务报表


定制
QQ:460-3528

开发
QQ群:3360-90194

源码
微信:136-3650-3721

如何:为查找列表视图实现级联筛选

大多数应用程序都有详细信息视图,其中包含需要过滤的查找属性编辑器。通常,应该使这些编辑器的“列表视图”数据源依赖于位于同一“详细信息视图”中的其他“属性编辑器”的值。为此,eXpressApp框架提供了DataSourcePropertyAttributeDataSourceCriteriaAttribute。本主题演示如何在代码中使用这两个属性以及如何使用应用程序模型。在这些示例中,Order,Product和Accessory类将以不同的方式实现。

提示

可在http://www.devexpress.com/example=E218的DevExpress代码示例数据库中找到完整的示例项目。

初步实施

最初,订单包括产品和配件。此外,每个配件都与特定产品相关。因此,产品对象和附件对象之间存在一对多关系。以下代码显示了如何实现这些类:

using System.ComponentModel;
using DevExpress.Data.Filtering;
//...
[DefaultClassOptions]
public class Order : BaseObject {
   public Order(Session session) : base(session) { }
   private Product fProduct;
   public Product Product {
      get {
         return fProduct;
      }
      set {
         SetPropertyValue(nameof(Product), ref fProduct, value);
      }
   }
   private Accessory fAccessory;
   public Accessory Accessory {
      get {
         return fAccessory;
      }
      set {
         SetPropertyValue(nameof(Accessory), ref fAccessory, value);
      }
   }
}
public class Product : BaseObject {
   public Product(Session session) : base(session) { }
   private String fProductName;
   public String ProductName {
      get { 
         return fProductName;
      }
      set {
         SetPropertyValue(nameof(ProductName), ref fProductName, value);
      }
   }
   [Association("P-To-C")]
   public XPCollection<Accessory> Accessories {
      get { return GetCollection<Accessory>(nameof(Accessories)); }
   }
}
public class Accessory : BaseObject {
   public Accessory(Session session) : base(session) { }
   private String fAccessoryName;
   public String AccessoryName {
      get { 
         return fAccessoryName; 
      }
      set {
         SetPropertyValue(nameof(AccessoryName), ref fAccessoryName, value);
      }
   }
   private bool fIsGlobal;
   public bool IsGlobal {
      get {
         return fIsGlobal;
      }
      set {
         SetPropertyValue(nameof(IsGlobal), ref fIsGlobal, value);
      }
   }
   private Product fProduct;
   [Association("P-To-C")]
   public Product Product { 
      get {
         return fProduct;
      } 
      set {
         SetPropertyValue(nameof(Product), ref fProduct, value);
      } 
   }
}

下图演示了Windows Forms应用程序中的“订单详细信息视图”:

LookupPropetyEditors_1

在这里,产品和附件查找属性编辑器提供了整个产品和附件对象集合。但是,某些情况下可能需要在“附件查找属性编辑器”中显示已过滤的集合。

方案1-使用指定Collection属性中的对象填充查找

在“订单明细视图”中,如果附件查找属性编辑器仅提供与当前所选产品相关的附件对象,将很方便。为此,可以使用DataSourcePropertyAttribute属性。该属性的值指定一个属性,其可能的值用作当前查找属性的数据源。对于Order类的Accessory属性,此属性应设置为Product类的Accessory属性:

[DefaultClassOptions]
public class Order : BaseObject {
   // ...
   [DataSourceProperty("Product.Accessories")]
   public Accessory Accessory {
      get {
         return fAccessory;
      }
      set {
         SetPropertyValue(nameof(Accessory), ref fAccessory, value);
      }
   }
}

下图演示了生成的“订单详细信息视图”:

LookupPropertyEditors_2

如果指定应用程序模型的“应用程序” | “数据源”的DataSourceProperty属性,则可以实现相同的结果。BO模型| 班级| 成员节点。

注意
  • IModelListView.DataAccessMode选项设置为该ListView模型的ServerServerViewInstantFeedbackInstantFeedbackView时,将创建一个独立的服务器模式集合作为查找ListView的数据源。但是,当DataSourcePropertyAttribute将应用于查找属性,将属性中指向的属性用作查找数据源,并且不会创建也不使用独立的独立服务器模式集合。原因是数据源属性getter包含在客户端计算的逻辑,并且当查找编辑器请求显示对象时,数据源由客户端应用程序填充。因此,ServerServerViewInstantFeedbackInstantFeedbackView模式选项和DataSourceProperty属性不能同时工作。

  • 若要对通过中间对象实现多对多关系的Entity Framework对象使用上面演示的方法,请使用Map方法指定联接表,其列名并应用其他配置。要了解更多信息,请参阅Entity Framework Fluent API-Relationships主题。

方案2-为查找属性集合应用条件

查找列表视图可能必须包含其属性满足指定条件的对象。例如,可以为每种产品选择附件,即所谓的全局附件。要在订单明细视图中显示这些全局附件,可以使用DataSourceCriteriaAttribute属性。此属性的值指定必需的条件:

[DefaultClassOptions]
public class Order : BaseObject {
   // ...
   [DataSourceCriteria("IsGlobal = true")]
   public Accessory Accessory {
      get {
         return fAccessory;
      }
      set {
         SetPropertyValue(nameof(Accessory), ref fAccessory, value);
      }
   }
}
public class Accessory : BaseObject {
      // ...
   private bool fIsGlobal;
   public bool IsGlobal {
      get { return fIsGlobal; }
      set { 
         SetPropertyValue(nameof(IsGlobal), ref fIsGlobal, value);      
      }
   }
}

LookupPropertyEditors_3

如果指定应用程序模型的BOModel | DataSourceCriteria属性,则可以实现相同的结果。班级| 成员节点。

方案3-如果指定的数据源属性为空,则使用替代条件

让Lookup Property数据源依赖于另一个属性的值(请参阅Scenario1)。如果未指定此值,则可以提供另一个数据源。例如,当在“订单详细信息”视图的“产品查找”属性编辑器中未指定“产品”时,“附件查找”属性编辑器将提供“全局附件”的集合。为此,可以为DataSourceProperty属性指定DataSourcePropertyIsNullModeDataSourcePropertyIsNullCriteria参数。

[DefaultClassOptions]
public class Order : BaseObject {
   // ...
   [DataSourceProperty("Product.Accessories", 
      DataSourcePropertyIsNullMode.CustomCriteria, "IsGlobal = true")]
   public Accessory Accessory {
      get {
         return fAccessory;
      }
      set {
         SetPropertyValue(nameof(Accessory), ref fAccessory, value);
      }
   }
}

LookupPropertyEditors_3

注意

除了CustomCriteria值之外,DataSourceProperty属性的DataSourcePropertyIsNullMode参数还可以具有SelectAll和SelectNothing值。在这种情况下,您无需指定DataSourcePropertyIsNullCriteria参数。

如果指定应用程序模型的BOModel | DataSourcePropertyDataSourcePropertyIsNullModeDataSourcePropertyIsNullCriteria属性,则可以实现相同的结果。班级| 成员节点。

方案4-手动填充查找

假定“附件查找”属性数据源除了当前所选产品的附件(请参见方案1)之外,还可以包含“全局附件”(请参见方案2)。此外,假设存在一个名为IncludeGlobalAccessories的标志。如果有效,则附件查找属性数据源由当前产品的附件和全局附件组成。否则,它仅由当前产品的附件组成。为此,必须为Accessory属性显示一个附加集合。每次更改Product或IncludeGlobalAccessories属性时,都必须刷新此集合。以下代码演示了如何为该任务实现Order类。

[DefaultClassOptions]
public class Order : BaseObject {
   // ...
   // Set the AvailableAccessories collection as a data source for the Accessory property
   [DataSourceProperty(nameof(AvailableAccessories))] 
   public Accessory Accessory {
      get {return fAccessory;}
      set {
         SetPropertyValue(nameof(Accessory), ref fAccessory, value);
      }
   }
   private XPCollection<Accessory> fAvailableAccessories;
   [Browsable(false)] // Prohibits showing the AvailableAccessories collection separately
   public XPCollection<Accessory> AvailableAccessories {
      get {
         if(fAvailableAccessories == null) {
            // Retrieve all Accessory objects
            fAvailableAccessories = new XPCollection<Accessory>(Session);
            // Filter the retrieved collection according to current conditions
            RefreshAvailableAccessories();
         }
         // Return the filtered collection of Accessory objects
         return fAvailableAccessories;
      }
   }
   private void RefreshAvailableAccessories() {
      if(fAvailableAccessories == null)
         return;
      // Process the situation when the Product is not specified (see the Scenario 3 above)
      if(Product == null) {
         // Show only Global Accessories when the Product is not specified
         fAvailableAccessories.Criteria = CriteriaOperator.Parse("[IsGlobal] = true");
      }
      else {
         // Leave only the current Product's Accessories in the fAvailableAccessories collection
         fAvailableAccessories.Criteria = new BinaryOperator("Product", Product);
         if(IncludeGlobalAccessories == true) {
            // Add Global Accessories
            XPCollection<Accessory> availableGlobalAccessories = 
               new XPCollection<Accessory>(Session);
            availableGlobalAccessories.Criteria = CriteriaOperator.Parse("[IsGlobal] = true");
            fAvailableAccessories.AddRange(availableGlobalAccessories);
         }
      }
      // Set null for the Accessory property to allow an end-user 
      //to set a new value from the refreshed data source
      Accessory = null;
   }
   public Product Product {
      get {return fProduct;}
      set {
         SetPropertyValue(nameof(Product), ref fProduct, value);
         // Refresh the Accessory Property data source
         RefreshAvailableAccessories();
      }
   }
   private bool fIncludeGlobalAccessories;
   [ImmediatePostData] //Use this attribute to refresh the Accessory 
   public bool IncludeGlobalAccessories {
      get {return fIncludeGlobalAccessories;}
      set {
         if(fIncludeGlobalAccessories != value) {
            fIncludeGlobalAccessories = value;
            if(!IsLoading) {
               // Refresh the Accessory Property data source                    
               RefreshAvailableAccessories();
               SetPropertyValue(nameof(IncludeGlobalAccessories), ref fIncludeGlobalAccessories, value);
            }
         }
      }
   }
}

下图显示了订单明细视图:

FilterLookupDataSource

注意

当您无法将所需的条件写为字符串以将其作为属性的参数传递时,这种筛选“查找列表视图”的方法会很有用。在代码中,您可以使用任何条件运算符和任何操作数(包括“函数条件运算符”)。

方案5-根据当前对象的属性过滤查找属性集合

若要访问传递给DataSourcePropertyAttribute的条件中的当前编辑记录,请使用“当前对象”参数@This)。使用下面的代码,Contact.Manager查找将显示除“当前联系人”外所有处于“经理”位置的联系人。

using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
// ...
public class Contact : Person {
    // ...
    [DataSourceProperty("Department.Contacts", DataSourcePropertyIsNullMode.SelectAll)]
    [DataSourceCriteria("Position.Title = 'Manager' AND Oid != '@This.Oid'")]
    public Contact Manager {
        get {
            return fManager;
        }
        set {
            SetPropertyValue(nameof(Manager), ref fManager, value);
        }
    }
    // ...
}
注意

此代码段未包含在链接的“如何过滤查找列表视图”示例中。而是在XAF随附的主要演示解决方案的%PUBLIC%\ Documents \ DevExpress演示19.2 \ Components \ eXpressApp Framework \ MainDemo \ CS \ MainDemo.Module \ BusinessObjects \ Contact.cs文件中进行了演示。您还可以在“实施依赖参考属性”(XPO)教程中看到类似的代码。

相关文章

转载保留此链接,注明出处