Wednesday, December 09, 2009

Leaping into BDD

As this title says Leaping into BDD I have plunged in to learn about and use BDD.  My experience with it is new and I don’t claim to know everything about BDD.  With this said if you have some more insight or explanations you want to indulge us with please don’t hesitate to broaden our knowledge by sharing yours. 

We have all heard of Test Driven Development (TDD) and many of us have used it.  I’m going to tell you about a newer type of development out that in my opinion produces a much easier flow.  The new development is called Behavior Driven Development or BDD.  BDD is exactly as it is named, it specifies your code from a behavioral approach.  By the time we start to code we know what we want the project to do because we have already thought this out by now.  So using BDD we can write specifics to guide our code.  As an example, lets say we are writing a notepad application.

Our specifics may look something like this:

Open Text File for Editing
    - File Open Dialog with Filters
    - Content of file is extracted and placed onto Rich Text Box
Save Changes
    - Collect text and save back to opened file
Close Notepad
    - Check for changes made
        - if changes prompt user
    - Cleanup code
    - Close application

These specifications are pretty straight forward; we are thinking like a human and how a human would use our application.  In these scenarios we would have the option to open a file; OK, after the file is opened what do we do? Well according to our specs we can save the file, and we can close the application.  During a close we are showing that our application should check for changes and prompt the user if any exist.  Handle our cleanup of code and resources, then close the application.  Pretty straight forward right?

To get started using BDD you must first get the following:

- MSpec (Machine.Specifications)
- TestDriven.Net Personal/Professional (Not Required but good for running your test)

 

Once you have downloaded MSpec and unzipped, you will have something like this:

MSpecDir

 

Double click on the build batch file to run the compiler against the code and output the assemblies we need.
Note: You may receive errors on Resharper if you don’t have that installed, don’t worry about those.  You may also have to open the solution in Source and manually compile.

Lets get started by opening Visual Studio, I’m going to create a class called BDD to hold our properties.  But first before I do that I need to know my specifications, lets do that:

BooleanProp is true
- DoubleProp must be greater than 0
- IntegerProp must be 0
BooleanProp is false
- DoubleProp must be 0
- IntegerProp must be greater than 0

So I know I will have 3 properties, BooleanProp, IntegerProp, and DoubleProp.  First context I am saying if the BooleanProp is set to true then DoubleProp must be greater than zero and IntegerProp must be zero.  With this said, lets create a class with these properties.

public class BDD
{
private int _IntegerProp;
public int IntegerProp
{
get { return _IntegerProp; }
set
{
_IntegerProp = value;
}
}

private double _DoubleProp;
public double DoubleProp
{
get { return _DoubleProp; }
set
{
_DoubleProp = value;
}
}

private bool _BooleanProp;
public bool BooleanProp
{
get { return _BooleanProp; }
set
{
_BooleanProp = value;
}
}
}


Now that I have my class I’m going to write out the specifications in code.  I start by created a class, ill call it BDDSpecifications.



using Machine.Specifications;

public class BDDSpecification
{
/*
* BooleanProp is true
* - DoubleProp must be greater than 0
* - IntegerProp must be 0
* BooleanProp is false
* - DoubleProp must be 0
* - IntegerProp must be greater than 0
*
*/

[Subject("BooleanProp is true")]
public class When_BooleanProp_is_true : BDDClass
{
Because of = () =>
{
testClass.BooleanProp = true;
};

It should_have_doubleProp_GreaterThanZero = () =>
{
testClass.DoubleProp.ShouldBeGreaterThan(0);
};

It should_have_integerProp_equal_zero = () =>
{
testClass.IntegerProp.ShouldEqual(0);
};
}

[Subject("BooleanProp is false")]
public class When_BooleanProp_is_false : BDDClass
{
Because of = () =>
{
testClass.BooleanProp = false;
};

It should_have_doubleProp_equal_zero = () =>
{
testClass.DoubleProp.ShouldEqual(0);
};

It should_have_integerProp_GreaterThanZero = () =>
{
testClass.IntegerProp.ShouldBeGreaterThan(0);
};
}

public abstract class BDDClass
{
protected static BDD testClass;
Establish context = () =>
{
testClass = new BDD();
};
}
}


