Current filter:
                                You should refresh the page.
                                  • Description:
                                    Although the PropertyGridControl is intended to work with specialized classes that provide extended metadata declared using Design-Time Attributes (unlike the VGridControl, which we suggest using with regular business objects), sometimes developers need to allow users to edit regular business objects using this control.

                                    This article describes how to meet particular requirements in this scenario when business objects are inherited from base classes of the eXpress Persistent Objects library:

                                    * Editing a property referencing another persistent object using a custom UI Type Editor.
                                    * Associate a Type Converter providing a list of standard values for a property referencing another persistent object.
                                    * Assign the ExpandableObjectConverterAttribute attribute to a property referencing another persistent object to edit sub properties.

                                    These (and similar) requirements have a common part: a property referencing another persistent object. By this, I mean a property participating in a relationship between objects and representing the "One" side of the One-to-Many relation.

                                    To support the Master-Detail mode, XPO classes represent such properties as collections containing a single item. This feature makes it difficult to complete the aforementioned tasks using the PropertyGridControl. Below, I have described how to overcome this shortcoming.

                                    Answer:
                                    Solution #1
                                    As mentioned above, the PropertyGridControl is intended to work with specialized classes. Hence, a straightforward way to achieve the required result is just to create a specialized class that can provide extended metadata for the PropertyGridControl and act as a decorator for a persistent object. This approach enables you to support end-user requirements of any complexity and extend the UI in the future without affecting regular business objects structure. It allows you to keep business objects library simple by moving UI-related logic into specialized classes.

                                    Solution #2
                                    If the aforementioned approach cannot be used, you can utilize the CustomPropertyDescriptor event provided by the PropertyGridControl to allow programmers to modify the default properties collection. It is necessary to declare a custom class inherited from the PropertyDescriptor and implement the capability to edit a reference property using the UI Type editor.

                                    The code snippets below demonstrate the implementation details for both approaches.

                                    Solution #1

                                    [C#]
                                    public class Customer :XPObject { public Customer(Session session) : base(session) { } public string ContactName { get { return this.GetPropertyValue<string>("ContactName"); } set { this.SetPropertyValue<string>("ContactName", value); } } [Aggregated] public Address Address { get { return this.GetPropertyValue<Address>("Address"); } set { this.SetPropertyValue<Address>("Address", value); } } } public class CustomerWrapper { private readonly Customer InnerCustomer; private readonly AddressWrapper InnerAddress; public CustomerWrapper(Customer customer) { this.InnerCustomer = customer; this.InnerAddress = new AddressWrapper(customer.Address); } public string ContactName { get { return this.InnerCustomer.ContactName; } set { this.InnerCustomer.ContactName = value; } } public AddressWrapper Address { get { return this.InnerAddress; } } } [TypeConverter(typeof(ExpandableObjectConverter))] public class AddressWrapper { private readonly InnerAddress; public AddressWrapper(Address address) { this.InnerAddress = address; } }
                                    [VB.NET]
                                    Public Class Customer Inherits XPObject Public Sub New(ByVal session As Session) MyBase.New(session) End Sub Public Property ContactName() As String Get Return Me.GetPropertyValue(Of String)("ContactName") End Get Set(ByVal value As String) Me.SetPropertyValue(Of String)("ContactName", value) End Set End Property <Aggregated> Public Property Address() As Address Get Return Me.GetPropertyValue(Of Address)("Address") End Get Set(ByVal value As Address) Me.SetPropertyValue(Of Address)("Address", value) End Set End Property End Class Public Class CustomerWrapper Private ReadOnly InnerCustomer As Customer Private ReadOnly InnerAddress As AddressWrapper Public Sub New(ByVal customer As Customer) Me.InnerCustomer = customer Me.InnerAddress = New AddressWrapper(customer.Address) End Sub Public Property ContactName() As String Get Return Me.InnerCustomer.ContactName End Get Set(ByVal value As String) Me.InnerCustomer.ContactName = value End Set End Property Public ReadOnly Property Address() As AddressWrapper Get Return Me.InnerAddress End Get End Property End Class <TypeConverter(GetType(ExpandableObjectConverter))> Public Class AddressWrapper Private ReadOnly InnerAddress Public Sub New(ByVal address As Address) Me.InnerAddress = address End Sub End Class

                                     Solution #2

                                    [C#]
                                    private void PropertyGridControl_CustomPropertyDescriptors(object sender, CustomPropertyDescriptorsEventArgs e) { string referencePropertyName = "ReferencePropretyName"; PropertyDescriptor referenceProperty = e.Properties.Find(referencePropertyName, false); if (referenceProperty == null) return; referenceProperty = new CustomPropertyDescriptor(referenceProperty, typeof(ReferencePropertyType)); List<PropertyDescriptor> properties = new List<PropertyDescriptor>(); foreach (PropertyDescriptor property in e.Properties) if (property.Name == referencePropertyName) properties.Add(referenceProperty); else properties.Add(property); e.Properties = new PropertyDescriptorCollection(properties.ToArray(), true); } public class CustomPropertyDescriptor : PropertyDescriptor { private PropertyDescriptor Inner; private Type InnerPropertyType; public CustomPropertyDescriptor(PropertyDescriptor inner, Type propertyType) : base(inner) { this.Inner = inner; this.InnerPropertyType = propertyType; } public override bool CanResetValue(object component) { return this.Inner.CanResetValue(component); } public override Type ComponentType { get { return this.Inner.ComponentType; } }     public override object GetValue(object component) {         PersistentBase entity = (PersistentBase)component;         XPMemberInfo member = entity.ClassInfo.GetMember(this.Name);         return member.GetValue(component);     } public override bool IsReadOnly { get { return false; } } public override Type PropertyType { get { return this.InnerPropertyType; } } public override void ResetValue(object component) { this.Inner.ResetValue(component); } public override void SetValue(object component, object value) { PersistentBase entity = (PersistentBase)component; XPMemberInfo member = entity.ClassInfo.GetMember(this.Name); member.SetValue(component, value); } public override bool ShouldSerializeValue(object component) { return this.Inner.ShouldSerializeValue(component); } }
                                    [VB.NET]
                                    Private Sub PropertyGridControl_CustomPropertyDescriptors(ByVal sender As Object, ByVal e As CustomPropertyDescriptorsEventArgs) Dim referencePropertyName As String = "ReferencePropretyName" Dim referenceProperty As PropertyDescriptor = e.Properties.Find(referencePropertyName, False) If referenceProperty Is Nothing Then Return End If referenceProperty = New CustomPropertyDescriptor(referenceProperty, GetType(ReferencePropertyType)) Dim properties As New List(Of PropertyDescriptor)() For Each [property] As PropertyDescriptor In e.Properties If [property].Name = referencePropertyName Then properties.Add(referenceProperty) Else properties.Add([property]) End If Next [property] e.Properties = New PropertyDescriptorCollection(properties.ToArray(), True) End Sub Public Class CustomPropertyDescriptor Inherits PropertyDescriptor Private Inner As PropertyDescriptor Private InnerPropertyType As Type Public Sub New(ByVal inner As PropertyDescriptor, ByVal propertyType As Type) MyBase.New(inner) Me.Inner = inner Me.InnerPropertyType = propertyType End Sub Public Overrides Function CanResetValue(ByVal component As Object) As Boolean Return Me.Inner.CanResetValue(component) End Function Public Overrides ReadOnly Property ComponentType() As Type Get Return Me.Inner.ComponentType End Get End Property Public Overrides Function GetValue(ByVal component As Object) As Object Dim entity As PersistentBase = DirectCast(component, PersistentBase) Dim member As XPMemberInfo = entity.ClassInfo.GetMember(Me.Name) Return member.GetValue(component) End Function Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object) Dim entity As PersistentBase = DirectCast(component, PersistentBase) Dim member As XPMemberInfo = entity.ClassInfo.GetMember(Me.Name) member.SetValue(component, value) End Sub Public Overrides ReadOnly Property IsReadOnly() As Boolean Get Return False End Get End Property Public Overrides ReadOnly Property PropertyType() As Type Get Return Me.InnerPropertyType End Get End Property Public Overrides Sub ResetValue(ByVal component As Object) Me.Inner.ResetValue(component) End Sub Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean Return Me.Inner.ShouldSerializeValue(component) End Function End Class

                                0 Solutions

                                Creation Date Importance Sort by