Base and Parent Filtering ViewModels

  • 4 minutes to read

The Filtering UI Context works with a filtering ViewModel, which is generated automatically from a filtering Model you provide. The ViewModel contains all business logic required to identify valid properties, parse filtering attributes and generate the required editors.

FilteringUI - Scheme Simple

You can modify this inaccessible ViewModel layer using the MVVM-based approach, by inheriting it from a custom class (base ViewModel) and\or relating it to another class (parent ViewModel) via the parent-child relationship.

FilteringUI - Scheme Advanced

To specify the base ViewModel, use the component's smart tag (in "Advanced Binding" mode) or set the BaseViewModelType property programmatically.

this.filteringUIContext1.BaseViewModelType = typeof(FilteringUIProviderEF.ProductFilteringViewModel);

To set the parent ViewModel, either assign its instance to the ParentViewModel property or specify the MvvmContext component that manages the same ViewModel.

this.filteringUIContext1.ParentViewModel = new CustomViewModel();
//or 
this.filteringUIContext1.ParentViewModelProvider = this.mvvmContext1;

There is no specific recommendation on whether to use the base ViewModel only, the parent ViewModel, or both simultaneously. Use the approach that best fits your needs.

Replacing Filtering Events

As the diagram above shows, filtering events no longer take part in this MVVM-like approach since handling events breaks the main MVVM concept of separating a GUI from application logic. Instead, use filtering attributes whose parameters that end with '...Member'. The example below illustrates how to populate a look-up editor without handling the QueryLookupData event.

The CustomFilteringViewModel class uses the RetrieveCategoryList method to return a list containing all the existing category names. The public ProductCategories property returns this list with one additional custom item added to it.

public class CustomFilteringViewModel {
    public List<Category> productCategoriesCore;

    public CustomFilteringViewModel() {
        this.productCategoriesCore= new List<Category>();
        List<String> catList = parentForm.RetrieveCategoryList();
        foreach (String element in catList) {
            productCategoriesCore.Add(new Category() { Name = element });
        }
        productCategoriesCore.Add(new Category() { Name = "Custom Category" });
    }

    public List<Cagetory> ProductCategories {
        get { return productCategoriesCore; }
    }
}

You can use this class's ProductCategories property to set the DataSourceMember parameter if you are using it as a base or parent ViewModel. Setting this parameter is identical to passing a lookup item collection to the QueryLookupData event handler's e.Result.DataSource property. You can also specify the ValueMember and DisplayMember parameters to assign two additional base or parent ViewModel members. The first member is used to build filter criteria objects while the second member returns values that are displayed to an end-user. Use these parameters when you have paired data fields like 'ModelName' and 'ModelID'.

[DevExpress.Utils.Filtering.FilterLookup(DataSourceMember = "ProductCategories",
    ValueMember ="CategoryName", DisplayMember ="CategoryName", EditorType = LookupUIEditorType.List,
    UseSelectAll = true, SelectAllName = "All Categories")]
[Display(Name = "Category")]

public string CategoryName { get; set; }

The same applies to the remaining filtering events:

  • Add the FilterRange attribute and specify its MinimumMember, MaximumMember, and AverageMember properties instead of handling the QueryRangeData event;
  • Add the FilterBooleanChoice attribute and specify its DefaultValueMember parameter to replace the QueryBooleanChoiceData event.

Metadata Classes

If your filtering Model changes (for example, they are re-generated when using code-first data sources), your filtering attributes declared in it are lost. To avoid these issues, create a metadata class with public fields and all the required filtering attributes. Then, with the help of the FilterMetadataType attribute, you can share these attributes with your filtering Model. See the 'Metadata Attributes' section of the Filtering Attributes article for an example.