xpo-403706-best-practices-wpf-best-practices.md
When you create data model classes for WPF applications, inherit XPO classes from the PersistentBase class.
It is not recommended to use the following classes as base classes:
Classes that inherit XPObject, XPLiteObject, XPCustomObject or XPBaseObject have the following limitations:
If you change a base class to PersistentBase, you can lose some functionaly. Follow the recommendations below:
The autoincrementing OID property.
The GetCollection method that is required to build a relationship between objects.
The EvaluateAlias method.
The code sample below shows how to implement a custom base class that enables only the required features:
using System.Runtime.CompilerServices;
using DevExpress.Data.Filtering;
using DevExpress.Data.Filtering.Helpers;
using DevExpress.Xpo;
using DevExpress.Xpo.Metadata;
//...
[NonPersistent]
[DeferredDeletion]
[OptimisticLocking]
public class BaseObject : PersistentBase {
public BaseObject(Session session) : base(session) { }
[Key(true)]
[Persistent("OID")]
private int fOid;
[PersistentAlias("fOid")]
public int Oid {
get => fOid;
}
public object EvaluateAlias([CallerMemberName] string memberName = null) {
XPMemberInfo mi = ClassInfo.GetMember(memberName);
PersistentAliasAttribute aa = (PersistentAliasAttribute)mi.GetAttributeInfo(typeof(PersistentAliasAttribute));
EvaluatorContextDescriptor descriptor = ClassInfo.GetEvaluatorContextDescriptor();
CriteriaOperator criteria = CriteriaOperator.Parse(aa.AliasExpression);
ExpressionEvaluator evaluator = new ExpressionEvaluator(descriptor, criteria, Session.CaseSensitive, Session.Dictionary.CustomFunctionOperators, Session.Dictionary.CustomAggregates);
return evaluator.Evaluate(this);
}
}
Imports System.Runtime.CompilerServices
Imports DevExpress.Data.Filtering
Imports DevExpress.Data.Filtering.Helpers
Imports DevExpress.Xpo
Imports DevExpress.Xpo.Metadata
' ...
<NonPersistent, DeferredDeletion, OptimisticLocking> _
Public Class BaseObject
Inherits PersistentBase
Public Sub New(ByVal session As Session)
MyBase.New(session)
End Sub
<Key(True), Persistent("OID")> _
Private fOid As Integer
<PersistentAlias("fOid")> _
Public ReadOnly Property Oid() As Integer
Function(get) fOid
End Property
Public Function EvaluateAlias(Optional <CallerMemberName> ByVal memberName As String = Nothing) As Object
Dim mi As XPMemberInfo = ClassInfo.GetMember(memberName)
Dim aa As PersistentAliasAttribute = CType(mi.GetAttributeInfo(GetType(PersistentAliasAttribute)), PersistentAliasAttribute)
Dim descriptor As EvaluatorContextDescriptor = ClassInfo.GetEvaluatorContextDescriptor()
Dim criteria As CriteriaOperator = CriteriaOperator.Parse(aa.AliasExpression)
Dim evaluator As New ExpressionEvaluator(descriptor, criteria, Session.CaseSensitive, Session.Dictionary.CustomFunctionOperators, Session.Dictionary.CustomAggregates)
Return evaluator.Evaluate(Me)
End Function
End Class
To bind a data-aware control to a collection of objects, use the ObservableCollection<T> class instead of XPCollection or XPView.
Use LINQ to XPO to populate ObservableCollection<T> with data.
// a helper method to support anonymous types
static ObservableCollection<T> ToObservableCollection<T> (this IEnumerable<T> en) {
return new ObservableCollection<T>(en);
}
// examples
var orders = session.Query<Order>().ToObservableCollection();
var customerNames = session.Query<Customer>()
.Select(c => string.Concat(c.FirstName, " ", c.LastName))
.ToObservableCollection();
Option Infer On
' a helper method to support anonymous types
_
Function ToObservableCollection(Of T)(ByVal en As IEnumerable(Of T)) As ObservableCollection(Of T)
Return New ObservableCollection(Of T)(en)
End Function
' examples
Private orders = session.Query(Of Order)().ToObservableCollection()
Private customerNames = session.Query(Of Customer)() _
.Select(Function(c) String.Concat(c.FirstName, " ", c.LastName)) _
.ToObservableCollection()
XPCollection does not raise the ListChanged event when a user changes an editor value if a persistent class is inherited from XPObject, XPLiteObject, XPCustomObject or XPBaseObject. As a result, other editors or controls bound to the modified property may display the previous value until the IEditableObject.EndEdit method is called.
XPView contains ViewRecords instead of XPO objects. This feature is not useful in MVVM applications where the business logic in a ViewModel requires a Model instance (an XPO object).