Here you can see my specifications in code.  I have an abstract class, this is not required but prevents me from having to create the BDD class for each test.  Notice my classes inherit the BDDClass.  Looking at the code you might be a little nervous, don’t be.  The code is actually very simple,



Because of Something, It should have/do this, It should have/do that, etc, etc, etc.



 



If you did not install the TestDrive.Net, no problem.  When you compiled the source for MSpec an executable was generated called mspec in the build output.  Open your Tools->External Tools, click on Add.



Parameters:



Title: Add a title

Command: The path to the mspec.exe file


Arguments: $(TargetName)$(TargetExt) --html $(ProjectDir)Reports\report.html  
(Note: By adding the –-html “Report Path” an html file will be created for you with the results.  The html part is not required.)


Initial Directory: $(BinDir)



image



 



Now that you have your specifications all laid out, lets run this.  I'm going to run using the MSpec option.




My Results:


image



I have 2 that failed which I expected.  To make these pass I need to make some changes.



public class When_BooleanProp_is_true : BDDClass
{
Because of = () =>
{
testClass.BooleanProp = true;
testClass.IntegerProp = 0;
testClass.DoubleProp = 2;
};







I made a simple change to both classes and got the following results:





image



 



All specifications passed!! The report generated is a nice addition that can be printed and handed over to your PM.



 



Happy Coding…

Tuesday, November 03, 2009

Downloading a PDF from Stream using XAF

At times you need to deliver PDF content or any content for that matter and the option to save the streams to a file and download are not always ideal. If your an XAF user and need to accomplish such a task here is how to do it. As we know downloading from a Stream is handled using an IHttpHandler along with an ashx file used to direct the user for downloading. To get started, first create an IHttpHandler. Set the IsReusable to false.

public bool IsReusable
{
get { return false; }
}


In the ProcessRequest do the following:


public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/pdf";
DevExpress.Xpo.IDataLayer dataLayer = XpoDefault.GetDataLayer(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString, DevExpress.Xpo.DB.AutoCreateOption.SchemaAlreadyExists);
using (DevExpress.Xpo.Session session = new DevExpress.Xpo.Session(dataLayer, null))
{
DataObject myDatasource = session.FindObject(new BinaryOperator("Oid", new Guid(context.Request.Params["oid"])));
context.Response.AddHeader("Content-Disposition", "attachment; filename=MyPDFName.pdf");
context.Response.BinaryWrite(myDatasource.PDFBlogField); // byte[]
context.Response.End();
}
}


Now that you have your handler done, lets get the ASHX file using it.

Create a Text File in your Project.Web project and rename it to PDFStream.ashx (Or whatever you want to name it), then add the following: (Replace Class with your NameSpace and class name)
Note: I usually create a Custom folder to keep track of these pages since they are not part of XAF themselves


<%@ WebHandler Language="C#" Class="Project.Web.Module.Handlers.MyPDFHandler" %>


This points your ashx file to the handler which will take care of passing the stream to your user.

When you have that ready, the next step is to create the Controller that will call this file.

In your Project.Web.Module project, add a controller. Set the TargetObjectType in the constructor to your class type which this will be used for. Add a SimpleAction to your controller and set the TargetObjectType for the action. Subscribe to the Execute event and add the following:


private void btnShowPDF_Execute(object sender, SimpleActionExecuteEventArgs e)
{
if (View.CurrentObject != null)
{
WebApplication.Redirect(String.Format("~/Custom/PDFStream.ashx?oid={0}", ((DataObject)View.CurrentObject).Oid));
}
}


And thats it, your action will direct the user to the ashx page which will return a file attachment to the user. Don't worry, the user will not be directed away from the current page, and the best part is you dont have to write files to the disk on your server.

Thursday, August 27, 2009

The Need for Cloning an Object

I am working on a project in XAF and came into the need of cloning an object but needed to exclude certain properties.  I looked into the CloneHelper but it didn’t do what I needed.  So I wrote a simple method to handle this requirement.  A few things to know, any properties that are readonly do not need to be included in the exclusion.  Also the Oid property (is readonly) does not need to be excluded.  So to get this working, copy the code:

