RIA services and combobox lookups

update: Here is another version using Async ctp, that will let us wait untill all the data for the related comboboxes is loaded.

Here is a quick sample on how to setup comboboxes for lookups whether in datagrid or dataform
I am using Chinook database which can be downloaded from here. I am using Employee and Customer tables only.
This sample uses for employee look up to populate the Support Rep ID column in the customer table

In Metadata class for the Customer, we add an attribute [Include] for the employee property
 public partial class Customer
  {
  
    internal sealed class CustomerMetadata
    {

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

     …

      [Include]
      public Employee Employee { get; set; }

     …
    }
  }

and in the DomainService, we include the Employee like below to fetech the related employee record for the customer

 [EnableClientAccess()]
  public class ChinookDomainService : LinqToEntitiesDomainService<ChinookEntities>
  {

    …

    public IQueryable<Customer> GetCustomers()
    {
      return this.ObjectContext.Customers.Include(“Employee”);
    }

    …
}

In XAML, we Add a DomainDataSource in the resources
<UserControl.Resources>
     <my1:DomainDataSource AutoLoad=”False” x:Name=”salesRepList” QueryName=”GetEmployeesQuery” LoadedData=”salesRepList_LoadedData”/>     
    </UserControl.Resources>

The DataGrid is defined like this

 <my:DataGrid x:Name=”datagrid1″ Grid.Row=”0″  AutoGenerateColumns=”False”>
            <my:DataGrid.Columns>
             <my:DataGridTextColumn Header=”FirstName”  Binding=”{Binding FirstName}”/>
             <my:DataGridTextColumn Header=”LastName”  Binding=”{Binding LastName}”/>
                <my:DataGridTextColumn Header=”City”  Binding=”{Binding City}”/>
                <my:DataGridTextColumn Header=”Country”  Binding=”{Binding Country}”/>
             <my:DataGridTextColumn Header=”Employee”  Binding=”{Binding Employee.FirstName}”/>
              
             <my:DataGridTemplateColumn Header=”Support Rep”>
              <my:DataGridTemplateColumn.CellTemplate>
               <DataTemplate>
                <TextBlock Text=”{Binding Employee.FirstName}”/>
               </DataTemplate>
              </my:DataGridTemplateColumn.CellTemplate>
              <my:DataGridTemplateColumn.CellEditingTemplate>
               <DataTemplate>
                <ComboBox ItemsSource=”{Binding Data, Source={StaticResource salesRepList}}”  SelectedValuePath=”EmployeeId”
                 DisplayMemberPath=”FirstName” SelectedValue=”{Binding SupportRepId, Mode=TwoWay}” />
               </DataTemplate>
              </my:DataGridTemplateColumn.CellEditingTemplate>
                   
             </my:DataGridTemplateColumn>
             <my:DataGridTemplateColumn Header=”Support Rep”>
              <my:DataGridTemplateColumn.CellTemplate>
               <DataTemplate>
                <TextBlock Text=”{Binding Employee.FirstName}”/>
               </DataTemplate>
              </my:DataGridTemplateColumn.CellTemplate>
              <my:DataGridTemplateColumn.CellEditingTemplate>
               <DataTemplate>
                <ComboBox ItemsSource=”{Binding Data, Source={StaticResource salesRepList}}”  SelectedItem=”{Binding Employee, Mode=TwoWay}”
                 DisplayMemberPath=”FirstName”  />

               </DataTemplate>
              </my:DataGridTemplateColumn.CellEditingTemplate>

             </my:DataGridTemplateColumn>
            </my:DataGrid.Columns>
        </my:DataGrid>

there are 2 Template columns defined. 1st column shows a way to specify the Id value (Foreign  Key) and the 2nd shows how to set the selectedItem

The codebehind looks like this

public partial class MainPage : UserControl
  {
    ChinookDomainContext ctx = new ChinookDomainContext();   
    public MainPage()
    {
      InitializeComponent();
      DomainDataSource ds = this.Resources[“salesRepList”] as DomainDataSource;
      ds.DomainContext = ctx;
      ds.Load();
    }

    private void salesRepList_LoadedData(object sender, LoadedDataEventArgs e)
    {
      ctx.Load(ctx.GetCustomersQuery(), (lo) => {datagrid1.ItemsSource = lo.Entities;}, false);
    }
  
    private void Button_Click(object sender, RoutedEventArgs e)
    {
      ctx.SubmitChanges();
    }  
  }

