Silverlight and RIA: Adding a ComboBox to a DataForm

Posted Wed, Nov 25 2009 15:44 by Deborah Kurata

Building a DataForm is quick and easy and is detailed in this prior post. Even customizing it is a breeze as was also shown in that prior post. But now the design calls for a ComboBox. Ready to walk off a cliff?

It is surprisingly difficult to modify a DataForm to display a working ComboBox that is bound to a DomainDataSource. And it is even harder because so many of the available examples use a Fields collection that disappeared in July of 2009.

This post provides the steps for adding a ComboBox control to a DataForm. It retrieves the values for the ComboBox via RIA Services, but you could bind the ComboBox to any collection of data.

The ComboBox used in this example is the one from this prior post. To use it in this example, follow these steps:

1. Add a DomainDataSource for the codes that will populate the ComboBox.

2. Add the ComboBox and bind it to the DomainDataSource.

Before adding the ComboBox to the DataForm, let's try the above steps adding the ComboBox directly to the UserControl.

In XAML:

<UserControl xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"  x:Class="SLVB.CustomerSummaryUC"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls" 
    xmlns:domain="clr-namespace:SLVB.Web">

    <Grid x:Name="LayoutRoot" Background="BlanchedAlmond">
        <riaControls:DomainDataSource x:Name="CustomerSource"
               QueryName="GetCustomers" AutoLoad="True">
            <riaControls:DomainDataSource.DomainContext>
                <domain:CustomerContext/>
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>

        <riaControls:DomainDataSource x:Name="CustomerTypeSource" 
               QueryName="GetCustomerTypes" AutoLoad="True">
            <riaControls:DomainDataSource.DomainContext>
                <domain:CodeContext/>
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>

        <StackPanel Margin="5,5,200,5">
            <ComboBox ItemsSource=
                 "{Binding Data, ElementName=CustomerTypeSource}"
                  DisplayMemberPath="CodeText"/>
            <dataFormToolkit:DataForm
                  ItemsSource=
                  "{Binding Data, ElementName=CustomerSource}">
            </dataFormToolkit:DataForm>
        </StackPanel>
    </Grid>
</UserControl>

The CustomerTypeSource is the new DomainDataSource. The ComboBox binds to this data source and displays the customer types.

The results are as follows:

image

The ComboBox appears above the DataForm and partially covers it when it is open. So now we know that the ComboBox works. The next step is to insert it instead into the DataForm.

There is no way to change the type of one field on the DataForm without then specifying every field on the DataForm. So if we want to specify that the Customer Type is a ComboBox, we can no longer use the auto field generation and must instead manually define every field.

The DataForm XAML code is then significantly longer.

In XAML:

<StackPanel Margin="5,5,200,5">
    <dataFormToolkit:DataForm
              ItemsSource="{Binding Data, ElementName=CustomerSource}">
        <dataFormToolkit:DataForm.EditTemplate>
            <DataTemplate>
                <StackPanel
                       dataFormToolkit:DataField.IsFieldGroup="True">
                    <dataFormToolkit:DataField>
                        <TextBox Text=
                           "{Binding FirstName, Mode=TwoWay}" />
                    </dataFormToolkit:DataField>
                    <dataFormToolkit:DataField>
                        <TextBox Text=
                           "{Binding LastName, Mode=TwoWay}" />
                    </dataFormToolkit:DataField>
                    <dataFormToolkit:DataField>
                        <ComboBox ItemsSource=
                      "{Binding Data, ElementName=CustomerTypeSource}"
                      DisplayMemberPath="CodeText"/>
                    </dataFormToolkit:DataField>
                    <dataFormToolkit:DataField>
                        <TextBox Text=
                           "{Binding EmailAddress, Mode=TwoWay}" />
                    </dataFormToolkit:DataField>
                </StackPanel>
            </DataTemplate>
        </dataFormToolkit:DataForm.EditTemplate>
    </dataFormToolkit:DataForm>
</StackPanel>

A DataField element defines each field on the form. Within the DataField element is the control to display for that data field. In most case, this is a TextBox control. The Text property of the TextBox is bound to the appropriate field in the data source. The mode is TwoWay to provide review and edit.

