0
votes

I a have a View Players, the datacontext is set to a ObservableCollection Players from the ViewModel MainPlayerViewModel.

In the View I have a datagrid with columns TeamId, Name and Position. I want to bind the TeamId column with a combobox to a list of available teams from the MainTeamViewModel which has a collection property Teams but of course I want the MainPlayerViewModel to be updated whenever I update the team for a player.

I hope you can follow me here.. This is my xaml:

<data:DataGridTemplateColumn.CellEditingTemplate>
  <DataTemplate>
   <ComboBox DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}" 
    Height="23" HorizontalAlignment="Left" 
    Name="cmbTeams" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Teams, 
    Mode=TwoWay}" SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"   
    DisplayMemberPath="Model.teamid"/>
  </DataTemplate>
 </data:DataGridTemplateColumn.CellEditingTemplate>

When I edit the cell it shows the list of available teams but the selectedvalue I pick from the list doesn't turn up in the TeamId column

How do I pull this off?

Kind regards,

Mike

UPDATE: Despite the help I received I didn't get it to work binding one View to 2 different Viewmodels. Guess the solution offered is long above my head.. I couldn't set the datacontext of the datagrid to MainTeam because it has an ItemsSource of players and a selecteditem bound twoway to selectedplayer. Anyway I decided to keep it 1 View / 1 ViewModel and created a public property on my PlayerViewModel named teamsVM:

    public MainTeamViewModel teamsVM
    {
       get
       {
           return ViewModelLocator.Container.Resolve<MainTeamViewModel>();
       }
    }

Now I can set the Itemsource to this new property and my player row get's updated when I change teams:

    <DataTemplate>
     <ComboBox 
       Height="23" HorizontalAlignment="Left" 
       Name="cmbTeams" VerticalAlignment="Top" Width="100" 
       ItemsSource="{Binding teamsVM.Teams, 
       Mode=TwoWay}" SelectedValue="{Binding Model.teamid, Mode=TwoWay}"   
       DisplayMemberPath="Model.teamid" SelectedValuePath="Model.teamid"/>
    </DataTemplate>

Regards,

Mike

2

2 Answers

0
votes

I find two things wrong with this code.

You are missing the SelectedValuePath for the ComboBox. Even though you bind all teams to it, the selected item's id is null because the SelectedValuePath is missing.

You also have a DataContext and an ItemsSource. Use only the ItemsSource for the teams you want to display, and the SelectedValue to be bound to the player's teamId, unless your view model has a "Teams" property and a "Player" property, in which case the DataContext may be used. (Id set the DataContext in code though...)

So yo will end up with something like this:

ItemsSource="{Binding Teams, Mode=TwoWay}"                  //Bind to all teams.
SelectedValue="{Binding Player, Path=TeamId, Mode=TwoWay}"  //Bind to the teamId of the player.
DisplayMemberPath="TeamName"                                //that's the Name of each team.
SelectedValuePath="TeamId"                                  //that's the Id of the team.
0
votes

Two problems here:

  • First, as @bleepzer noted you did not specify the value/display paths in your combo box.
  • Second, you trying to access a property in the data context that is outside your grid (i.e. the main view model's data context) from within a data template. In silverlight 4 there is no relative source binding (something you would use in SL 5 or WPF), so you will have to use element binding to archive what you want.

Here is an example based on your code. It is not complete as it leaves out some of the DataGrid elements needed, but it shows the concept:

<data:DataGrid x:Name="myDataGrid" 
               DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}" >
  <!-- additional stuff needed here -->
    <data:DataGridTemplateColumn.CellEditingTemplate>
      <DataTemplate>
        <ComboBox Height="23" HorizontalAlignment="Left" 
                  Name="cmbTeams" VerticalAlignment="Top" Width="100" 
                  ItemsSource="{Binding ElementName=myDataGrid, Path=DataContext.Teams}" 
                  SelectedValuePath="TeamId"
                  DisplayMemberPath="TeamName"
                  SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"/>
      </DataTemplate>
    </data:DataGridTemplateColumn.CellEditingTemplate>
  <!-- additional stuff needed here -->
<data:DataGrid>

And here is the description:

  1. Add a name to your data grid.
  2. Make sure the data grid has the right data context, either by setting it explicitly as in the sample, or inheriting it from the parent hierarchy.
  3. Modify your ComboBox's ItemsSource property to point to the data grid using the element name you specified earlier. As you are now on the element and not on the data context you have to use DataContex.Teams to access the Teams property on the data context of your grid. The ItemsSource does not need two-way-binding as the view does not write anything back to your view model.
  4. Specify the SelectedValuePath and DisplayMemberPath properties.
  5. Finally, bind the SelectedValue property of the combo box to your rows model TeamId property using two-way-binding - needed now as the view should update the model's value. Important: the SelectedValue property of the combo box has to be bound after the ItemsSource to prevent some problems with the combo box.