Description:
Answer:
Type properties are defined in code and represented in the application UI for different platforms as described in the eXpressApp Framework > Concepts > Business Model Design > Data Types Supported by built-in Editors > Type Properties documentation article. Thus, there are three possible ways of accomplishing this task, which apply at different application layers:
1. Data model level
Since the System.Type properties are usually declared using System.ComponentModel.TypeConverterAttribute that provides a TypeConverter class for setting a list of default values or default choice of types shown in the editor, you can provide a custom TypeConverter that contains only required types. A custom TypeConverter class can either be implemented from scratch or inherited from built-in XAF ones like LocalizedClassInfoTypeConverter or ClassInfoTypeConverter.
If you own the source code of the target System.Type property, you can change its declaration directly in the code of your business class. Otherwise (e.g., you want to customize the behavior of a class in a third-party assembly), you can remove the default TypeConverterAttribute and replace it with a required one at runtime as per eXpressApp Framework > Concepts > Business Model Design > Types Info Subsystem > Customize Business Object's Metadata. To find the exact type of TypeConverter used in such a class, refer to its source code. The location of DevExpress source code is shown in the KA18677: Where can I get demo source code folder, installed assemblies, or source code on machines with different OS versions article. The following source code illustrates this approach in action for a scenario when a list of types shown for the TargetType editor of the security type permission record in the UI is filtered:
C#using System;
using System.Linq;
using System.ComponentModel;
using DevExpress.ExpressApp;
using MainDemo.Module.Reports;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Xpo;
using System.Collections.Generic;
using DevExpress.ExpressApp.Updating;
using DevExpress.ExpressApp.ReportsV2;
using MainDemo.Module.BusinessObjects;
using DevExpress.ExpressApp.Security.Strategy;
namespace MainDemo.Module {
public sealed partial class MainDemoModule : ModuleBase {
public MainDemoModule() {
InitializeComponent();
}
public override void CustomizeTypesInfo(ITypesInfo typesInfo) {
base.CustomizeTypesInfo(typesInfo);
CalculatedPersistentAliasHelper.CustomizeTypesInfo(typesInfo);
SecurityTargetTypeConverterEx.TypesToBeExcluded.Add(typeof(MainDemo.Module.BusinessObjects.Contact));
SecurityTargetTypeConverterEx.TypesToBeExcluded.Add(typeof(DevExpress.Persistent.BaseImpl.Country));
SecurityTargetTypeConverterEx.CustomizeTypesInfo(typesInfo);
}
}
public class SecurityTargetTypeConverterEx: SecurityTargetTypeConverter {
public static readonly IList<Type> TypesToBeExcluded = new List<Type>();
public override List<Type> GetSourceCollection(ITypeDescriptorContext context) {
List<Type> result = base.GetSourceCollection(context);
foreach(Type item in TypesToBeExcluded) {
result.Remove(item);
}
return result;
}
public static void CustomizeTypesInfo(ITypesInfo typesInfo) {
ITypeInfo typeInfo = typesInfo.FindTypeInfo(typeof(PermissionPolicyTypePermissionObject));
if(typeInfo != null) {
BaseInfo memberBaseInfo = typeInfo.Members.First(p => p.Name == "TargetType") as BaseInfo;
if(memberBaseInfo != null) {
TypeConverterAttribute typeConverterAttribute = memberBaseInfo.FindAttribute<TypeConverterAttribute>();
if(typeConverterAttribute != null) {
memberBaseInfo.RemoveAttribute(typeConverterAttribute);
}
memberBaseInfo.AddAttribute(new TypeConverterAttribute(typeof(SecurityTargetTypeConverterEx)));
}
}
}
}
}
Visual BasicImports System
Imports System.Linq
Imports System.ComponentModel
Imports DevExpress.ExpressApp
Imports MainDemo.[Module].Reports
Imports DevExpress.ExpressApp.DC
Imports DevExpress.ExpressApp.Xpo
Imports System.Collections.Generic
Imports DevExpress.ExpressApp.Updating
Imports DevExpress.ExpressApp.ReportsV2
Imports MainDemo.[Module].BusinessObjects
Imports DevExpress.ExpressApp.Security.Strategy
Namespace MainDemo.[Module]
Public NotInheritable Partial Class MainDemoModule
Inherits ModuleBase
Public Sub New()
InitializeComponent()
End Sub
Public Overrides Sub CustomizeTypesInfo(ByVal typesInfo As ITypesInfo)
MyBase.CustomizeTypesInfo(typesInfo)
CalculatedPersistentAliasHelper.CustomizeTypesInfo(typesInfo)
SecurityTargetTypeConverterEx.TypesToBeExcluded.Add(GetType(MainDemo.[Module].BusinessObjects.Contact))
SecurityTargetTypeConverterEx.TypesToBeExcluded.Add(GetType(DevExpress.Persistent.BaseImpl.Country))
SecurityTargetTypeConverterEx.CustomizeTypesInfo(typesInfo)
End Sub
End Class
Public Class SecurityTargetTypeConverterEx
Inherits SecurityTargetTypeConverter
Public Shared ReadOnly TypesToBeExcluded As IList(Of Type) = New List(Of Type)()
Public Overrides Function GetSourceCollection(ByVal context As ITypeDescriptorContext) As List(Of Type)
Dim result As List(Of Type) = MyBase.GetSourceCollection(context)
For Each item As Type In TypesToBeExcluded
result.Remove(item)
Next
Return result
End Function
Public Shared Sub CustomizeTypesInfo(ByVal typesInfo As ITypesInfo)
Dim typeInfo As ITypeInfo = typesInfo.FindTypeInfo(GetType(PermissionPolicyTypePermissionObject))
If typeInfo IsNot Nothing Then
Dim memberBaseInfo As BaseInfo = TryCast(typeInfo.Members.First(Function(p) p.Name = "TargetType"), BaseInfo)
If memberBaseInfo IsNot Nothing Then
Dim typeConverterAttribute As TypeConverterAttribute = memberBaseInfo.FindAttribute(Of TypeConverterAttribute)()
If typeConverterAttribute IsNot Nothing Then
memberBaseInfo.RemoveAttribute(typeConverterAttribute)
End If
memberBaseInfo.AddAttribute(New TypeConverterAttribute(GetType(SecurityTargetTypeConverterEx)))
End If
End If
End Sub
End Class
End Namespace
Note: this approach allows you to write platform-agnostic logic only once. Also, in certain scenarios, you can use other specific approaches: SecurityStrategy.AdditionalSecuredTypes to add additional types in the current sample. In reporting and Pivot Chart analysis it is possible to decorate a business type with VisibleInReportsAttribute or manage the IModelClassReportsVisibility.IsVisibleInReports property in the Model Editor for that purpose.
2. UI PropertyEditor level
Since the System.Type properties are represented by the TypePropertyEditor, VisibleInReportsTypePropertyEditor classes for WinForms and ASPxTypePropertyEditor, ASPxVisibleInReportsTypePropertyEditor classes for ASP.NET in the XAF framework to build the resultant application UI, you can create descendants of these classes and override their virtual IsSuitableType method, which represents a predicate called for each checked type item before adding it into the editor control.
Refer to the eXpressApp Framework > Concepts > UI Construction > View Items > Implement Custom Property Editors article and see some pseudo-code at Q337620 for more implementation details.
Note: this approach requires you to write the same logic for each descendant, but you can write it only once in a separate method and then call it twice from two descendants of the standard PropertyEditor class for each platform without knowing details of control implementation for each platform.
3. UI control level
Since the System.Type properties are represented by ImageComboBoxEdit for WinForms and ASPxComboBox for ASP.NET in the resultant application UI, you can access these controls and customize their items directly in code of your ViewControllers. Refer to the Access Editor Settings article for more implementation details.
Note: this approach requires writing platform-dependent code. Despite its flexibility, it requires knowledge of each platform and their controls' low level implementation details as well as additional or different code for ListView/DetailView and other standard scenarios.
Hi,
In code of approach #1 first removed the old TypeConverter attribute then added the new one. It is ok but pay attention about the problem of adding back of removed attribute that is described in https://www.devexpress.com/Support/Center/Question/Details/T310890 ticket and fixed just in v2015 vol 2.5 of product.
Thanks for your helpful note, Sargis