public static T CloneObject<T>(T sourceObj, T destObj, params string[] excludeProperties)
{
// Get the properties of the Source Object
PropertyInfo[] propCollection = sourceObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (PropertyInfo pInfo in propCollection)
{
// Exclude any properties from the exclude list
if (Array.Find<string>(excludeProperties, val => val.Equals(pInfo.Name)) == null && !pInfo.IsDefined(typeof(NonCloneableAttribute), false))
{
PropertyInfo tmpProp = destObj.GetType().GetProperty(pInfo.Name);
if (tmpProp.CanWrite)
tmpProp.SetValue(destObj, pInfo.GetValue(sourceObj, null), null);
}
}

return destObj;
}


To use this method, simply create the object that will become the cloned object and pass the source like so:



public static MyClonedObject CloneLineItem(DevExpress.Xpo.Session session, MyClonedObject sourceLineItem, params string[] excludeProperties)
{
MyClonedObject clonedLineItem = new MyClonedObject(session);
return CloneObject<MyClonedObject>(sourceLineItem, clonedLineItem, excludeProperties);
}


Create a simple method like above and pass something like:



MyClonedObject clone = CloneLineItem(this.Session, this, "Parent", "Total", "Payments");


In this example the properties Payments, Total, and Parent will be ignored when cloned.  I could have also just called it without any exclusions like so:



MyClonedObject clone = CloneLineItem(this.Session, this);

If this helps you out let me know…


Updated: Added support for the NonCloneableAttribute attribute.



Happy Coding!!

Monday, June 29, 2009

Using a bit column to hold 30+ Checkbox values

 

Sometimes your asked to design an application that will contain ‘X’ number of checkboxes.  The DBA is a hardball and tells you no way am I creating 30 columns for your checkboxes, ill create one and you figure it out.  What a punk but lets see what we can do about this.  We could do one of two things, we could have the DBA create a vertical approach where we store the value of each checkbox in its own row, or we can have the DBA create a bit column and we bit flag this baby.  Well being the title of this article has “bit column”, you know what I’m going to talk about.  That’s right, we are creating a bit column.  Just a tad bit about bit flags since we are not really focused on explaining them in this article is that they are powers of 2.  Meaning our values stored as enums will increment to the power of 2 starting with the value 1.

Example:

public enum CheckBoxValues
{
first = 1,
second = 2,
third = 4,
fourth = 8,
fifth = 16,
sixth = 32,
seven = 64,
eight = 128,
nine = 256
}


So here we show only 9 values, you however would continue on down the path of 30 as per this title.  But for clarity we will keep this simple.  Seeing that our values of the enum go from 1-256 does not mean your values will be stored in the db this way.  These are flag values using the power of 2, our db values will be the int value of the enum.  So “first” int value is 1 and “nine” int value is 9.  Now that we have that clear lets move on.



Ok, so we now have a bit column called “CheckedValues”, sounds good to me.  We need to store all our check box values into this one column.  The way we handle this is we treat the checkbox checked value as its enum value.  So for example we would have a check box called chkFirst and its checked value would be 1, chkNine would have a checked value of 9 and so on.  The checked values must match or be handled as the enum value (such as (int)CheckBoxValues.third will return 3).  This is important because we need to sum these values up.  So assume we are done and have all our checkboxes in place.  We are now ready to store/retrieve these values.  When the save button is hit, your code will then iterate through the checked check boxes and sum up their values.  So lets say first, second, and fourth are checked then our value would be 7 that gets stored in the database (1+2+4 = 7).



Setting the checkbox check state from the db value is just as easy.  Create a simple method like so:



private bool IsChecked(int dbValue, int enumValue)
{
return ((dbValue & enumValue) == enumValue);
}


Then you would simply handle the checked value like:



chkFirst.Checked = IsChecked(7, (int)CheckBoxValues.first);
chkSecond.Checked = IsChecked(7, (int)CheckBoxValues.second);
chkThrid.Checked = IsChecked(7, (int)CheckBoxValues.third);
chkFourth.Checked = IsChecked(7, (int)CheckBoxValues.fourth);
...


I am passing 7 since that is what the DB Value is in our example.  How is this working? Well its actually quite simple.  We are getting the BitAnd value of the enum and checking if its turned on in our db value.  So what is happening in the backend is something like this.  The binary value of 7 is 0111.  The IsChecked method is comparing this value to the passed enum flag value.  So a check looks something like this for second: 0111 & 0010 == 0010.  It passes because the 1 & 0 = 0 and 1 & 1 = 1.  So 0111 & 0010 does in fact = 0010 because starting from right to left we see 1 & 0 = 0, 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, total that up and we get 0010 (Remember I went right to left, so do the same totaling).  So that tells us this flag is on so check the checkbox.  The value 7 would check our 1, 2, and 4 enum values.  The exact ones we checked.  If the db value is 5 then first and fourth would be checked and so on.  This is a 32 bit column so naturally you could only store 32 bits of values in it but 30 checkboxes would easily fit in just one column.



 



Hope this helps you out there.

Thursday, June 18, 2009

Shrink those Urls

 

Those using twitter know about the benefits of shrinking a url to reduce character count, a tweet is limited to 140 characters so each letter matters.  Being a tweeter myself I tend to use tinyurl like most people out there.  It is the most popular for shrinking urls on twitter today. 

What if you wanted to not only shrink your urls but also track data about the urls you shrink.  Data such as where the person that clicked your links location is; or how many times they have clicked the link perhaps to show another colleague.  A nice solution that I found out there written by Andy Meadows is www.budurl.com.  This site is well laid out and tracks some very useful information.  I noticed AMD is one of their customers so I assume I am not alone in liking the service. 

A video is located on their home page which shows us some of the features, you can see it here:

BudURL Demo from Andy Meadows on Vimeo.

 

This is one of many great sites out there that shrink our urls to save space.  The benefit to budurl.com is the addition of the marketing data collected that can assist your business in understanding who and where is viewing your site and how many times they have visited.  They have an enterprise version which allows you to use what ever url domain you want which is also very cool.

Tuesday, June 09, 2009

Windows 7 RC Experience Thus Far

 

I have been using Windows 7 now for about 1 month or so and I must say I really like it.  I was once on Vista and never more after seeing the light of an OS that does not slow me down.  On another note, the system I installed Windows 7 on is my new Alienware Laptop which has also been doing very well after the upgrade.  I have experienced some freezing of the system twice now, albeit that is better than how it was with Vista which was becoming a 3-5 time a day experience.  I haven’t really done much with the XP theme on individual applications nor have I dove into the VM of Windows 7 but I am enjoying the user experience I get with this OS and plan to upgrade the other 3 boxes with it when it comes out, or not.  I still haven’t decided what to do with my older machines.

Monday, June 08, 2009

XAF Custom Rule for Conditionally Required Properties

 

For those of you using DevExpress XAF (eXpressApp) you may have come across the need for making a Domain Object property conditionally required.  For Example, lets say you have a Domain Object with 3 properties (FirstName, LastName, and Phone) and you want Phone to be required only if FirstName and LastName are not null. How do you do it in XAF? Well I have a solution for you.  Simply download the source and apply the RuleConditionalIsRequiredAttribute to your properties like so:

[DefaultClassOptions]
public class TestRule : BaseObject
{
public TestRule(Session session) : base(session) { }

...

private string phone;
[RuleConditionalIsRequired("Phone is Required", DefaultContexts.Save, "!String.IsNullOrEmpty(FirstName) && !String.IsNullOrEmpty(LastName)", "Phone is required when First Name and Last Name are added.")]
public string Phone
{
get
{
return phone;
}
set
{
SetPropertyValue("Phone", ref phone, value);
}
}
}




As you can see you are writing C# code as the condition, I haven't tested in VB but since its using lambda expressions to compile this condition I'm sure it will work (I hope at least for VB coders).  It works great in my C# applications.  Your condition has to return bool and can only be used for properties.  The method CheckCondition will build a lambda expression and execute it against your class instance.  If the condition returns true then this property is required, otherwise it is not required.  The lambda expression class was developed by Microsoft and distributed with Visual Studio 2008 as a Sample application on using LAMDBA Expressions.



Now when we run this we get the following error: ValidationError



The Full Source is attached.



I hope this helps someone.



Happy Coding!!! Download Source Here

Sunday, May 03, 2009

Alienware Laptop Purchase

Well I got my new laptop, I’ve had it about 3 weeks now and unfortunately its completely frozen up on me about 7 times.  I have made a call to support and they thought maybe the memory was not seated correctly so we went through the routine of stress testing the system checking each memory slot individually.  Nothing came of it, the system only froze a couple of times but not consistently while testing.  Well sadly its still freezing up on me.  I hope the next call is more productive and we get this thing running as it should be.  Don’t get me wrong, this machine is a champ while its running, I would like to keep it running; not asking too much.

