Silverlight 3 ComboBox Control

This post outlines technique for displaying ComboBox control with .net RIA services to handle Foreign Key scenarios.

When ComboBox control was introduced as part of Silverlight 2, I blogged about a technique to use ComboBox control in foreign key scenarios, to workaround the lack of SelectedValue\SelectedValuePath property. I further enhanced the technique to handle cascading selection as outlined in this post. Fast forward to Silverlight 3. ComboBox control still does not have SelectedValue\SelectedValuePath property and the same technique still works. Moreover, if you are using Silverlight 3 with .net RIA services, majority of the code is automatically generated by the framework. In fact, with Silverlight 3 and .net RIA services there is no requirement for SelectedValuePath property!

Background

In business applications with relation database as backend data store, foreign keys are often used to form association between entities. When working with such an entity in UI, a friendly description is shown to user, while system handles the actual foreign key value behind the scene. For ComboBox, this translates to displaying foreign key entity with a friendly description (perhaps using a custom template), and storing the results of selection as foreign key value to the base entity. However, ComboBox does not provide a SelectedValuePath property to set selected foreign key value back to the base entity. Simplest workaround is to use SelectedItem property. By adding Foreign key entity as a property to the base entity, we can data bind SelectedItem to the foreign key entity, automating the whole process.

With .net RIA services, you can do this easily, just by setting Include attribute on the associated foreign key entity. This results in foreign key entity being added a property to the base entity, which can then be data bound to SelectedItem property. Now when SelectedItem sets new foreign key entity, property setter in turn sets related foreign key value property, as indicated by the Association attribute. All of this code is already in place, generated automatically by the .net RIA services code generator. All you have to do is to data bind to SelectedItem and take care of ItemsSource.

Modelimage

I will use the same Address/City model that I had previously used for Silverlight 2 ComboBox post, so that you can contrast the code, except that this time I will start with a database model. Model consists of Address and City tables.

Applicationimage

Create a Silverlight Navigation Application. Next add the ADO.NET Entity Data Model as AddressModel and generate the AddressEntities from database tables, Address and City.

Next add a Domain Service Class as AddressService, adding Address and City entities. Select Enable editing and also generate associated meta data.

In the class AddressMetadata, decorate City field with Include attribute.

internal sealed class AddressMetadata {

    // Metadata classes are not meant to be instantiated.
    private AddressMetadata() {
    }

    public Guid AddressId;
    [Include]
    public City City;
...

This will ensure that City entity in included as a property in the Address class and it is sent to client. Also modify GetAddress method in AddressService class to include City in retrieved data.

public IQueryable<Address> GetAddress() {
    return this.Context.Address.Include("City");
}

Compile and build the application.

Auto generated City Property

Find the Generated Code folder (unhide by clicking Show All Code for client application) and navigate to City field in Address entity class. Note that City property is decorated with Association attribute that ties Address.CityId foreign key to City.CityId primary key. Also note the Set property assessor for City property. When ever a new City value is set, it also automatically sets CityId property to proper foreign key value. Following is the auto generated code for the City Property:

[Association("City_Address", "CityId", "CityId", IsForeignKey = true)]
[XmlIgnore()]
public City City {
    get {
        if ((this._city == null)) {
            this._city = new EntityRef<City>(this, "City", this.FilterCity);
        }
        return this._city.Entity;
    }
    set {
        City previous = this.City;
        if ((previous != value)) {
            this.ValidateProperty("City", value);
            if ((previous != null)) {
                this._city.Entity = null;
                previous.Address.Remove(this);
            }
            this._city.Entity = value;
            if ((value != null)) {
                value.Address.Add(this);
                this.CityId = value.CityId;
            } else {
                this.CityId = default(Guid);
            }
            this.RaisePropertyChanged("City");
        }
    }
}

So far, .net RIA services has generated all the code necessary for City property and tying it to corresponding CityId foreign key property. All that is now needed for us to do is to add code to allow ComboBox to find a City entity in the ItemsSource entity list.

Shared City Partial Class

Add shared City partial class as City.shared.cs to the Silverlight server web application.

public partial class City {