So far, the ComboBox code is the same code defined earlier when the ComboBox was above the DataForm. But now it is in the desired location within the DataForm.

Let's give this a try and see what we have:

image

Well, the ComboBox is there … but it is empty. We simply copied the working ComboBox from above the DataForm to inside the DataForm and now it no longer populates. Hmmm.

After spending several hours Bing'ing about this … I ran across this post and thought it might be relevant. But instead of building a proxy, I thought I would just move the DomainDataSource into a UserControl resource.

So I removed the CustomerTypeSource DomainDataSource from under the Grid element and instead added it to a resources section. I then changed the x:Name to x:Key.

In XAML:

<UserControl.Resources>
    <riaControls:DomainDataSource x:Key="CustomerTypeSource"
                   QueryName="GetCustomerTypes"
                   AutoLoad="True">
        <riaControls:DomainDataSource.DomainContext>
            <domain:CodeContext/>
        </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>
</UserControl.Resources>

This required changing the binding on the ComboBox to use this as a StaticResource. The other change was setting the SelectedItem to the CustomerTypeId.

In XAML:

<ComboBox ItemsSource=
    "{Binding Data, Source={StaticResource CustomerTypeSource}}"
     DisplayMemberPath="CodeText"
     SelectedItem="{Binding CustomerTypeId, Mode=TwoWay}"/>

And the result:

image

Whohoo!!

Now the only problem is that the SelectedItem is not correct. Regardless of the customer type for a Customer, the SelectedValue is always set to the first item on the list. How do we fix this? Yes, another cliff.

The data bound to the ComboBox has both a display member (the CodeText) and a value member (the CodeId). We want to bind the CustomerTypeId property to the Code Id.

Because the ComboBox does not have a ValueMemberPath property, there is no easy way to tell the control that it should map the CustomerTypeId to the CodeId. But there is a hard way using Converters.

The fact that the ComboBox is missing a ValueMemberPath seems like a bug that I hope will be corrected.

But I have to start baking Thanksgiving pies. So more on this in a future post.

Happy Thanksgiving!

Enjoy!

Comments

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Saturday, November 28, 2009 6:21 PM by sebnet

Great post... but I have one question.

I'm experimenting a little bit with this RIA thing and came across the following situation:

The query to retrieve the combobox items is a paremeterized query, so I added a query parameter to my DomainDataSource, but, unfortunately the query parameter is not bindable, the only way to pass a value is harcoding it... The value for this parameter is given from the selected item in my dataform...

do you know how could I overcome this problem?

bye,

Sebastián.

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Saturday, November 28, 2009 8:10 PM by Tim

Great Post Deborah!  I have been fighting this for awhile.  I have a custom combobox that I created that loads on demand but it has a few quirks.  This is so much cleaner. I am looking forward to your follow up post once you solve the next piece of the puzzle.

Also another variable to throw at it once you have it working are some validation attributes.  I have a required attribute on mine (one of the quirks) and the dataform can correctly identify that has changed and needs to save but the box does not get a red border or tooltip.

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Friday, December 04, 2009 12:35 PM by Bryan G Campbell

My thoughts while reading through this post:

"Yes, yes, I've been there, move my working combo box into a Data Form and suddenly it doesn't work."

"Ok, good, move the DDS to resources and bind as StaticResource to get ComboBox items to display, I've solved that the same way."

"Yep, the SelectedItem is not sticking, lets see how she solves that."

"Wait, that's the end? How can that be? All this talk about cliffs and she leaves me hanging off one? Now I'm going to have to subscribe to this blog to see if she comes up with an elegant solution."

