|
|
binding to business object with property datatypes as enum
Last post 10-22-2008, 10:53 AM by Shazam. 28 replies.
-
07-11-2007, 8:43 PM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
binding to business object with property datatypes as enum
I have a business object I want to use for binding. There are a series of combobox on the form that are populated via a bindingsource which sets the DataSource, DataMember, ValueMemeber. THis populates the combo with available values. Now, I bind all the controls on teh form to my business object. The BO has a property which I set to be bound to the SelectedValue of the combo. The property in question is defined as an enum. It seems like the binding mechanism cannot read/write from the property when defined as an enum. If I change it to Integer, it all works correctly.
Does anyone know the cause of this issue? Is there a work around or something I need to do to make this work? If I has to use integers for my properites, it will not be pretty, I have dozens of enums and the code will get very ugly fast.
Thanks in advance for any assistance you may provide.
|
|
-
07-11-2007, 10:59 PM |
-
hurcane
-
-
-
Joined on 05-08-2006
-
-
Posts 93
-
Points 1,320
-
|
Re: binding to business object with property datatypes as enum
Enums *are* integers. The enum values are only around in your source code. When it is compiled, they all become integers. Suppose you have an enum with members Red, White, and Blue. Red = 0, White = 1, and Blue = 2.
You probably want your enum options to display with a user-friendly value in the combo box (like Red, White, or Blue). I think you're going to need an additional object that represents the list of those values. I haven't tried this, but perhaps you could use reflection against the Enum to generate the list? I'm not sure if reflection will let you retrieve "Red" out of the enum type, but it could be worth exploring.
|
|
-
07-12-2007, 8:11 AM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
Re: binding to business object with property datatypes as enum
Hi,
Thanks for your reply.
So, what is happening is that I am not binding the combobox to the enum values. I am binding the combo box to a List object that contains the values loaded from the database. However, to represent the values loaded in the database, I use enums in the application.
So, for example I have,
Public Enum MyEnum
Red
White
Blue
End Enum
And in my business object, I have a property
public property SomeColor as MyEnum
Get...
Set...
End property.
I have a binding source that is set to an Object of a ReadOnlyList that is used to populate the combobox. Then, in my business object for the overall form, I have a property like above. I bind teh SelectedValue to the property in the Business Object so that when an object is being edited, the combobox shows the right value.
I put a breakpoint on teh Get and Set routine in teh property. When I change the value in the combobox, the set never gets called, but the Get is getting called 2 or 3 times. Then the form goes into a state where I cannot even take teh focus of the combobox in question, can't even close the form with the controlbox.
I am going to do some isolated testing today, but there seems to be a limitation here...hoping I am wrong though.
Rick.
|
|
-
07-12-2007, 10:47 AM |
-
david.wendelken
-
-
-
Joined on 06-14-2006
-
Addis Abeba, Ethiopia
-
Posts 494
-
Points 7,250
-
|
Re: binding to business object with property datatypes as enum
I'm a bit confused.
Enums are a static construct, and building a list of values from the database is, by definition, a dynamic thing to do. So I'm concerned about keeping the list of values in the enum the same as the list of items in the database. It just feels like a design mismatch to me.
Why not load an NVList (from NameValueListBase) from the database and bind it to the combobox? That's what it's for! :)
|
|
-
07-12-2007, 11:03 AM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
Re: binding to business object with property datatypes as enum
Hello,
Ok, so binding a list of items to the combobox is not the issue.
Yes, we have enums that are kept in sync with values from the database, good or bad, that is how it was done.
I bind the combobox based on an id that will give me a group of related possible values for a particular domain from the database (also b/c we are supporting multiple languages, this is in teh database). This is fine.
My issue is with the business object that has attributes of those enum types.
The business object has a property, for example, a car object, with a color property, wher the only options are red,white,blue as the enum above. So, when declaring the property on the Car object, it is delcared as the enum type. Why? So that when developers are coding against the property, they immediatly see the options for the enum...this is very common practice throughout the entire .Net framework.
So, I have a winform to manage my 'car' object. I use a combobox to give the user the limited choices they have on colors. I load the available values from the database in teh appropriate language for the user. I bind all the controls on my winform to by Car object. The combobox selected value is bound to the color property whose datatype is defined as the colors enum above.
The winform is not behaving nicely in this situation. It is not calling the Set on teh property when the value is changed. It is calling the get,but not changing the value in the combobox based on teh value of the property when the property datatype is the enum.
Please note that my issue has nothing to do with loading the combobox, it has to do with binding the comboboxes on the form to properties of my business object.
|
|
-
07-12-2007, 11:35 AM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
Re: binding to business object with property datatypes as enum
I know this is down the path of a general .Net thing now, but I am trying to do a proof of concept with the CSLA framework with our existing application. And this is how I came accross this. Here is a sample app I whipped up that will demonstrate the problem.
Public Enum MyEnum
One = 1
Two
Three
Four
End Enum
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sortedList As Collections.ArrayList = New ArrayList
sortedList.Add( New myItems(-1, ""))
sortedList.Add( New myItems(1, "One"))
sortedList.Add( New myItems(2, "Two"))
sortedList.Add( New myItems(3, "Three"))
sortedList.Add( New myItems(4, "Four"))
ComboBox1.DataSource = sortedList
ComboBox1.DisplayMember = "Value"
ComboBox1.ValueMember = "Key"
Dim _bo As MyBO = New MyBO()
MyBOBindingSource.DataSource = _bo
End Sub
Public Class myItems
Private Dim _key As Integer
Private Dim _value As String
Public Property Key() As Integer
Get
Return _key
End Get
Set(ByVal value As Integer)
_key = value
End Set
End Property
Public Property Value() As String
Get
Return _value
End Get
Set(ByVal value As String)
_value = value
End Set
End Property
Public Sub New(ByVal key As Integer, ByVal value As String)
_key = key
_value = value
End Sub
End Class
End Class
Public Class MyBO
Public Property X() As EnumClassLibrary.MyEnum
Get
Return _x
End Get
Set(ByVal value As EnumClassLibrary.MyEnum)
_x = value
End Set
End Property
Private _x As EnumClassLibrary.MyEnum
Public Sub New()
X = EnumClassLibrary.MyEnum.Four
End Sub
|
|
-
07-12-2007, 12:15 PM |
-
lprada
-
-
-
Joined on 07-05-2006
-
-
Posts 21
-
Points 405
-
|
Re: binding to business object with property datatypes as enum
How do you bounf to the selecedvalue of the combo?
|
|
-
07-12-2007, 12:52 PM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
Re: binding to business object with property datatypes as enum
I am binding using the propeties window - Data - Data Bindings - SelectedValue and setting the SelectedValue to MyBOBindingSource.PropertyName.
So, from the SelectedValue property under data bindings, a data source has been created bound to my business object. I then use this binding source to bind to all the controls.
|
|
-
07-12-2007, 1:49 PM |
-
ajj3085
-
-
-
Joined on 05-05-2006
-
Vermont
-
Posts 2,883
-
Points 44,050
-
|
Re: binding to business object with property datatypes as enum
That's not quite true; enums are first class members. by default, using an enum will have the actual enum name display in the combobox, if you were to databind them. In other words, Red, White and Blue woudl be displayed, not 0, 1, or 2.
Also, not all enums are ints; you CAN create enums which inherit from short or long, as you need, although I think that's discouraged.
|
|
-
07-12-2007, 4:48 PM |
-
dshafer
-
-
-
Joined on 10-09-2006
-
-
Posts 37
-
Points 590
-
|
Re: binding to business object with property datatypes as enum
Rick,
I have a similar setup to yours where I have a "lookup" table in the database with values to populate combo boxes. I also have corresponding enums with these "lookup" values. As far as I know, it is not possible to bind a combobox directly to an enum property. I'm assuming that your business object also stores the database id of the lookup item that was selected so that it can be persisted back to the database. What I do is bind the combobox to this lookup id property on the business object. Then in the get accessor of the enum property I call a static/shared helper method that "maps" the database id of the lookup item to the correct value in the enum. So your get accessor for the enum property on the business object would look something like this (c#):
public MyEnum SomeColor { get { return EnumHelper.GetMyEnumValue(m_colorId); } }
The implementation is a little tedious, but it gets the job done. It's also much better than looking at code like this:
if (m_colorId == 1) && 1 stands for Red
If anybody knows a better way, please let us know.
Dustin
|
|
-
07-12-2007, 5:18 PM |
-
RockfordLhotka
-
-
-
Joined on 04-19-2006
-
Eden Prairie, MN, USA
-
Posts 3,812
-
Points 64,450
-
|
Re: binding to business object with property datatypes as enum
Why not wrap the enum in a NVL? In other words, create an object that inherits from NVLB, where the DataPortal_Fetch() method merely loads the list from the enum. You can enumerate the values in an enum (using reflection if nothing else).
Given an enum like
public enum MyEnum { Red, Blue, Green }
You'd have a class like:
[Serializable] public class MyEnumList : Csla.NameValueListBase<MyEnum,string> { public static MyEnumList GetList() { return Csla.DataPortal.Fetch<MyEnumList>(new Criteria(typeof(MyEnumList))); }
private MyEnumList() { /* require use of factory method */ }
[Csla.RunLocal] protected override void DataPortal_Fetch(object criteria) { this.IsReadOnly = false; foreach (MyEnum item in Enum.GetValues(typeof(MyEnum))) Add(new Csla.NameValueListBase<MyEnum, string>.NameValuePair( item, Enum.GetName(typeof(MyEnum), item))); this.IsReadOnly = true; } }
Then you can bind it like you'd bind any other object/list to a combobox, as long as the object's property is of type MyEnum:
MyEnum _color; public MyEnum Color { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] get { CanReadProperty(true); return _color; } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] set { CanWriteProperty(true); if (!_color.Equals(value)) { _color = value; PropertyHasChanged(); } } }
Rocky
|
|
-
07-12-2007, 8:50 PM |
-
rd_bigdog
-
-
-
Joined on 07-12-2007
-
-
Posts 14
-
Points 220
-
|
Re: binding to business object with property datatypes as enum
Hey Rocky, In summary, that code worked perfectly. After analyzing my problem set more after I got a sample project working with it, I added a few requirements to my list. I follow the pattern you posted. But, in my case, I have a 'master' enum which is an enum of all the available enums that we have. When I say enums in this context I am referring to different domain of lookup values. So, I have an enum of all lookup value types, and enums of each individual lookup. In total, dozens upon dozens of enums -- lots of entities managed in this system. So, I wanted to make your code sample generic so that I only had one class to deliver my lookups to the UI, and not one class per lookup/enum. I managed to get this to work, it wasn't too tricky, I will post the code here as I think the pattern might help others. I have custom combobox that is dedicated to showing the lookup values based on the enums. I gave it a property with the type of the "master' enum so that a consumer can pick the lookup domain to popluate the box with:
Protected Overrides Sub OnCreateControl()
MyBase.OnCreateControl()
For Each bindings As System.Windows.Forms.Binding In DataBindings
bindings.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
Next
If Not Me.DesignMode Then
Me.DataSource = AMSCSLA.ValueList.GetValueList(AMSDomain)
Me.DisplayMember = "Value"
Me.ValueMember = "Key"
End If
End Sub
Public Property AMSDomain() As AMS.Framework.AMSDomains
Get
Return _amsDomain
End Get
Set(ByVal value As AMS.Framework.AMSDomains)
_amsDomain = value
End Set
End Property
In here, pass the master domain type to my NVL. In my NL I do this:
Public Shared Function GetValueList(ByVal domain As AMS.Framework.AMSDomains) As ValueList
Return Csla.DataPortal.Fetch(Of ValueList)(New DomainCriteria(domain))
End Function
Protected Overloads Sub DataPortal_Fetch(ByVal thecriteria As DomainCriteria)
Me.IsReadOnly = False
Dim enumName As String = [Enum].GetName(GetType(AMSDomains), CType(thecriteria.Domain, Integer))
Dim enumTypeHandle As System.Runtime.Remoting.ObjectHandle = System.Activator.CreateInstance("AMS.Framework", "AMS.Framework.AMSDomainValues." & enumName)
Dim enumType As [Enum] = CType(enumTypeHandle.Unwrap(), [Enum])
For Each item As Object In [Enum].GetValues(enumType.GetType)
Add( New Csla.NameValueListBase(Of [Enum], String).NameValuePair( _
item, [Enum].GetName(enumType.GetType, item)))
Next
Me.IsReadOnly = True
End Sub
Protected Class DomainCriteria
Public Property Domain() As AMS.Framework.AMSDomains
Get
Return _domain
End Get
Set(ByVal value As AMS.Framework.AMSDomains)
_domain = value
End Set
End Property
Private _domain As AMS.Framework.AMSDomains
Public Sub New(ByVal domain As AMS.Framework.AMSDomains)
_domain = domain
End Sub
End Class
End Class
I use a little reflection to create an insance of the type of enum specified by the domain (this makes a requirment that the text of the master domain match the actual domain, but that will be managable). I will have left to do after this is add in a call to my lookup table to get the string text for the NVL in the users culture so the UI displays correctly and to sort the values by that text.
Thanks very much for your post, you definitely got me down the right path.
Regards,
Rick.
|
|
-
07-13-2007, 9:15 AM |
-
dshafer
-
-
-
Joined on 10-09-2006
-
-
Posts 37
-
Points 590
-
|
Re: binding to business object with property datatypes as enum
Wow. That's a pretty good idea. I'll have to try to modify my system to use something like this. It's quite a bit less tedious than what I'm currently using.
Dustin
|
|
-
04-02-2008, 7:55 PM |
-
Dave Boal
-
-
-
Joined on 08-04-2007
-
-
Posts 4
-
Points 45
-
|
Re: binding to business object with property datatypes as enum
Here's another suggestion:
I created a class called EnumNVL which creates a NameValueList from any Enum Type.
Sample Usage in form:
EnumNVL envlDateRangeTypes = EnumNVL.GetEnumNVL(typeof(DateRangeType)); // The parameter for the GetEnumNVL() method is any valid Enum, ie., GetEnumNVL(typeof(AnyValidEnum)). // The substitutable parameter in this example uses the Enum type "DateRangeType".
cbxDateRangeTypes.DataSource = envlDateRangeTypes cbxDateRangeTypes.DisplayMember = "Value"; cbxDateRangeTypes.ValueMember = "Key"; cbxDateRangeTypes.SelectedIndex = 0;
Here's is the EnumNVL class:
[Serializable] public class EnumNVL : Csla.NameValueListBase<Enum, string> { private static Type _Type = null; public static EnumNVL GetEnumNVL(Type type) { _Type = type; return Csla.DataPortal.Fetch<EnumNVL>(new Criteria(typeof(EnumNVL))); }
private EnumNVL() { /* require use of factory method */ }
[Csla.RunLocal] protected override void DataPortal_Fetch(object criteria) { this.IsReadOnly = false; foreach (Enum item in Enum.GetValues(_Type)) Add(new Csla.NameValueListBase<Enum, string>.NameValuePair( item, Enum.GetName(_Type, item))); this.IsReadOnly = true; } }
-- Update:
Cine's brilliant generic version below is a great modification. Here is an example of how I use his code:
EnumNVL<DateRangeType> enumNVL = EnumNVL<DateRangeType>.GetEnumNVL();
// The KEY POINT is that with your more general code, I can cast the type to int as follows: int dbColumnValue = (int)enumNVL[0].Key;
// I could not do that cast with my code!
|
|
-
04-02-2008, 11:12 PM |
-
Cine
-
-
-
Joined on 03-26-2008
-
HCMC, Vietnam
-
Posts 17
-
Points 250
-
|
Re: binding to business object with property datatypes as enum
Even more general:
class Program { static void Main(string[] args) { foreach (NameValueListBase<hest, string>.NameValuePair s in HestNVL.GetEnumNVL()) Console.WriteLine(string.Format("{0} {1}", (int)s.Key, s.Value)); } } [Serializable] public class EnumNVL<T> : NameValueListBase<T, string> { public static EnumNVL<T> GetEnumNVL() { return DataPortal.Fetch<EnumNVL<T>>(new Criteria(typeof(T))); }
protected EnumNVL() { /* require use of factory method */ }
[RunLocal] protected override void DataPortal_Fetch(object criteria) { Criteria c = (Criteria)criteria; IsReadOnly = false; foreach (T item in Enum.GetValues(c.ObjectType)) Add(new NameValuePair(item, Enum.GetName(c.ObjectType, item))); IsReadOnly = true; } } [Serializable] public enum hest { red, green } [Serializable] public class HestNVL : EnumNVL<hest> { }
|
|
Page 1 of 2 (29 items)
1
Please contact Magenic for your .NET consulting and CSLA .NET mentoring needs. |
Please consider making a donation to help support the ongoing development of CSLA .NET. Why donate?
|
|
|