Most applications have Detail Views which contain Lookup Property Editors that need to be filtered. Often, you should make the List View data source of these editors dependent on values of other Property Editors located in the same Detail View. For this purpose, the eXpressApp Framework provides the DataSourcePropertyAttribute and DataSourceCriteriaAttribute. This topic demonstrates how to use both these attributes in code and using the Application Model. In these examples, the Order, Product and Accessory classes will be implemented in different ways.
大多数应用程序具有包含需要筛选的查找属性编辑器的详细信息视图。通常,应使这些编辑器的列表视图数据源依赖于位于同一详细信息视图中的其他属性编辑器的值。为此,eXpressApp 框架提供数据源属性属性和数据源标准属性。本主题演示如何在代码中使用这两个属性,以及如何使用应用程序模型。在这些示例中,订单、产品和附件类将以不同的方式实现。
- Initial Implementation
- Scenario 1 - Populate the Lookup with Objects from the Specified Collection Property
- Scenario 2 - Apply Criteria For the Lookup Property Collection
- Scenario 3 - Use Alternate Criteria if the Specified Data Source Property is Empty
- Scenario 4 - Populate the Lookup Manually
- Scenario 5 - Filter the Lookup Property Collection Based on the Current Object's Properties
- 初步实施
- 方案 1 - 使用指定集合属性中的对象填充查找
- 方案 2 - 为查找属性集合应用条件
- 方案 3 - 如果指定的数据源属性为空,请使用备用条件
- 方案 4 - 手动填充查找
- 方案 5 - 基于当前对象的属性筛选查找属性集合
Tip 提示
A complete sample project is available in the DevExpress Code Examples database at http://www.devexpress.com/example=E218
完整的示例项目可在 DevExpress 代码示例数据库中找到,http://www.devexpress.com/example=E218
.
Initial Implementation
初步实施
Initially, an Order includes a Product and Accessory. In addition, each Accessory is related to a particular Product. So, the Product and Accessory objects are related by a One-to-Many relationship. The following code shows how these classes can be implemented:
最初,订单包括产品和附件。此外,每个附件都与特定产品相关。因此,产品和附件对象由一对多关系相关。以下代码演示如何实现这些类:
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); } } }
The image below demonstrates the Order Detail View in a Windows Forms application:
下图演示了 Windows 窗体应用程序中的订单详细信息视图:
Here, the Product and Accessory Lookup Property Editors provide the entire Product and Accessory objects collections. However, certain scenarios may require a filtered collection to be displayed within the Accessory Lookup Property Editor.
在这里,产品和附件查找属性编辑器提供整个产品和附件对象集合。但是,某些方案可能需要在"附件查找属性编辑器"中显示筛选的集合。
Scenario 1 - Populate the Lookup with Objects from the Specified Collection Property
方案 1 - 使用指定集合属性中的对象填充查找
In the Order Detail View, it would be convenient if the Accessory Lookup Property Editor only provided the Accessory objects related to the currently selected Product. To accomplish this, the DataSourcePropertyAttribute attribute can be used. This attribute's value specifies a property whose possible values serve as the data source for the current lookup property. For the Order class' Accessory property, this attribute should be set to the Product class' Accessory property:
在"订单详细信息"视图中,如果附件查找属性编辑器仅提供与当前所选产品相关的附件对象,则会很方便。为此,可以使用 DataSourceProperty属性属性。此属性的值指定一个属性,其可能的值用作当前查找属性的数据源。对于 Order 类的"附件"属性,此属性应设置为 Product 类的"附件"属性:
[DefaultClassOptions] public class Order : BaseObject { // ... [DataSourceProperty("Product.Accessories")] public Accessory Accessory { get { return fAccessory; } set { SetPropertyValue(nameof(Accessory), ref fAccessory, value); } } }
The following image demonstrates the resulting Order Detail View:
下图演示了生成的订单详细信息视图:
The same result can be achieved if you specify the DataSourceProperty property of the Application Model's Application | BOModel | Class | Member node.
如果指定应用程序模型应用程序的 DataSourceProperty 属性,则结果相同 |BOModel |类 |成员节点。
Note 注意
An independent server-mode collection is created as a data source for a lookup ListView when the IModelListView.DataAccessMode option is set to Server or InstantFeedback for that ListView model. However, when the DataSourcePropertyAttribute is applied for the lookup property, the property pointed in the attribute is used as a lookup data source, and the standalone independent server-mode collection is not created and is not used at all. The reason is that the data source property getter contains logic calculated on the client side and the data source is populated by the client application at the moment when the lookup editor requests to display objects. So, the Server or InstantFeedback mode option and the DataSourceProperty attribute do not work simultaneously.
To use the approach demonstrated above for Entity Framework objects with a many-to-many relationship implemented through an intermediate object, use the Map topic.
当 IModelListView.DataAccessMode 选项设置为该 ListView 模型的"服务器"或"即时反馈"时,将创建一个独立的服务器模式集合作为查找 ListView 的数据源。但是,当 DataSourceProperty属性应用于查找属性时,属性中指向的属性将用作查找数据源,并且不会创建独立的独立服务器模式集合,也不会使用。原因是数据源属性 getter 包含客户端计算的逻辑,并且在查找编辑器请求显示对象时,客户端应用程序填充了数据源。因此,服务器或即时反馈模式选项和 DataSourceProperty 属性不能同时工作。
要对通过中间对象实现的多对多关系的实体框架对象使用上面演示的方法,请使用 Map 主题。
method to specify the join table, its columns names, and to apply additional configuration. To learn more, refer to the Entity Framework Fluent API - Relationships
方法,以指定联接表及其列名称,并应用其他配置。要了解更多信息,请参阅实体框架流畅 API - 关系
Scenario 2 - Apply Criteria For the Lookup Property Collection
方案 2 - 为查找属性集合应用条件
It may be necessary for a Lookup List View to contain objects whose properties satisfy a specified criteria. For example, there can be Accessories that can be chosen for every Product, so called Global Accessories. To display these Global Accessories in the Order Detail View, the DataSourceCriteriaAttribute attribute can be used. This attribute's value specifies the required criteria:
查找列表视图可能需要包含其属性满足指定条件的对象。例如,可以为每个产品选择附件,称为全局附件。要在"订单详细信息"视图中显示这些全局附件,可以使用"数据源标准属性"属性。此属性的值指定所需的条件:
[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); } } }
The same result can be achieved if you specify the DataSourceCriteria property of the Application Model's BOModel | Class | Member node.
如果指定应用程序模型的 BOModel 的 DataSourceCriteria 属性,则可以得出相同的结果 |类 |成员节点。
Scenario 3 - Use Alternate Criteria if the Specified Data Source Property is Empty
方案 3 - 如果指定的数据源属性为空,请使用备用条件
Let a Lookup Property data source depend on a value of another property (see Scenario1). When this value is not specified, you can provide another data source. For example, when a Product is not specified in the Product Lookup Property Editor of the Order Detail View, the Accessories Lookup Property Editor will provide the collection of Global Accessories. To accomplish this, the DataSourcePropertyIsNullMode and DataSourcePropertyIsNullCriteria parameters can be specified for the DataSourceProperty attribute.
让查找属性数据源依赖于另一个属性的值(请参阅方案 1)。未指定此值时,可以提供其他数据源。例如,当订单详细信息视图的产品查找属性编辑器中未指定产品时,附件查找属性编辑器将提供全局附件的集合。为此,可以为 DataSourcePropertyIsNullMode 和 DataSourcePropertyIsNullcriteria 参数指定数据源属性属性。
[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); } } }
Note 注意
In addition to the CustomCriteria value, the DataSourcePropertyIsNullMode parameter of the DataSourceProperty attribute can also have the SelectAll and SelectNothing values. In this instance, you do not need to specify the DataSourcePropertyIsNullCriteria parameter.
除了自定义标准值外,DataSourcePropertyIninSNullMode 属性的 DataSourcePropertyIsNullMode 参数还可以具有"全部选择"和"选择不一切"值。在这种情况下,您不需要指定 DataSourcePropertyIsNullCriteria 标准参数。
The same result can be achieved if you specify the DataSourceProperty, DataSourcePropertyIsNullMode and DataSourcePropertyIsNullCriteria properties of the Application Model's BOModel | Class | Member node.
如果指定应用程序模型的 BOModel 的 DataSource 属性、DataSourcePropertyIsNullMode 和 DataSourcePropertyIsNullcriteria 属性属性,则可以得出相同的结果。类 |成员节点。
Scenario 4 - Populate the Lookup Manually
方案 4 - 手动填充查找
Assume the Accessory Lookup Property data source can contain Global Accessories (see Scenario 2) in addition to the currently selected Product's Accessories (see Scenario 1). In addition, assume there is a flag called IncludeGlobalAccessories. If it is in effect, the Accessory Lookup Property data source is composed of both the current Product's Accessories and Global Accessories. Otherwise, it is made up of the current Product's Accessories only. For this purpose, an additional collection must be shown for the Accessory property. This collection must be refreshed each time the Product or IncludeGlobalAccessories property is changed. The following code demonstrates how to implement the Order class for this task.
假设附件查找属性数据源可以包含全局附件(参见方案 2),以及当前选定的产品附件(请参阅方案 1)。此外,假设有一个名为"包括全球附件"的标志。如果有效,则"附件查找属性"数据源由当前产品的附件和全局附件组成。否则,它仅由当前产品的附件组成。为此,必须为"附件"属性显示其他集合。每次更改"产品"或"包括全球附件"属性时,都必须刷新此集合。以下代码演示如何实现此任务的 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); } } } } }
The following image shows an Order Detail View:
下图显示了订单详细信息视图:
Note 注意
This approach to filter Lookup List Views is helpful when you cannot write the required criteria as a string to pass it as an attribute's parameter. In code, you can use any criteria operator and any operands (including Function Criteria Operators).
当您无法将所需的条件编写为字符串以将其作为属性的参数传递时,筛选查找列表视图的此方法非常有用。在代码中,可以使用任何条件运算符和任何操作数(包括函数条件运算符)。
Scenario 5 - Filter the Lookup Property Collection Based on the Current Object's Properties
方案 5 - 基于当前对象的属性筛选查找属性集合
To access the currently edited record in criteria passed to the DataSourcePropertyAttribute, use the Current Object Parameter (@This). With the code below, the Contact.Manager lookup will display all Contacts with the "Manager" Position except for the current Contact.
要访问传递到 DataSourceProperty 属性的条件中当前编辑的记录,请使用当前对象参数 (@This)。使用下面的代码,联系人.管理器查找将显示除当前联系人之外的所有具有"经理"位置的联系人。
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); } } // ... }
Note 注意
This code snippet is not included in the linked How to Filter Lookup List Views example. Instead, it is demonstrated in the %PUBLIC%DocumentsDevExpress Demos 19.2ComponentseXpressApp FrameworkMainDemoCSMainDemo.ModuleBusinessObjectsContact.cs file of Main Demo solution shipped with XAF. You can also see a similar code in the Implement Dependent Reference Properties (XPO) tutorial.
此代码段不包括在链接的"如何筛选查找列表视图"示例中。相反,它在%PUBLIC%DocumentsDevExpress Demos 19.2ComponentseXpressApp FrameworkMainDemoCSMainDemo.ModuleBusinessObjectsContact.cs file of Main Demo solution shipped with XAF. You can also see a similar code in the Implement Dependent Reference Properties (XPO) tutorial.