you can download the sample from here

Advertisements

18 thoughts on “RIA services and combobox lookups

  1. hi,

    what does the lambda expression return (in below statement)?
    ctx.Load(ctx.GetCustomersQuery(), (lo) => {datagrid1.ItemsSource = lo.Entities;}, false);

    why doesnt the datagrid load properly, if i put the domaincontext inside the usercontrol(not in static resources), and autoload=true?

    thanks

    1. Hi,
      All it is doing is loading the data from customers query. ctx.load returns LoadOperation(lo) which will have the entities property populated with data. instead of lambda, you can use the completed event of the loadoperation. you dont see any data?. Do you see a call to getdata

  2. Lee, thanks for the example. It is very useful. For anyone else who has downloaded, I had to tweak the connection string in web.config so it could connect to my Chinook database. Out of the box, it showed the datagrid with no data. Also, in order to build, I had to remove column ‘Password’ from the Customer table definition (it wasn’t in my version 1.1 of Chinook db).

    1. Hi,
      There were issues with combobox(missing properties etc) in SL 3. Combobox in SL 4 doesnt have those shortcommings

  3. I’ve tried multiple examples of getting the combobox to work inside a datagrid in Silverlight 4 and your example has got me the closest. What a learning curve for a simple lookup ComboBox…

    Anyways, I can now get data to show in the combobox but I’m having some trouble with getting the correct values to be show. I’ve got a Project table with a WindowID foreign key to a Window table, simple enough. So here’s my ComboBox DataGridTemplateColumn:

    What I get is a list of Window’s but, for example, the first 10 Window’s are the first 10 related windows of the first 10 projects, not just a straight list of Windows. I think it’s because I’m using the related “Window.WindowName” instead of just “WindowName” but I can’t get “WindowName” to show any data. Please help!

  4. Replaced with []:
    [sdk:DataGridTemplateColumn x:Name=”windowDropDownColumn” Header=”Window” Width=”Auto”]
    [sdk:DataGridTemplateColumn.CellTemplate]
    [DataTemplate]
    [TextBlock Text=”{Binding Path=Window.WindowName}” /]
    [/DataTemplate]
    [/sdk:DataGridTemplateColumn.CellTemplate]
    [sdk:DataGridTemplateColumn.CellEditingTemplate]
    [DataTemplate]
    [ComboBox Height=”23″ Width=”120″
    ItemsSource=”{Binding Path=Data, Source={StaticResource projectDomainDataSource}, Mode=TwoWay}”
    SelectedValuePath=”WindowID”
    SelectedItem =”{Binding Window, Mode=TwoWay}”
    SelectedValue=”{Binding WindowID, Mode=TwoWay}”
    DisplayMemberPath=”Window.WindowName”
    Name=”windowComboBox” /]
    [/DataTemplate]
    [/sdk:DataGridTemplateColumn.CellEditingTemplate]
    [/sdk:DataGridTemplateColumn]

    1. looks like you are binding to a window object , so “WindowName” would be the the one you have to use

      Assuming your datagrid is bound to List of projects, does it have a property named “Window”
      if so the TextBlock binding would be right.

      1. Yes, and the TextBlock binds perfect, the problem is with the ComboBox. A “Window” is a month, January through December. So instead of the ComboBox showing:
        January
        February
        March
        April
        June
        July
        August
        September
        October
        November
        December

        It will show the months in the same order as the what the projects are referencing:
        January
        January
        December
        January
        March
        March
        March
        March
        ….and so on

  5. I download your code and chinook DB. Build your solution everything OK but I got message error from IE8 when running:
    Line: 56
    Error: Unhandled Error in Silverlight Application
    Code: 4009
    Category: ManagedRuntimeError
    Message: Element is already the child of another element.

    Please help me investigate the problem.
    Thanks.

  6. Nice sample, but [Include] works only with primitive data types. I have a db where primary and foreign keys are uniqueidentifiers/GUIDs – and this sample won’t compile. Can anybody suggest anything please 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s