Thursday, April 30, 2009

ASP.NET DIY Intellesence

As a time killer I decided to figure out a way to incorporate intellesence into an ASP.NET application.  Note this is something I worked on for a few hours without time to refactor; there could also be better ways to accomplish this.  I used jQuery to handle all my javascript needs and just your basic .NET standard TextBox and ListBox.

What exactly does this do?

Well first of all I must instill again that this is basic; you can take this code and modify it to fit your needs.  This simply renders your basic intellesence from a populated listbox.  Being that it is not complete, if someone would like to take the reigns and send me the code changes to re-publish that would be great too.  My email is gary.l.coxjr at gmail dot com.

Current Known Problems:

  • Intellesence is not showing below the text
  • Intellesence only displays when the OemPeriod is pressed ‘.’ (would be nice to be able to press “Ctrl”+”Shift”+”Space”)
  • Select from list as you type is not perfect (Doesn’t always find the right item)
  • Double-Click on listbox does not post to textbox

Please keep in mind this is NOT production code and shall not be used as such.  You may use this at your own risk.

What can be done to make this more useful?

Since the intellesence works off the listbox, any ListItems you load in there will be displayed when a period is pressed.  Whatever is selected in the listbox when you hit “Space” or “Enter” is what will be entered after the period in the textbox.  If you populate it with a list of object properties, like in my example of class Person, when a user types Person and then hits the period they will be presented with the pre-populated properties that can be selected.

The Javascript can be found in AspxIntellesence.js file located in ~/JS directory.

Here is what we see:

Intellesence

Notice I started to type “S” and the intellesence moved to StreetAddress.  If I had pressed the space bar then you would get Person.StreetAddress as the javascript would handle this.

What is this useful for anyway?

Well I think it could be very useful if your designing a template builder that allows your users to design custom email messages, or campaigns.  This type of tool would allow your customer to build the template and from your backend code process it from a given business object.  Take my example, assume I had a class named Person and the above template was processed.  I could send personalized emails to a select group that may look like:

Welcome Gary Cox,
    We have your current street listed as 123 Some Street.

Simply by parsing out the [object property] and replacing with its value of the current instance.

As always, I hope this helps someone.  Happy Coding!!!

 

Download Source Code

Wednesday, April 22, 2009

A Hidden Gem when it comes to string separation

Most developers based on code I have seen separate strings like so:

for (int i=0; i<someData.Count; i++)
myStringBuilder.AppendFormat("{0},", someData[i]);

Then after constructing this string they need to remove the last separator

myStringBuilder = myStringBuilder.Remove(myStringBuilder.Length-1, 1);

I too have used this concept. However, there is another way to do this that a lot of people didn’t even know existed. The String.Join class; it takes 2 params, the separator and the array.

ArrayList<String> myList = new ArrayList<String>();
for (int i=0; i<someData.Count; i++)
myList.Add(someData[i]);
return String.Join(",", myList.ToArray());


This would return a string separated by a comma such as “Text,MoreText,EvenMore,AndLast”

Monday, April 20, 2009

Going to twitter

Well I jumped on the band wagon and started using twitter.  I must say I really like it; firing off a quick text message type snippets of what you need and someone out there responds.  It’s very easy to use and didn’t take me long to understand the lingo.  When you want to send a tweet to someone you simply place a ‘@’ and their name, for example I am @GaryLCoxJr.  See you out there on twitter :)

Friday, April 17, 2009

Fade Form on Move or Resize



I had a project where we display a form to a user and perform a certain task. Well the user wanted to be able to fade the form when they move it or resize it so they can see the underlying (Main) form.  This is simple but thought since my blog has been out of date for some time now I should add something to it.


To get started, add the following to your form that you want to handle the fade or add to your constant class:

// Called when a Resize or Move loop has ended
const int WM_EXITSIZEMOVE = 0x0232;

// Called at the beginning of a Resize Move loop
const int WM_ENTERSIZEMOVE = 0x0231;


Next, override the WndProc method of your form like and handle the fade of your choice:

