SpriteHand
Module Border
  ComboBox in DataForm
Module Border
Location: BlogsAndy's Blog    
Posted by: host 9/24/2009 8:14 AM


I ran into a baffling data binding issue when using a DataForm containing a ComboBox recently which caused me to spin my wheels for way too long. Luckily,
Keith Jones was nice enough to set me straight and give me a solution.

I have a DataForm with a ComboBox in its EditTemplate. This is bound to a DataGrid's SelectedItem in a standard Master/Detail, and it’s all using .NET RIA Services.

I was seeing some kind of weird delay in the binding of the Grid's SelectedItem to the ComboBox. If you clicked on a row, the combobox was not bound properly. But if you clicked on a few rows (3 rows was the magic number), then the ComboBox got bound properly from that point on. It seemed like maybe the ComboBox items were taking forever to load, but in looking at an HTTP trace, there was no data being requested across the wire.

It turns out this was a timing issue with the data binding. The SelectedItem was being evaluated properly, but at the time the ItemsSource of the ComboBox was null. You see, I was using the DataForm’s ContentLoaded event to fill the ComboBox with items, something like this:

<ComboBox x:Name="cboCategory"

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

DisplayMemberPath="BreweryName" />

 

void dataForm1_ContentLoaded(object sender, DataFormContentLoadEventArgs e)

{

    ComboBox cboBrewery = dataForm1.FindNameInContent("cboBrewery") as ComboBox;

    cboBrewery.ItemsSource = _beerContext.Brewers;

}


…and while this fills the ComboBox just fine, it does it a bit too late --- the SelectedItem of the ComboBox has already been evaluated. Makes sense, but why would three clicks on the DataGrid set the binding straight? As Keith pointed out to me, the DataForm uses a caching mechanism that starts with 2 empty slots. After the first click, the first cache slot was filled. After the second click, the second cache slot was filled. Then on the third click, the first cache slot is reused – and since it had data by the third click, the data was shown.

The Fix: ComboBox in DataForm

There are probably a dozen ways to do this, but here is what I ended up using. You can also use this method for other list bound controls inside a DataForm such as a ListBox. First, add an instance of your Domain Context inside your page resources. Then have your ComboBox bind its ItemsSource to that context. This is shown highlighted below.

<navigation:Page

  x:Class="TestBeer1.Home"

  <!-- Note I removed some stuff here for brevity -->

  xmlns:testBeer1="clr-namespace:TestBeer1.Web"

  NavigationCacheMode="Enabled"

  Style="{StaticResource PageStyle}">

    <navigation:Page.Resources>

        <testBeer1:BeerDomainContext x:Key="beerDomainContext" />

        <DataTemplate x:Key="DataTemplate1">

            <StackPanel>

                <TextBox Text="{Binding BeerName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />

 

                <ComboBox x:Name="cboBrewery"

ItemsSource="{Binding Brewers, Source={StaticResource beerDomainContext}}"

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

                      DisplayMemberPath="BreweryName"

                />

            </StackPanel>

        </DataTemplate>

    </navigation:Page.Resources>

 

    <Grid x:Name="LayoutRoot" >

        <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}" >

            <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">

 

                <data:DataGrid x:Name="grdBeers" Height="200" />

 

                <StackPanel Orientation="Horizontal" Margin="20,20,20,20">

                    <dataControls:DataForm x:Name="dataForm1"

CommandButtonsVisibility="Commit,Cancel" AutoEdit="True"

IsReadOnly="False" Width="300" AutoCommit="True"

EditEnded="DataForm_EditEnded"

EditTemplate="{StaticResource DataTemplate1}" >

                        <d:DataContext>

                            <testBeer1:Beers></testBeer1:Beers>

                        </d:DataContext>

                    </dataControls:DataForm>

                </StackPanel>

            </StackPanel>

        </ScrollViewer>

    </Grid>

</navigation:Page>

… And then it is a matter of getting a reference to the domain context and loading up the data. We can do this in the Loaded event for a page or the OnNavigatedTo event for a View in a Navigation Application…

public partial class Home : Page

{

    BeerDomainContext _beerContext;

 

    public Home()

    {

        InitializeComponent();

    }

 

    // Executes when the user navigates to this page.

    protected override void OnNavigatedTo(NavigationEventArgs e)

    {

        _beerContext = this.Resources["beerDomainContext"] as BeerDomainContext;

 

        _beerContext.Load(_beerContext.GetBeersQuery(), LoadBeersComplete, null);

        _beerContext.Load(_beerContext.GetBrewersQuery(), LoadBrewersComplete, null);

        grdBeers.ItemsSource = _beerContext.Beers;

    }

 

    void LoadBeersComplete(LoadOperation<Beers> op)

    {

        if (op.HasError)

            throw op.Error;

    }

 

    void LoadBrewersComplete(LoadOperation<Brewers> op)

    {

        if (op.HasError)

            throw op.Error;

    }

 

    private void DataForm_EditEnded(object sender, System.Windows.Controls.DataFormEditEndedEventArgs e)

    {

        dataForm1.CommitEdit();

        if (e.EditAction == DataFormEditAction.Commit)

            _beerContext.SubmitChanges(SubmitChangesComplete, null);

 

    }

 

    void SubmitChangesComplete(SubmitOperation op)

    {

        if (op.HasError)

            throw op.Error;

    }

}

 

Permalink |  Trackback

Comments (4)   Add Comment
Re: ComboBox in DataForm    By Anonymous on 9/25/2009 1:55 AM
DEMO OR BUST

Re: ComboBox in DataForm    By Anonymous on 9/25/2009 3:49 AM
Heh... Yeah, there is a full demo coming, with complete CRUD that uses the "Beer Database" from my prior data access talks. This will be in the next week or so.
-Andy

Re: ComboBox in DataForm    By Anonymous on 10/20/2009 7:15 PM
thanx... helped a lot... as you say there must be a 12 ways to do this, but my way was pretty similar ;)

Re: ComboBox in DataForm    By Anonymous on 5/27/2010 2:45 PM
Hi,
Maybe you could help me. I have quite a similar problem but I don't know how to fix it.
I have Articles and article Families (not beers and brewers but same pb).
In the begining the fist article (first row of datagrid) is selected it has a 'sport' family. The dataform shows the combobox with 'sport' selected. When I select, let's say the third article that has a 'music' family, the dataform is properly updated but the previously selected first article has been modiied and has now the 'music' family set...
I'm getting crazy.
Thanks for your help


Title:
Comment:
Add Comment   Cancel 
Module Border Module Border
Module Border
  Subscribe
Module Border
RSS   Twitter
Module Border Module Border
Module Border
  Diversions
Module Border

TALKING RAGDOLL
This Windows Phone 7 App was created using Silverlight, the  Physics Helper Library,  and the Farseer Physics Engine. It gets interesting when you import your friends photos and have your way with them!

MORE INFO



DROPPYPOP
This Windows Phone 7 game was created using Silverlight, the  Physics Helper Library,  and the Farseer Physics Engine.
DEMO

MORE INFO



BOSS LAUNCH
This physics game won first place in the Server Quest Contest. Created using Silverlight 2, the Physics Helper Library,  and the Farseer Physics Engine.
PLAY IT

MORE INFO



DESTROY ALL INVADERS
A scrolling shooter game where the objective is to destroy the invading UFO's flying over a neighborhood of your choosing. Imagery provided by Microsoft Virtual Earth. Created using Silverlight 2.
PLAY IT

INFO AND CODE



PHYSICS HELPER DEMOS
These demos were created for the Physics Helper Library, which makes it easy to create physics games and simulations using Expression Blend, Silverlight, and the Farseer Physics Engine.
PLAY IT

INFO AND CODE



HOOK SHOT
This little basketball game took first place in the TeamZoneSports Silverlight Contest. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



SORT THE FOOBARS
A game where you need to sort the good foobars from the bad ones. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



POLYGON PHYSICS DEMO
A demo showing polygon physics where the user draws physics objects with the mouse. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



SILVERLIGHT ROCKS!
Destroy the asteroids before they destroy your ship! Created using Silverlight 2.
PLAY IT

INFO AND CODE



FISH GAME
A simple game of harpoon-the-fish. Written using the AJAX Sprite Toolkit.
PLAY IT

INFO AND CODE

Module Border Module Border
Module Border
  Search_Blog
Module Border
Module Border Module Border
Module Border
  Blog_Archive
Module Border
Module Border Module Border
Copyright (c) 2013 andy.beaulieu.com - Login