Can't DataBind a WPF combo-box to a CslaDataProvider parameter

Can't DataBind a WPF combo-box to a CslaDataProvider parameter

Old forum URL: forums.lhotka.net/forums/t/5079.aspx


BBM posted on Thursday, July 10, 2008

Hi everyone,

I am trying to create a simple WPF form that consists of a combo-box that is used to select a value  (a Guid) that represents the parm for a CslaDataProvider (which is the DataSource of a ListBox).

I can make it work fine if I hook the SelectionChanged event of the combo-box and explicitly set the CslaDataProvider parm with the SelectedValue.

But if I try to use databinding to automatically update the parm from the SelectedValue of the combo-box, I get curious results.

1)  SelectedValue in the combo-box never gets (completely) set during InitializeComponent.  SelectionChanged is raised TWO times for the combo-box.  The first time, the SelectedItem is correct, but SelectedValue is Nothing (null).  The second time it's raised there is NO selected item (SelectedIndex = -1) and both SelectedItem and SelectedValue are Nothing.  Without the databinding, I get the expected behavior.  SelectedIndex is set to 0 (as specificed in the Xaml), SelectedItem and SelectedValue are both correct.

2)  The list of the Combo-box is populated, and I can select an entry.  That entry correctly updates the value of my CslaDataProvider parm.  But the CslaDataProvider never re-queries on this change.  The only way I can get it to update is to set the parm value in code.

Here's the Xaml (edited to shorten it) with the Databinding code...

<Window x:Class="DesFamilyEditForm" xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation      

Title="Edit Descriptor Families" Height="370" Width="300"       Name="DesFamilyEditForm"       FlowDirection="LeftToRight"

Loaded ="OnLoadedHandler">

<Window.Resources>

<csla:CslaDataProvider x:Key="FamiliesList"

ObjectType="{x:Type lib:DFamiliesList}"

FactoryMethod="GetEditableRootList"

ManageObjectLifetime="True"

IsInitialLoadEnabled="False">

<csla:CslaDataProvider.FactoryParameters>

<ms:Guid>00000000-0000-0000-0000-000000000000</ms:Guid>

</csla:CslaDataProvider.FactoryParameters>

</csla:CslaDataProvider>

<csla:CslaDataProvider x:Key="FamTypesList"

ObjectType="{x:Type lib2:DFTypesListInfo}"

FactoryMethod="GetList"

ManageObjectLifetime="False">

</csla:CslaDataProvider>

</Window.Resources>

<Grid Name="mainGrid" FlowDirection="LeftToRight">

<Grid.RowDefinitions>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

</Grid.ColumnDefinitions>

<StackPanel Grid.Row="0" Name="FamTypeSelector" Orientation="Horizontal" HorizontalAlignment="Left">

<TextBlock Margin="10,5,2,0" Name="TypeLabel" Text="Family Type : "          IsEnabled="False"  VerticalAlignment="Center"

            FontStyle="Normal" TextDecorations="None" FontWeight="Bold"/>

<ComboBox    Margin="10,5,2,0"    Name="FamTypeCB"    MinWidth="175"    

Height="25"    IsEnabled="True"  FontStyle="Normal"

FontWeight="Bold" IsEditable="False" IsReadOnly="True" SelectedValuePath="Id" SelectedIndex="0"

ItemsSource="{Binding Source ={StaticResource FamTypesList}}" SelectionChanged="FamTypeCB_SelectionChanged">

<ComboBox.SelectedValue>

<Binding Source="{StaticResource FamiliesList}"

Path="FactoryParameters[0]"

BindsDirectlyToSource="True"

Mode="OneWayToSource"

UpdateSourceTrigger="PropertyChanged">

</Binding>

</ComboBox.SelectedValue>

</ComboBox>

</StackPanel>

<ListBox Name="FamilyTable" Grid.Row="2" Margin="10,0,2,0" ItemsSource="{Binding Source ={StaticResource FamiliesList}}"

KeyboardNavigation.TabNavigation="Continue" Loaded="FamilyTable_Loaded" IsSynchronizedWithCurrentItem="True">

<ListBox.ItemTemplate>

<!-- Format stuff here -->

</ListBox.ItemTemplate>

</ListBox>

</Grid>

</Window>

Any suggestions?  (BTW my code behind is in VB, and I know it looks strange to use FactoryParamters[0] as the Binding source for SelectedValue, but the parm doesn't update otherwise).

Thanks.

BBM

BBM replied on Friday, July 18, 2008

Hi Everyone,

I've decided that for whatever reason, my approach doesn't work.  The bottom line is that when ComboBox.SelectedValue is DataBound in Xaml to a CslaDataProvider parm, that while the ComboBox is being initialized, SelectedValue is just NOT set even though SelectedIndex, and SelectedItem ARE correct.  So the parm gets set to Nothing, and the FactoryMethod doesn't know what to do (or crashes).

So the work-around is to hook the ComboBox's SelectionChanged event, in the code-behind and to set the value of FactoryParameter there.  SelectedValue is set properly, and you can use the value to set the parm value - everyone is happy.  This isn't a big deal, but I think that one of the most attractive aspects of WPF is the possibility of "codeless" (ok nearly codeless), UI for BO's.  I'm disappointed that I couldn't make the Xaml work.

Also, it seems to me that the DataBinding here is "backwards".  I would have much preferred to set the DataBinding directly on the FactoryParameter in Xaml (i.e. make it the "target" of the DataBinding instead of the "source").  That's what Mode=OneWayToSource is supposed to work around, but it didn't do me any good here.  I couldn't figure out how to do this (set the Binding on the parm in Xaml) - the parm would need to be a DependencyProperty and I doubt that DependencyProperties are serializable.

Thanks anyway to everyone that at least looked at my post and thought about it.

BBM

 

BBM replied on Sunday, July 27, 2008

452 views and nobody has an opinion on this besides me?

Possibilities:

1)   My Xaml example is too long to read...

2)  Nobody else is stupid / bold enough to try to actually use WPF

3)  I've asked a question for which the answer is so brain-dead easy that no one will post it for fear of embarrassing me?

4)  It's not worth the effort to look into this when a one line work-around fixes it?

BTW I posted the same question on the WPF forum on MSDN and to date I have no responses there either.

BBM

 

RockfordLhotka replied on Sunday, July 27, 2008

You are probably charting new waters...

Have you tried binding the value to a TextBlock or something, so you can see what value is being "sent" from the combobox?

I agree that the binding feels backward. But a lot of things feel backward in XAML, so I guess we'll all just need to get used to it.

Curelom replied on Monday, July 28, 2008

You may want to try turning async off for the CslaDataProvider(I don't recall if it is on by default) and put the FamiliesList provider above the FamiliesType provider in the code.

Curelom replied on Wednesday, July 30, 2008

I've tried something similar to this and I can't get it to work either.

There is a similar example in the ProjectTracker code in the ProjectSelect.xaml where it binds to a textbox.  I don't know why that would work, but not the combobox.

          <TextBox Name="NameTextBox" AutoWordSelection="True">
            <TextBox.Text>
              <Binding Source="{StaticResource ProjectList}"
                Path="FactoryParameters[0]"
                BindsDirectlyToSource="true"
                UpdateSourceTrigger="PropertyChanged">
              </Binding>
          </TextBox.Text>
        </TextBox>

Copyright (c) Marimer LLC