Simple binding using DevExpress XtraEditors and XPO Simplified Criteria Syntax
I posted the other day about using the XPO Simplied Criteria Syntax which is a CodeRush plugin that will generated a FieldClass for your XPO object. One of the main benefits I like is that you are using a strongly typed class which stops alot of issues (such as renaming your property or Case-Sensitivity) when having to use a String representation of your property.
Lets show some examples
When binding a control normally you would bind your control using the string representation of your objects property
TradingNameEdit.DataBindings.Add(New Binding("EditValue", Client, "TradingName"))
Now if we were to rename the TradingName property on our Client Object to say DisplayName we wouldn’t be presented with any errors in the IDE however would incur a runtime error when running the code, another issue that can commonly occur is the string representation is CASE SENSITIVE, so if you did the same line and say put the Property as “tradingname” it would also incur a runtime error.
Now let’s generate a FieldClass using the XPO Simplified Criteria Syntax plugin
TradingNameEdit.DataBindings.Add(New Binding("EditValue", Client, Client.Fields.TradingName.PropertyName))
Now the property is based on the FieldClass which is a static class which contains each of our properties. This is strongly typed so if I was to change my TradingName property to DisplayName and regenerate my FieldClass I would get compile errors as TradingName doesn’t exist anymore, the other advantage is I cannot stuff up the casing of the String as the returns the exact string representation of the property. One this is though that the FieldClass will return a XPO OperandProperty type, this is why we return the “PropertyName” property of the OperandProperty for the case of Databinding. This is a pretty long line so lets introduce a simple method that will do the large part of the work for us.
Introducing my Bind method
Private Sub Bind(ByVal control As Control, ByVal datamember As OperandProperty, Optional ByVal UseKey As Boolean = False)If TypeOf (control) Is DevExpress.XtraEditors.BaseEdit Thencontrol.DataBindings.Add(New Binding("EditValue", Client, datamember.PropertyName & IIf(UseKey, "!Key", "")))ElseIf TypeOf (control) Is DevExpress.XtraEditors.BaseControl Thencontrol.DataBindings.Add(New Binding("Text", Client, datamember.PropertyName & IIf(UseKey, "!Key", "")))End IfEnd Sub
This is designed to be used with DevExpress XtraEditors which all inherit from BaseControl and the Edits inherit BaseEdit (which inherits BaseControl). So it might not make perfect sense yet so I will provide the same binding above using this nifty method
Bind(TradingNameLabel, Client.Fields.TradingName)
How much easier was that. What happens here is I pass the control through to the method which then checks if it is a BaseEdit (ie. TextEdit, ButtonEdit, LookupEdit,ComboEdit etc) these all expose a EditValue to hold their value and should be the value you always use in your programming. Now there is another control I use for binding to and that is the LabelControl which doesn’t inherit from BaseEdit but rather directly from BaseControl. BaseControl has a “Text” property which is what is commonly used as a value for these types of controls.
Now you may ask about the UseKey argument I have in there, what this does is allow for situations whereby you may have a LookupEdit which doesn’t contain XPO Objects but rather a list of ID’s what we can do is assign the ID to the XPO objects Property and let the Object get the correct reference.
BACKGROUND: The XPO Session class is NOT thread safe, however there is a thread safe DataLayer. So you setup a Datastore then you can have an application wide ThreadSafeDatalayer for that Datastore. Then for each thread/instance you should use a seperate Session (keep in mind a Session may be of type Session or UnitOfWork (transaction based session)). So lets say in our application we can open multiple forms at once, if you used an application wide Session and both forms tried to obtain data you will end up with unexpected results and exceptions. The way to handle this is to have a Session per form/thread. This also applies to UserControls, as the UserControl can work independantly from the parent Form. One issue is you cannot mix objects between Sessions, ie. if you load an Object on Session1 and try to assign it to a property on an Object that was loaded on Session2 you will receive a SessionMixingException.
Scenario:
Lets say we have an application where the user can open multiple forms, when a frmClient opens up it sets up a new session for the form (lets call it SessionClient, this will be independant to any other instances of the frmClient that may be present), So lets say our Client Object has a Property called AccountManager which is a User Object type (User being another XPO Object in the project), now lets say in my application I load all my users into a XPCollection (based on a session created at program startup lets call it SessionMain) and use that as my Datasource of a LookupEdit on my form called AccountManagerEdit. The issue I have here is I can’t assign the Object from the XPCollection directly to my Client object as my Client and LookupEdit’s datasource are on two different Sessions. What we can do however is assign the ID to the Client.AccountManager field and the Client Object will use it’s session to obtain the User Object based on that ID.
So to make this work on your LookupEdit you need to set the Datasource to your XPCollection of User, set the DisplayMember to something like “Fullname” and the ValueMember to “ID” (this happens to be my Key field for the Object, XPObjects by Default use “Oid” it will depend on your object what you put here) then when we do the databinding we bind to the “AccountManager!Key” field which is a special binding method exposed by an XPObject. When the ID is assigned to the property the Client Object will use it’s Session and perform a GetObjectByKey(Of User)(<the new ID assigned>) and set the reference of that Object to the “AccountManager” property.
If we did have a XPCollection of User based on the same session as the Client then we could set the ValueMember to “This” and bind to the “AccountManager!” property, this will assign a reference of the selected object directly to the AccountManager property.
So our binding code is still simple to bind the Key to a Object
Bind(AccountManagerEdit, Client.Fields.AccountManager, True)
As I have written this I have just realised how much of a can of worms this opens when it comes to Session Mixing and Thread safety of XPO. Please comment if you have issues and I might follow up with a post on Session Mixing / Thread safety and what I do to avoid it.
Background: eXpress Persistent Objects (XPO) is a Object Relation Mapping (ORM) solution provided by DevExpress (DX), XPO is a Object->Database model (ie. You create strongly typed objects to which XPO will handle the persistance to a database store). XPO supports persisting to 16databases out of the box (although you can easily extend their DataStore classes to gain support for your database). See here for more details http://www.devexpress.com/Help/?document=XPO

Should AussieALF stay bald?
Latest Comments
- How to make XPO only...
Hi Sean, Very true ;) however keep in mi... More...
09-Apr-10 - How to make XPO only...
True, but it's worth noting that DX do ... More...
09-Apr-10 - How to make XPO only...
I would have to check with Gary, as alth... More...
09-Apr-10 - How to make XPO only...
Hi, I agree it seems like a "normal" thi... More...
09-Apr-10 - How to make XPO only...
Another question, how does it work with ... More...
09-Apr-10






Comments
Thanks for the comment,
In my particular bind scenario, I get a lookup list of Key,Title therefore I need the !Key so I can assign the ID of the record instead of the Object itself, the reason I did it that way is so I didn't have to load a full list of objects which was nearly 10 times as much data as a simple Key,Title list and also ensured I didn't have any issues with "SessionMixing".
Your mention of NestedUnitOfWor k reminds me that I am still overdue to produce that blog on it! :)
I will try and get onto that in the coming days, but correct, any object you assign to your objects property MUST be of the same Session.
Thanks for popping by.
RSS feed for comments to this post.