John Kraft
John Kraft

Reputation: 6840

How to bind a DataGridComboBoxColumn outside the ItemSource

I am working on my first 'production' WPF app, and I'm encountering an issue.
I have some code that is similar to the example below. The problem I am having is that I cannot get the ComboBox to populate. I'm assuming it is because the Grid's ItemsSource is 'blocking' the ComboBoxfrom being able to see the Tasks collection on the ViewModel, but I am only guessing. Everything else is databinding correctly.

I scoured SO and found this question; which sounds exactly like what I am trying to do, but it did not work for me.

Any idea why I can't get the ComboBox to populate?

Model:

public class Activity{
  public int Id { get; set; }
  public string Title { get; set; }
  public Task Task { get; set; }
}

public class Task{
  public int Id { get; set; }
  public string Title { get; set; }
}

ViewModel:

public ApprovalViewModel{
  public ObservableCollection<Activity> Activities { /* ... property logic */ }
  public ObservableCollection<Task> Tasks { /* ... property logic */ }
}

View:

<DataGrid ItemsSource="{Binding Activities}" AutoGenerateColumns="False">
    <DataGrid.Resources>
        <DataTemplate x:Key="displayTemplate">
            <TextBlock Text="{Binding Task.Title}"/>
        </DataTemplate>
        <DataTemplate x:Key="editTemplate">
            <ComboBox ItemsSource="{Binding Tasks}" <!--I think the problem is here-->
              SelectedValue="{Binding Task}"
              DisplayMemberPath="Title"/>
        </DataTemplate>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridComboBoxColumn DisplayMemberPath="Title"/>
        <DataGridTextColumn Binding="{Binding User}" Header="User"/>
        <DataGridTextColumn Binding="{Binding Task.Project.Title}" Header="Project"/>
        <DataGridTemplateColumn 
            Header="Task" 
            CellTemplate="{StaticResource displayTemplate}" 
            CellEditingTemplate="{StaticResource editTemplate}"/>
        <DataGridTextColumn Binding="{Binding Description}" Header="Description"/>
    </DataGrid.Columns>
</DataGrid>

Edit: the correct ComboBox code is here:

<ComboBox 
  ItemsSource="{Binding Path=DataContext.Tasks, 
                        RelativeSource={RelativeSource FindAncestor, 
                                        AncestorType={x:Type UserControl}}}"
  SelectedValue="{Binding Task.Title}"
  SelectedValuePath="Title"
  DisplayMemberPath="Title"/>

Upvotes: 2

Views: 2944

Answers (1)

Chris Sainty
Chris Sainty

Reputation: 9346

You are correct in where the problem lies, that binding is relative to the Activity. So it is looking for Activity.Tasks.

The post you linked to has the right approach, you just need to tweak it for your situation.

ItemsSource="{Binding Path=DataContext.Tasks, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 

This will go back up the Visual tree looking for a Window, which has a DataContext.Tasks property.

Is your code example inside a window? If not you will need to change the {x:Type } and secondly is the DataContext set on this object? If not you will need to set it to your ViewModel.

Upvotes: 5

Related Questions