    public override bool Equals(object obj) {
        if (null == obj) return false;
        City cityToCompare = obj as City;
        if (null == cityToCompare) return false;
        return CityId.Equals(cityToCompare.CityId);
    }

    public override int GetHashCode() {
        return CityId.GetHashCode();
    }
}

This code will be copied over to client and is used to find City entity from list of cities.

City List Provider

Next add class CityListProvider to the Silverlight client Application.

public class CityListProvider {
    AddressContext _dc;
    public AddressContext DomainContext {
        set {
            _dc = value;
            _dc.Load<City>(_dc.GetCityQuery());
        }
    }
    public EntityList<City> CityList {
        get {
            return _dc.Cities;
        }
    }
}

ComboBox XAML

Add a new page to display Address data using DataGrid. Following shows City column XAML snippet:

<data:DataGridTemplateColumn Header="City">
    <data:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding City.CityName}" />
        </DataTemplate>
    </data:DataGridTemplateColumn.CellTemplate>
    <data:DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding CityList, Source={StaticResource cityListProvider}}"
                      SelectedItem="{Binding City, Mode=TwoWay}"
                      DisplayMemberPath="CityName" />
        </DataTemplate>
    </data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>

Note that ComboBox control’s SelectedItem is directly bound to the City property. User is shown friendly “CityName” by setting DisplayMemberPath. Also add CityListProvider as a resource to the root Grid control.

Modify code behind to set DataGrid ItemsSource to Address property on AddressContext (domain context) and load addresses using LoadAddress method of address domain context.

AddressContext _dc;

void AddressList_Loaded(object sender, RoutedEventArgs e) {
    _dc = new AddressContext();
    addressDataGird.ItemsSource = _dc.Addresses;
    //
    CityListProvider cityListProvider = LayoutRoot.Resources["cityListProvider"] as CityListProvider;
    cityListProvider.DomainContext = _dc;
    //
    _dc.Load<Address>(_dc.GetAddressQuery());
}

imageCompile and test the application. Note that appropriate City field is automatically selected when ComboBox drop down opens, thanks to Equality override in City class. When a new City is selected from the drop down, CityId is auto updated to reflect the new selection.

Use of ComboBox for Implementing foreign key scenarios is now completely automatic with aid of .net RIA service. Framework generates necessary Foreign Key entity property and also generates corresponding code to keep underlying foreign key value in sync.

Steps to get started
  1. Use Include attribute on foreign key entity. Also include foreign key entity in data retrieval.
  2. Provide Equality override code to find entity in entity list
  3. Data bind ItemsSource to entity list provider
  4. Data bind SelectedItem directly to foreign key entity

Source Code: SL3ComboBox.zip (560KB) - (Updated Sep-21-2009)

Technorati Tags:
Published Friday, July 03, 2009 1:11 PM by manish.dalal
Filed under: , ,

Comments

# Silverlight 3 ComboBox Control - Manish Dalal

Sunday, July 05, 2009 8:47 AM by DotNetShoutout

Thank you for submitting this cool story - Trackback from DotNetShoutout

# Silverlight 3 ComboBox Control - Manish Dalal's blog

Monday, July 06, 2009 12:17 AM by WebDevVote.com

You are voted (great) - Trackback from WebDevVote.com

# re: Silverlight 3 ComboBox Control

Monday, July 06, 2009 9:30 AM by Thosebug

how smart is RIA services or comobox or both to get the foreign key values?

let's thinkg in something about Employee/Address and Address has Locality (country/city/state..) the combobox will have a thousands of records right?

what about performance? I think combobox is not usable for this scenario, at least not for business app. I prefer AutocompleteBox.

