views:

2474

answers:

1

Trying to determine if it is possible to bind the SelectedValue of a ComboBox to the inputs of multiple ObjectDataProviders with XAMAL Bindings.

I looked at MultiBinding but that appears to be grouping multiple controls together, not exactly what I'm looking to day.

I'd like to be able to have the ComboBox (locations) change the TextBlock (deviance) which it does AND to call the ObjectDataProvider (CommentProvider) to update the TextBox (locationComments).

This is fairly straightforward in a code-behind but would prefer to not go this route as a learning experience.

XAMAL CODE

<Window.Resources>
    <ObjectDataProvider x:Key="LocationProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True"MethodName="GetAssignedLocations" />
    <ObjectDataProvider
        x:Key="DevianceProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True" MethodName="GetPercentChange">
        <ObjectDataProvider.MethodParameters>
            <system:String>Location1</system:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <ObjectDataProvider
        x:Key="CommentProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True"
        MethodName="GetCommentByBusinessUnit">
        <ObjectDataProvider.MethodParameters>
            <system:String>Location1</system:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="locations"  VerticalAlignment="Top" ItemsSource="{Binding Source={StaticResource LocationProvider}}"
              DisplayMemberPath="BuName" SelectedValuePath="BuKey"
              SelectionChanged="locations_SelectionChanged">
        <ComboBox.SelectedValue>
            <Binding Source="{StaticResource DevianceProvider}"
             Path="MethodParameters[0]"   
                 BindsDirectlyToSource="True" 
                 Mode="OneWayToSource" />
        </ComboBox.SelectedValue>
<TextBlock Name="deviance" Height="23" Margin="0,0,645,17" Width="40" Text="{Binding Source={StaticResource DevianceProvider}}" IsEnabled="False" />

<TextBox Height="23" Margin="0,0,181,17" Name="locationComments" Width="350" />
+1  A: 

You're on the right track with the MultiBinding. The key is to use a MultiValueCoverter in conjunction with the MultiBinding.

<MultiBinding Converter="{StaticResource Coverter_LocationMultiConverter}"
        Mode="OneWayToSource">
    <Binding Source="{StaticResource DevianceProvider}"
       Path="MethodParameters[0]"
       BindsDirectlyToSource="True"
       Mode="OneWayToSource" />
    <Binding Source="{StaticResource CommentProvider}"
       Path="MethodParameters[0]"
       BindsDirectlyToSource="True"
       Mode="OneWayToSource" />
   </MultiBinding>

Where we were binding to just one thing before, now we are binding it to both ObjectDataProviders. The key factor that lets us do this is the converter:

public class LocationMultiCoverter : IMultiValueConverter
{
 #region IMultiValueConverter Members

 public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
 {
  throw new NotImplementedException();
 }

 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
 {
  return new object[] { value, value };
 }

 #endregion
}

Because we just need the same value in both places the CovertBack method is quite simple, however I'm sure you can see that it could be used to parse some complex stuff and pass back different components to different places in the UI.

Using this converter we can also try out a small sample, using two text boxes instead:

<Window x:Class="Sample.Window1"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="clr-namespace:Sample"
 Title="Window1"
 Height="300"
 Width="300">
<Window.Resources>
 <local:LocationMultiCoverter x:Key="Coverter_LocationMultiConverter" />
</Window.Resources>
<Grid>
 <StackPanel>
  <TextBlock x:Name="uiDeviance" />
  <TextBlock x:Name="uiComment" />
  <ComboBox x:Name="uiLocations"
      Height="23"
      HorizontalAlignment="Left"
      VerticalAlignment="Top"
      SelectedValuePath="Content">
   <ComboBoxItem>1</ComboBoxItem>
   <ComboBoxItem>2</ComboBoxItem>
   <ComboBoxItem>3</ComboBoxItem>
   <ComboBoxItem>4</ComboBoxItem>
   <ComboBoxItem>5</ComboBoxItem>
   <ComboBox.SelectedValue>
    <MultiBinding Converter="{StaticResource Coverter_LocationMultiConverter}"
         Mode="OneWayToSource">
     <Binding ElementName="uiDeviance"
        Path="Text"
        BindsDirectlyToSource="True" />
     <Binding ElementName="uiComment"
        Path="Text"
        BindsDirectlyToSource="True" />
    </MultiBinding>
   </ComboBox.SelectedValue>
  </ComboBox>
 </StackPanel>
</Grid>

(The Converter in my example exists in the Window's code behind as a separate class) And as you can see testing this out it will update both TextBoxes when the SelectedValue changes.

rmoore
It seems that with the converter and multibinding the objectdataproviders are not firing when the selected value is changed. The break point inside ConvertBack is being hit but the breakpoints in my WCF service are not being hit.
Brian
I figured out my problem, if you don't specify the source tag properly it doesn't work. Imagine that.Source="{StaticResource CommentProvider}"
Brian
The first thing that comes to mind is that the types need to match. Even though you can cram pretty much any value into anything field in WPF, some things like the method parameters or the new StringFormat binding property are aware of type. So if your BuKey isn't also a string that may be causing issues. Beyond that possible cause, it should be working and WCF may be the blocker here. A quick way to solve this would be to remove the object data providers and in the ConvertBack make the method calls you need. Then in the bindings bind to the Elements needed.
rmoore
Glad to hear it was something simple.
rmoore