protected override void WndProc(ref Message m)
        {
            // Check if user is/isn't dragging the form
            switch (m.Msg)
            {
                case WM_ENTERSIZEMOVE:
                    // Form is being Moved or Resized, set opacity
                    this.Opacity = 0.65;
                    break;
                case WM_EXITSIZEMOVE:
                    // Form is done moving/resizing, set opacity back to 100%
                    this.Opacity = 1;
                    break;
            }

            base.WndProc(ref m);
        }


And thats it, when you move or resize the form the opacity will drop to 65%.  Once the resizing or moving is complete the form will return to 100% opacity.

Load an Xml File into a Class Collection using LINQ


Work a lot with Xml using the C# language? You will know that to load an Xml
file it can be quite extensive at times depending on how deep your requirements
send you. I personally prefer to work with classes that are populated with the
data from the Xml and bind my controls to such. I have put together a simple
example of loading data from an xml and building a collection of a given class.
Then binding a combobox to this list.


Here is my Xml file:
xmlversion="1.0"encoding="utf-8" ?>
<StageTypes>
<StageTypename="SUB">
<StageItemvalue="CP">Customer PlanStageItem>
<StageItemvalue="FF"> ContactStageItem>
<StageItemvalue="OC">Other ContactStageItem>
<StageItemvalue="MD">Medical/DentalStageItem>
<StageItemvalue="LG">LegalStageItem>
<StageItemvalue="OT">OtherStageItem>
StageType>
<StageTypename="FSU">
<StageItemvalue="FP">Family PlanStageItem>
<StageItemvalue="FF"> ContactStageItem>
<StageItemvalue="OC">Other ContactStageItem>
<StageItemvalue="MD">Medical/DentalStageItem>
<StageItemvalue="LG">LegalStageItem>
<StageItemvalue="OT">OtherStageItem>
StageType>
StageTypes>


Here is my StageTypeItem Class I will use to store the Text and Value for a combobox:
public class StageTypeItem
{
///
/// Initializes a new instance of the StageTypeItem class.
///
public StageTypeItem()
{
}
private string dataValue;
public string DataValue
{
get { return dataValue; }
set
{
dataValue = value;
}
}
private string dataText;
public string DataText
{
get { return dataText; }
set
{
dataText = value;
}
}
}


Here is the code to build the list:
public static List<StageTypeItem> LoadStageType(string stageType)
{
XDocument doc = XDocument.Parse(Properties.Resources.StageTypes, LoadOptions.None);
var stageTypes = from st in doc.Descendants("StageType").Descendants("StageItem")
where st.Parent.Attribute("name").Value == stageType
select new StageTypeItem
{
DataText = st.Value,
DataValue = st.Attribute("value").Value
};
return stageTypes.ToList<StageTypeItem>();
}


So I have a Root of StageType, with children StageItem in the Xml. I want to load the values where StageType name = passed parameter stageType. So assume I pass “SUB” in Xml I want the SUB children (StageItem only) to be returned:
<StageTypename="SUB">
<StageItemvalue="CP">Customer PlanStageItem>
<StageItemvalue="FF">ContactStageItem>
<StageItemvalue="OC">Other ContactStageItem>
<StageItemvalue="MD">Medical/DentalStageItem>
<StageItemvalue="LG">LegalStageItem>
<StageItemvalue="OT">OtherStageItem>
StageType>


Here I am saying load all Descendants of StageItem:
var stageTypes = from st in doc.Descendants("StageType").Descendants("StageItem")


But then I say, only StageItem where its parent has the name “SUB”, remember stageType is the parameter and I passed “SUB”
where st.Parent.Attribute("name").Value == stageType


This part creates a class of type StageTypeItem and I populate it from the Xml values:
select new StageTypeItem
{
DataText = st.Value, // the value of the Element, example first one is “Customer Plan”
DataValue = st.Attribute("value").Value // The Attribute named value (Case Sensitive) in the first case is “CP”
};


And then I return a list:
return stageTypes.ToList<StageTypeItem>();


Now I can bind a combobox to this list:
ComboBox cbo = new ComboBox();
cbo.DataSource = LoadStageType(“SUB”);
cbo.DisplayMember = “DataText”; // StageTypeItem.DataText
cbo.ValueMember = “DataValue”; // StageTypeItem.DataValue


Happy Coding!!!

 
Creative Commons License
Blogged Information and Code is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.