anyway in other hand the problem goes to RIA services...because requires to serialize before go to the client, the a thousand of localities would be serialized as xml/json/etc....this is not good...back to asp.net/html world ?

# Silverlight 3 ComboBox Control - Manish Dalal&#39;s blog

Tuesday, July 07, 2009 1:33 PM by Gridget

[Source: Manish Dalal's blog] quoted: Moreover, if you are using Silverlight 3 with .net RIA services, majority of the code is automatically generated by the framework.

# re: Silverlight 3 ComboBox Control

Thursday, July 09, 2009 1:47 PM by Fan

Great!! does it work in DataForm?

# re: Silverlight 3 ComboBox Control

Friday, July 10, 2009 11:44 AM by Marc

Nice post.

I wonder, will the Silverlight 3 version of ComboBox actually be a "combo" box, rather than a dropdown menu? i.e. users will be able to type into it. The current name is misleading!

I also wonder whether the size of the dropdown will change when you add/remove items after the control has finished loading. Lets hope so!

# re: Silverlight 3 ComboBox Control

Thursday, July 16, 2009 3:42 PM by Fan

Hi Manish,

I try to use DataPager control because of lots of records in the table. the comboBox can not work properly!! (error: the entity does not support 'Add' operation ??)

# re: Silverlight 3 ComboBox Control

Saturday, July 18, 2009 10:13 AM by Marlon

Hi Manish,

How do you go about on using this on DataForm? Your guidance will be greatly appreciated.

Cheers

# re: Silverlight 3 ComboBox Control

Monday, July 20, 2009 6:35 AM by Nic Oughton

Awesome - that works brilliantly. Thanks!

# re: Silverlight 3 ComboBox Control

Monday, July 20, 2009 3:55 PM by Bob Harrison

I'm using the July CTP of Silverlight 3 with RIA. I extended my Person class to include GenderInfo. In the Person table if field sex =0 then male, sex=1 then female. I create a Gender class in partial Person class extension and added a Gender Provider with the 2 Gender records and the Gender class. The problem is I get a null reference for value in the Setter of GenderInfo.

# re: Silverlight 3 ComboBox Control

Tuesday, July 21, 2009 1:18 PM by manish.dalal

@Fan,

It seems to works fine with DataPager, I have updated source code to include paged example

@Marlon,

Please download updated source code to see DataForm usage

# re: Silverlight 3 ComboBox Control

Wednesday, July 22, 2009 12:07 PM by Fan

It Works perfect. Thanks Manish, Great job!!

# re: Silverlight 3 ComboBox Control

Wednesday, July 22, 2009 5:53 PM by Fan

Could you help me another problem? I meet another problem when I tried to use popup window (from Brad Abrams' blog, blogs.msdn.com/.../business-apps-example-for-silverlight-3-rtm-and-net-ria-services-july-update-part-1-rich-data-query.aspx)"add new record" in DataForm, same problem happened like before(the entity does not support 'Add' operation ), Thanks in advance!!

# re: Silverlight 3 ComboBox Control

Thursday, July 30, 2009 4:08 PM by Elina

Great works

Thank you very much

# re: Silverlight 3 ComboBox Control

Thursday, July 30, 2009 4:51 PM by manish.dalal

Fan,

You need to make sure that you are using the same instance of domain context as on the main form. Set domain context on child window similar to City provider class.

# re: Silverlight 3 ComboBox Control

Friday, July 31, 2009 9:43 AM by Tim

If tried your appliction, and it seems to work. Only the AddressForm.xaml does not save the city object and AddressFormDDS.xaml does not select the right city.

is this only, or is this problem common.

# re: Silverlight 3 ComboBox Control

Friday, July 31, 2009 2:05 PM by Fan

Hi Manish,

In order to avoid lot of problems from using childwindow, I used another way not solved the problem. Anyway,Thank your help very much. Maybe it will be useful in the future(binding lookup table in the childwindow). Thanks again!!  

# re: Silverlight 3 ComboBox Control

Saturday, August 01, 2009 3:04 PM by Mark Johnston

Excellent post and code sample! This was a HUGE help for a "traditional" .NET developer to better understand the workings of Silverlight/XAML.

Thanks so much!

# re: Silverlight 3 ComboBox Control

Monday, August 03, 2009 10:32 AM by Dave

Super Great article!! Manish!

this solution helped us so much!!!!

but I have the same issue as Tim (Friday, July 31, 2009 9:43 AM by Tim)

The selecteditem in AddressFormDDS.xaml is not correct. I really would like to use DomainDataSource, but I do not know how to set the selectedItem to the correct value. In your example it will populate the combobox, but the selecteditem is incorrect.

Tim is also correct about the saving problem in AddressForm.xaml, but I added one line of code to get that working:

void saveButton_Click(object sender, RoutedEventArgs e)

{

    // add this to get the saving to work.

    addressDataForm.CommitEdit();

    _dc.SubmitChanges();

}

I really would appreciate if someone knows how to get the correct selecteditem working in AddressFormDDS.xaml

Thanx in advance!

# re: Silverlight 3 ComboBox Control

Monday, August 03, 2009 1:49 PM by Sanjay

I just started with SL3 & RIA services. Based on this post, I am trying to insert new record using DataForm & ComboBox.

In my test application, there are two entities HardwareAsset & LocationMaster.

LocationMaster contains master list of location & LocationID is primary key (identity column) which is foreign key in HardwareAsset table.

When I insert new hardware asset using DataForm & ComboBox, record gets inserted correctly in HardwareAsset but for every record it creates new row in LocationMaster table.

In domain service, even if I comment insert operation of LocationMaster, still record is added in LocationMaster table.

     public void InsertLocationMaster(LocationMaster locationMaster)

       {

           //this.Context.AddToLocationMaster(locationMaster);

       }

How to fix this issue? Any help is appreciated.

Thanks,

Sanjay

# re: Silverlight 3 ComboBox Control

Monday, August 03, 2009 2:38 PM by Nathan

I am also experiencing the same issue as Sanjay (Using add in combobox in a dataform). Using this technique it adds entries into both the foreign key table and the primary key table. I would greatly appreciate your help in understanding why this is happening.

# re: Silverlight 3 ComboBox Control

Tuesday, August 11, 2009 5:47 PM by Sanjay

Nathan,

Please check this post for combobox in Dataform

silverlight.net/.../255611.aspx

Thanks,

Sanjay

# re: Silverlight 3 ComboBox Control

Saturday, August 29, 2009 5:59 PM by Tommy

I did exactly as this article explained and my datagrid didn't get the ProgramName as I needed. It's empty. Seems like the ProgramListprovider("cityListprovider") doesn't get the list from the program table.

Any idea what happen? I checked the association was fine.

# re: Silverlight 3 ComboBox Control

Saturday, August 29, 2009 6:14 PM by Tommy

Additional, I tried the following:

<riaControls:DomainDataSource x:Name="programDataSource"

                                                             QueryName="GetProgramsQuery"

                                                             AutoLoad="True"

                                                             >

                                   <riaControls:DomainDataSource.DomainContext>

                                       <web:OleDataDomainContext/>

                                   </riaControls:DomainDataSource.DomainContext>

                               </riaControls:DomainDataSource>

                               <ComboBox ItemsSource="{Binding Data, ElementName=programDataSource}"

                                     SelectedItem="{Binding Program, Mode=TwoWay}"

                                     DisplayMemberPath="ProgramName" />

                               <ComboBox ItemsSource="{Binding ProgrmList, Source={StaticResource programListProvider}}"

                                     SelectedItem="{Binding Program, Mode=TwoWay}"

                                     DisplayMemberPath="ProgramName" />

One combobox with dds and one with ProgramListProvider.

The one with dds working just fine. It can shows ProgramName, but the other just show nothing. Please help.

Thank you.

# re: Silverlight 3 ComboBox Control

Tuesday, September 01, 2009 7:32 PM by Maca007

I've found similar problem to others.  That is, the "address form dds" page does not correctly select the right combo box item.  In addition to this, I have found that it only happens for the first 2 items in the DataForm list.  I re-ordered my list of addresses and it always was the first 2 DataForm items that were incorrect.

I have posted a possible bug onto the Silverlight forum, so it will be interesting to see what other people have found.

silverlight.net/.../280036.aspx

# re: Silverlight 3 ComboBox Control

Wednesday, September 16, 2009 3:54 PM by Evertom Scopim

I´m going trough the same combobox selected item problems.... if u have any kind of solution for this problem let-me know! sierrote@uol.com.br

# re: Silverlight 3 ComboBox Control

Monday, September 21, 2009 1:07 PM by manish.dalal

@Evertom Scopim, Maca007, Sanjay, Nathan

I have update source code to fix issue with address form dds. It now selects proper city.

# re: Silverlight 3 ComboBox Control

Tuesday, September 22, 2009 3:57 PM by Evertom Scopim

Thanks for the update!

I´ve just download and took a look in the changes....

I think this way only the cities that already have any relationship to the adress table will be display in the combobox items. Well i´ll take a look and rebuild your example database and have some practice with it.

# re: Silverlight 3 ComboBox Control

Tuesday, September 22, 2009 4:14 PM by Evertom Scopim

Ok! I´ve done the tests and now i understandd why you load the cities context even "without binding" it!

Really thnx!

# re: Silverlight 3 ComboBox Control

Wednesday, September 30, 2009 4:21 PM by TOUMI Fethi

Hi,

I see your example : great work.

I want to use in my application a static class in wich i will have many list that will be loded with data in application start up.

  public static class BusinessManager2

   {

       public static IQueryable<Web.DataAccess.TDDESPCP> TDDESPCPCache { get; set; }

   }

Then, i want to use these list as itemsource for (combo, grid, ..) in xaml.

I see in the web an example where these list are dictionary and with converter they can do it.

My lists are not dictionary and i prefer use them as static ressource.

Is there any way.

In your example i want the CityListProvider become static and in application startup i load the city list. is it possible ?

# re: Silverlight 3 ComboBox Control

Thursday, October 01, 2009 3:24 PM by wtfChris

Great Post!  I've refactored this a bit to a generic base class.  This let's me construct new strongly typed ListProviders with a single line of code.

Check out my post geekswithblogs.net/.../silverlight-3-combobox-binding-made-easy.aspx

# re: Silverlight 3 ComboBox Control

Monday, October 19, 2009 8:04 AM by Jacky Kenhjiro

Silverlight 3  With .net RIA services,Domain Service

Test in VS2008 Run Data and Form Show OK

but Deploy To WEB (use VS2008 Publish) Show From no Data ...

Please Help mee...  

# re: Silverlight 3 ComboBox Control

Monday, October 26, 2009 10:14 AM by Bathery

Great Post Manish!!!

I am also facing similar issue as reported by Nathan and Sanjay.  While editing the Address to change the city, a duplicate row with the same city is getting inserted into the City table.  I started experiencing this issue after implementing the Combobox as described here. I am using DDS. Any suggestion?

# re: Silverlight 3 ComboBox Control

Friday, October 30, 2009 2:57 PM by Bathery

Got it...once i set the same instance of the DomainContext my issue got resolved.  Now having a slight performance issue..:)

# re: Silverlight 3 ComboBox Control

Thursday, November 12, 2009 5:16 AM by PentaDragon

This seems an extraordinary amount of manual intervention for a pattern that is practically universal in every LOB application in existence. :-(

Leave a Comment

(required) 
(required) 
(optional)
(required)