New Posts New Posts RSS Feed: Tech Tip: ListBox Unbound - Programming List Controls the DevForce Way
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Tech Tip: ListBox Unbound - Programming List Controls the DevForce Way

 Post Reply Post Reply
Author
IdeaBlade View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 30-May-2007
Location: United States
Posts: 353
Post Options Post Options   Quote IdeaBlade Quote  Post ReplyReply Direct Link To This Post Topic: Tech Tip: ListBox Unbound - Programming List Controls the DevForce Way
    Posted: 06-Jun-2007 at 3:04pm

Level 300

DevForce Express

Aug 8, 2006

Suppose the UI displays a list of customers, a minimum order date, and an orders grid. The grid will show orders of the selected customer that were placed after the minimum order date. Our program must combine the selected customer with the minimum order date to compose the query that returns the subset of orders placed by that customer.

Binding can't help us. The customer list is potentially arbitrary and unrelated to anything we can bind to. It is not the property of any other object known to us. So we can't use data binding to drive the listbox (or combobox). We're going to have to do some programming.

In this tip, we will riff on this use case and

  • show how to populate the list control programmatically.
  • show how to configure it to return the user-selected customer.
  • explain the DevForce "__Self" property that returns whole objects.
  • introduce the DevForce "Dynamic Properties" feature.

Imagine we are building a UserControl to present our UI. In Visual Studio's Design View we drag a .NET ListBox from the ToolBox onto the design surface and call it mCustomerListBox. We then switch to Code View where we

  • subscribe to the CustomerListBox's SelectedIndexChanged event.
  • define the handler for that event (we'll present a MessageBox in this example).
  • populate the CustomerListBox.

C#:

// Subscribe to event

mCustomerListBox.SelectedIndexChanged +=

  CustomerListBoxSelectedIndexChanged;

// Event handler

private void CustomerListBoxSelectedIndexChanged(

  System.Object sender, System.EventArgs e) {

  Customer aCustomer = (Customer)mCustomerListBox.SelectedValue;

  if (aCustomer != null) {

     MessageBox.Show(aCustomer.Id.ToString + "-" +

     aCustomer.CompanyName,"Selected Customer");

  }

}

// Populate ListBox

private void ConfigureCustomerListBox() {

  EntityList<Customer> customers = Customer.GoGetEm();

  mCustomerListBox.DataSource = customers;

  mCustomerListBox.DisplayMember = "CompanyName";

  mCustomerListBox.ValueMember = "__Self";

}

VB.NET:

' Subscribe to event

AddHandler mCustomerListBox.SelectedIndexChanged, _

  AddressOf CustomerListBoxSelectedIndexChanged

 

' Event handler

Private Sub CustomerListBoxSelectedIndexChanged( _

  ByVal sender As System.Object, ByVal e As System.EventArgs)

  Dim aCustomer As Customer = _

    CType(mCustomerListBox.SelectedValue, Customer)

  If (aCustomer IsNot Nothing) Then

     MessageBox.Show(aCustomer.Id.ToString & "-" & _

     aCustomer.CompanyName, _

     " Selected Customer")

  End If

End Sub

 

' Populate ListBox

Public Sub ConfigureCustomerListBox()

  Dim customers As EntityList(Of Customer) = Customer.GoGetEm()

  mCustomerListBox.DataSource = customers

  mCustomerListBox.DisplayMember = "CompanyName"

  mCustomerListBox.ValueMember = "__Self"

End Sub

ConfigureCustomerListBox is the method of interest. It is very straightforward until the last line.

  • The fabulous "GoGetEm" method fetches the customers for the list.

 

C#:

public static EntityList<Customer> GoGetEm(){

return PersistenceManager.DefaultManager.GetEntities<Customer>();

}

VB.NET:

Public Shared Function GoGetEm() As EntityList(Of Customer)

Return PersistenceManager.DefaultManager.GetEntities(Of Customer)()

End Function

  • We pour those customers in a DevForce EntityList named customers.
  • We set the ListBox's datasource to that list.
  • We tell the ListBox to display the name of the customer which it obtains from the "CompanyName" property.
  • We set the "ValueMember" so that, when asked for its "SelectedValue", the ListBox returns the output. from the selected Customer's "__Self" property.

We run, click on a customer and see something like this:

 

The mystery here is the peculiar property name given to the ValueMember. The Customer doesn't have a "__Self" property? What is it anyway and why would we want it?

Returning Objects, Not Data

"__Self" is a property that returns the selected customer instance. Not the customer Id or the customer name or any other property of the selected customer. It returns the entire customer instance.

"__Self" is a bit of cleverness that grows on you as you become more familiar with object-oriented programming. In the "old days" we'd be content to get back a single property of the selected customer. That's what the ListBox control was designed to do. Of course a typical object property can return only a piece of raw data. What if we received the entire selected customer object instead? Then we could access all of the customer's aspects including its properties, methods, and events. This is a much richer foundation for constructing our orders query or whatever else we want to do with the selected customer.

Unfortunately, that's not the way the ListBox works. Like most controls, it wants to give you some data from the selected object rather than the object itself. Most UI controls are stuck in this pre-object-oriented world. The DevForce "__Self" property finesses the limitation by returning the object itself.

The example event handler drives that point home by concatenating the selected customer's Id to its name in the MessageBox text, something we could not do without access to the whole customer object.

Phantom (Dynamic) Properties

Of course the Customer class does not have a "__Self" property. DevForce created it for us.

Now DevForce can't actually change the Customer class; that was fixed at compile time. But DevForce can create a property on-the-fly and add it to the EntityList that holds customers. More precisely, it creates a "__Self" property and adds that property to the set of "PropertyDescriptors" maintained by that EntityList.

Here is the cool part. .NET databinding checks the EntityList for properties of Customers before it checks the Customer class. .NET asks the EntityList, "Do you have a " __Self" property?" to which the EntityList replies "I sure do and here it is!" .NET then invokes that " __Self" property and returns the customer object result.

.NET doesn't care whether or not this is an actual property of the Customer. It relies upon the EntityList to deliver a property (a "PropertyDescriptor" actually) that it can call. DevForce takes care of constructing the "__Self" property and conveying it to .NET.

You might say that "__Self" is a phantom property of the Customer class. We prefer to call it a "Dynamic" property because such properties are created "dynamically" at runtime.

"__Self" is only one example of such a property. DevForce creates others and you can create your own dynamic properties as well. But that's a tip for another day.

 

 

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down