This is a very clear explanation of the problem, thanks! As you say, hopefully the Silverlight team gets this resolved. A ComboBox should never be this difficult to use.  Until then, I guess we keep doing it the hard way. :-(

# Silverlight: ComboBox SelectedItem

Friday, December 04, 2009 8:08 PM by Deborah's Developer MindScape

When last we saw our Silverlight ComboBox in this prior post , it was correctly populating, but as we

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Sunday, December 06, 2009 8:19 PM by Deborah Kurata

Hi Bryan -

The continuation of this is already posted. It is here:

msmvps.com/.../silverlight-combobox-selecteditem.aspx

Thanks for visiting the blog!

# Silverlight: Wish List

Friday, December 11, 2009 10:30 AM by Deborah's Developer MindScape

Yes, it is that time of the year when we put together our holiday wish list and hope Santa has us on

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Tuesday, December 15, 2009 2:33 PM by Jonathan

Hmmm, I don't know why, but this doesn't work for me, the ComboBox remain empty, even after binding it to a UserControl.Resource, changing the Name to a Key and switching the binding like you did (literally a copy&paste).

Any clue ? I've been searching for hours :(

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Tuesday, December 15, 2009 3:12 PM by Deborah Kurata

Hi Jonathan -

Post your question here: forums.silverlight.net/forums

That will make it easier for you to post some code and for other experts to see the question as well.

Hope this helps.

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Tuesday, May 25, 2010 9:30 PM by Chris Pietschmann

Here's a custom ComboBox that inherits from the standard ComboBox posted by Rockford Lhotka that fixes this issue perfectly:

www.lhotka.net/.../SilverlightComboBoxControlAndDataBinding.aspx

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Tuesday, June 15, 2010 12:03 AM by spam-dev

very good. thank ypu.

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Friday, July 02, 2010 8:08 PM by jonx

Hello,

Nice series of articles about the combobox problems...

I recommend reading:

blogs.msdn.com/.../combobox-sample-for-ria-services.aspx

Then I'm using third parties components namely teleriks and things are even more easy...

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Tuesday, September 28, 2010 3:54 AM by Pooja

I want to insert combobox in a dataform..in a registration window.... which does not have <UserControl.Resources> in it...

how do i do this???

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Thursday, November 18, 2010 12:23 PM by jess

can u show how to insert that in resources. kinda new in SL :D

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Friday, December 10, 2010 7:36 PM by Ivan

Thanks this is jus what i needed and it works

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Friday, January 28, 2011 10:40 PM by Zack

This is excellent! Just what I was looking for... have you ever tried to do:

2 combo boxes

1 data form

2 separate DomainDataSources

This is reflective of my underlying data model where I have one table with two lookups represented as combo boxes. It's probably something in my setup, but I get an error that randomly barfs on binding.

Entity 'UserAccount : 1' cannot be attached to this EntityContainer because it is already attached to another EntityContainer.

Great post! Just curious though if you've ever had success in doing what I'm trying.

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Monday, February 14, 2011 3:50 PM by Shimmy

And how would you do that with MVVM??

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Sunday, February 20, 2011 3:26 AM by rojorm

here stackoverflow.com/.../databinding-combobox-in-dataform-silverlight-using-mvvm-in-update  i have silimar question, DomainDataSources is good, but MVVM approach is better. How to do that using MVVM?

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Thursday, August 11, 2011 4:48 AM by Imran Khan

i m working on it but not abling to add

xmlns:domain="clr-namespace:SLVB.Web"

<domain:CustomerContext/>

please help me how can i do this

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Thursday, September 15, 2011 8:30 AM by Water Damage Restoration

It doesn't update the database after performing a dataform edit...

# re: Silverlight and RIA: Adding a ComboBox to a DataForm

Thursday, June 28, 2012 6:01 AM by Peter Klein

Hi Deborah,

Your article on this subject helped me to get on the right track. Your suggestion to move the RIAControl to local Resources was a helpful suggestion. Based on that suggestion I have been experimenting further and found this: stackoverflow.com/.../difference-between-selecteditem-selectedvalue-and-selectedvaluepath

That led to the conclusion that there MIGHT be an option to get it running. And... indeed there is. This is the relevant part of my XAML:

  <ComboBox ItemsSource="{Binding Source={StaticResource Source_Nation}, Path=Data}" DisplayMemberPath="Description" SelectedValuePath="ID" Name="cboNation" SelectedValue="{Binding Path=Data.CurrentItem.Nation_ID, Mode=TwoWay, Source={StaticResource Source_Person}}" />

I'm sorry for not having translated the example into your LOTR figures...

Peter

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: