All docs
V21.1
21.2 (EAP/Beta)
21.1
20.2
The page you are viewing does not exist in version 20.2. This link will take you to the root page.
20.1
The page you are viewing does not exist in version 20.1. This link will take you to the root page.
19.2
The page you are viewing does not exist in version 19.2. This link will take you to the root page.
19.1
The page you are viewing does not exist in version 19.1. This link will take you to the root page.
18.2
The page you are viewing does not exist in version 18.2. This link will take you to the root page.
18.1
The page you are viewing does not exist in version 18.1. This link will take you to the root page.
17.2
The page you are viewing does not exist in version 17.2. This link will take you to the root page.
.NET Framework 4.5.2+
.NET Framework 4.5.2+
.NET Standard 2.0+
.NET Core 3.0+

How to: Display and Edit Simple Type Values in a Lookup Property Editor

  • 8 minutes to read

This help topic describes how to allow end users to select a property value of a simple type (string, integer, enumeration, and so on) in a lookup editor.

Important

The examples demonstrated in this help topic require calculation on the client side and do not support Server, ServerView, InstantFeedback, and InstantFeedbackView modes.

Populate the Lookup Editor with Values from Another Property

This section demonstrates how to display user-friendly strings instead of simple type values in a lookup editor.

Scenario

Suppose you have the following class and want to display user-friendly strings for the Position integer property:

File: MySolution.Module\BusinessObjects\DemoClass.cs(.vb).

using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
//...
[DefaultClassOptions]
public class DemoClass : BaseObject {
    public DemoClass(Session session) : base(session) { }
    int _position;
    public int Position {
        get { return _position; }
        set { SetPropertyValue(nameof(Position), ref _position, value); }
    }
}

Solution

  1. Apply the Browsable attribute to the Position property to hide its editor from the UI:

    using System.ComponentModel;
    //...
    public class DemoClass {
        //...
        [Browsable(false)]
        public int Position {
            //...
        }
    }
    
  2. Create an additional PositionPropertyWrapper class that is a wrapper for the DemoClass.Position property. Apply the DomainComponent attribute to this class to make it non-persistent. In PositionPropertyWrapper, the Key property stores the original integer values, and the DisplayName property returns their user-friendly string representations.

    File: MySolution.Module\BusinessObjects\PositionPropertyWrapper.cs(.vb).

    using DevExpress.ExpressApp.DC;
    //...
    [DomainComponent, XafDefaultProperty(nameof(PositionName))]
    public class PositionPropertyWrapper {
        private int _key;
        private string _positionName;
        public PositionPropertyWrapper(string positionName, int key) {
            this._key = key;
            this._positionName = positionName;
        }
        [DevExpress.ExpressApp.Data.Key]
        public int Key { get { return _key; } }
        public string PositionName { get { return _positionName; } }
    }
    

    Important

    Use the Key attribute from the DevExpress.ExpressApp.Data namespace only (not from the System.ComponentModel.DataAnnotations or DevExpress.Xpo namespaces). This attribute is required for XAF ASP.NET Web Forms and ASP.NET Core Blazor applications.

  3. Extend DemoClass with the PositionDataSource property that stores the collection of non-persistent PositionPropertyWrapper objects. The Position lookup editor displays these objects. Apply the Browsable attribute to the PositionDataSource property to hide its editor from the UI:

    File: MySolution.Module\BusinessObjects\DemoClass.cs(.vb).

    using System.ComponentModel;
    //...
    public class DemoClass {
        //...
        private BindingList<PositionPropertyWrapper> _positionDataSource;
        [Browsable(false)]
        public BindingList<PositionPropertyWrapper> PositionDataSource {
            get {
                if (_positionDataSource == null) {
                    _positionDataSource = new BindingList<PositionPropertyWrapper>();
                    for (int i = 0; i < 5; i++) {
                        _positionDataSource.Add(new PositionPropertyWrapper("Position" + i.ToString(), i));
                    }
                }
                return _positionDataSource;
            }
        }
    }
    
  4. Extend DemoClass with the non-persistent PositionWrapper property of the PositionPropertyWrapper type to update the persistent Position property. Apply the DataSourceProperty attribute to PositionWrapper to populate the lookup editor data source:

    using System.Linq;
    // ...
    public class DemoClass {
        // ...
        private PositionPropertyWrapper _positionPropertyWrapper;
        [NonPersistent, XafDisplayName("Position")]
        [DataSourceProperty(nameof(PositionDataSource))]
        public PositionPropertyWrapper PositionWrapper {
            get {
                if (_positionPropertyWrapper == null || _positionPropertyWrapper.Key != Position) {
                    _positionPropertyWrapper = PositionDataSource.FirstOrDefault(i => i.Key == Position);
                }
                return _positionPropertyWrapper;
            }
            set {
                SetPropertyValue(nameof(PositionWrapper), ref _positionPropertyWrapper, value);
                if (!IsLoading && !IsSaving) {
                    Position = value.Key;
                }
            }
        }
    }
    
  5. Optional. You can also hide the lookup editor’s Clear button for a non-nullable PositionWrapper property. To do this, set its AllowClear property to false in the Model Editor or apply ModelDefaultAttribute to PositionWrapper:

    using DevExpress.ExpressApp.Model;
    // ...
    public class DemoClass {
        // ...
        [ModelDefault("AllowClear", "false")]
        public PositionPropertyWrapper PositionWrapper {
            // ...
        }
    }
    

Populate the Lookup Editor with Persistent Business Objects

This section demonstrates how to display a lookup editor with persistent objects instead of a simple type editor. Use this technique if you have legacy databases and cannot modify their schemas to create associations between tables.

Scenario

Suppose you have the following classes and want to display the Position.Title lookup editor instead of the DemoClass.PositionTitle string editor.

using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
//...
[DefaultClassOptions]
public class DemoClass : BaseObject {
    public DemoClass(Session session) : base(session) { }
    string positionTitle;
    public string PositionTitle {
        get { return positionTitle; }
        set { SetPropertyValue(nameof(PositionTitle), ref positionTitle, value); }
    }
}

[DefaultClassOptions, XafDefaultProperty(nameof(Title))]
public class Position : XPObject {
    public Position(Session session) : base(session) { }
    string _title;
    [Size(SizeAttribute.DefaultStringMappingFieldSize)]
    public string Title {
        get {
            return _title;
        }
        set {
            SetPropertyValue(nameof(Title), ref _title, value);
        }
    }
}

Solution

  1. Apply the Browsable attribute to the PositionTitle property to hide its editor from the UI:

    using System.ComponentModel;
    //...
    public class DemoClass {
        //...
        [Browsable(false)]
        public string PositionTitle {
            //...
        }
    }
    
  2. Create a non-persistent wrapper property (LookupPropertyForDisplay) to fetch records from the Position data table:

    using DevExpress.Data.Filtering;
    using DevExpress.ExpressApp.DC;
    using DevExpress.Xpo;
    //...
    public class DemoClass {
        //...
        private Position _LookupPropertyForDisplay;
        [NonPersistent, XafDisplayName("Position")]
        public Position LookupPropertyForDisplay {
            get {
                if ((_LookupPropertyForDisplay == null && !string.IsNullOrEmpty(positionTitle)) || 
                (_LookupPropertyForDisplay != null && _LookupPropertyForDisplay.Title != PositionTitle)) {
                    _LookupPropertyForDisplay = 
                        Session.FindObject<Position>(new BinaryOperator("Title", positionTitle));
                }
                return _LookupPropertyForDisplay;
            }
            set {
                SetPropertyValue<Position>(nameof(LookupPropertyForDisplay), 
                                           ref _LookupPropertyForDisplay, value);
                if (!IsLoading && !IsSaving) {
                    PositionTitle = value != null ? value.Title : string.Empty;
                }
            }
        }
    }
    

Notes