M.Bouabdallah
M.Bouabdallah

Reputation: 772

DevExpress XAF Cascading Lookup List Views

I have created DevExpress XAF Blazor application.
I have four tables(pages)
The first one is Category related by a one-to-many with AssignedContractorCategory table
-oid string
-Title string

private string _Title;
public string Title
{
    get { return _Title; }
    set { SetPropertyValue(nameof(Title), ref _Title, value); }
}

[DevExpress.Xpo.Association("Category-AssignedContractorCategory")]
public XPCollection<AssignedContractorCategory> AssignedContractorCategory
{
    get
    {
        return GetCollection<AssignedContractorCategory>(nameof(AssignedContractorCategory));
    }
}

The second one is Contractor related by a one-to-many with AssignedContractorCategory table
-oid string
-Title string

private string _Title;
public string Title
{
    get { return _Title; }
    set { SetPropertyValue(nameof(Title), ref _Title, value); }
}

[DevExpress.Xpo.Association("Contractor-AssignedContractorCategory")]
public XPCollection<AssignedContractorCategory> AssignedContractorCategory
{
    get
    {
        return GetCollection<AssignedContractorCategory>(nameof(AssignedContractorCategory));
    }
}

The third one is AssignedContractorCategory related by a one-to-many with Bill table
-oid string
-FKCategory string
-FKContractor string

private Category _Category;
[Association("Category-AssignedContractorCategory")]
public Category Category
{
    get { return _Category; }
    set { SetPropertyValue(nameof(Category), ref _Category, value); }
}

private Contractor _Contractor;
[Association("Contractor-AssignedContractorCategory")]
public Contractor Contractor
{
    get { return _Contractor; }
    set { SetPropertyValue(nameof(Contractor), ref _Contractor, value); }
}

The fourth one is Bill
-oid string
-FKAssignedContractorCategory string
-Amount double

private Category _Category;
public Category Category
{
    get { return _Category; }
    set { SetPropertyValue(nameof(Category), ref _Category, value); }
}

private Contractor _Contractor;
public Contractor Contractor
{
    get { return _Contractor; }
    set { SetPropertyValue(nameof(Contractor), ref _Contractor, value); }
}

private double _Amount;
public double Amount
{
    get { return _Amount; }
    set { SetPropertyValue(nameof(Amount), ref _Amount, value); }
}

On Bill page I want to show :
Category (Lookup List Views) and after I chose one category it shows only Contractor (Lookup List Views) that are related on table AssignedContractorCategory
Please note that I am a beginner.

Upvotes: 1

Views: 1092

Answers (1)

Marco
Marco

Reputation: 840

Step 1: On your Bill class, decorate the Category-property with the ImmediatePostData attribute. It will ensure that the setter will get called immediately after every change on the UI:

[ImmediatePostData]
public Category Category

Step 2: On the Bill class, add the DataSourceProperty-attribute to your Contractor property, and then implement a corresponding property which always returns the correct selection of Contractors. Note that I decorate the new ContractorSelection-property with [Browsable(false)] so that it's completely invisible on the XAF UI:

private Contractor _Contractor;
[DataSourceProperty(nameof(ContractorSelection))]
public Contractor Contractor
{
    get { return _Contractor; }
    set { SetPropertyValue(nameof(Contractor), ref _Contractor, value); }
}

[Browsable(false)]
public IList<Contractor> ContractorSelection
{
    get
    {
       return Category?.AssignedContractorCategory.Select(i => i.Contractor).Distinct().ToList();
    }
}

Step 3: The problem now is that XAF does not automatically update its internal cache of the ContractorSelection-collection when you change the Category. For this to work, you need to change the setter of your Category-property and tell XAF than the Contractor property has also changed:

[ImmediatePostData]
public Category Category
{
    get { return _Category; }
    set 
    { 
        SetPropertyValue(nameof(Category), ref _Category, value);
        if (!IsLoading)
        {
            OnChanged(nameof(Contractor));
        }
    }
}

I tested this, and it works fine in XAF Blazor.


Alternative method:

If you prefer your objects to be filtered by the DB (ideal if you have a large collection of contractors), you can use the DataSourceCriteria-attribute instead, and then remove the ContractorSelection-property from my initial solution. All the other code remains the same:

private Contractor _Contractor;
[DataSourceCriteria("AssignedContractorCategory[Category = '@This.Category'].Count > 0")]
public Contractor Contractor
{
    get { return _Contractor; }
    set { SetPropertyValue(nameof(Contractor), ref _Contractor, value); }
}

Additional Info:

  • We have not defined what XAF should display when no category is selected. Check out the XAF documentation of the DataSourceProperty-attribute on how you can specify the appropriate behavior in case the datasource is null.
  • You may also want to use the Category-setter to enforce other constraints, such as setting the Contractor to null in case the currently selected Contractor is not part of the selected category. The more interdependent properties you have, the more complex this gets.
  • If your AssignedContractorCategory class is only used as a pure link between Contractor and Category (without additional properties), then you may want to consider using XPO's integrated many-to-many associations

Upvotes: 2

Related Questions