Search code examples
c#wpfmvvmcomboboxitemssource

C# WPF MVVM ItemSource not attaching list


I have a list of Roles that I want to have selectable in a DataGrid cell ComboBox.

I have the ObservableCollection Roles for the ComboBox being populated in the ViewModel.

For some reason, nothing shows up in the ComboBox though. What's the proper way of attaching this collection of objects?

Any comments or suggestions would be helpful.


PersonModel:

public int SelectedRole { get; set; }

RoleModel:

public int Id { get; set; }

public int Role { get; set; }

public string Description { get; set; }

public string RoleInfo 
{ 
    get 
    {
        return $"{Role} - {Description}";
    }  
}

ViewModel:

private ObservableCollection<PersonModel> _people;
public ObservableCollection<PersonModel> People
{
    get { return _people; }
    set
    {
        _people = value;
        NotifyOfPropertyChange(() => People);
    }
}

public ObservableCollection<RoleModel> _roles;
public ObservableCollection<RoleModel> Roles
{
    get
    {
        return _roles;
    }
    set 
    {
        _roles = value;
        NotifyOfPropertyChange(() => Roles);
    }
}

public PersonViewModel(IEventAggregator events, IWindowManager windowmanager)
{
    _events = events;
    _windowManager = windowmanager;

    sql = "SELECT * FROM People";
    People = SqliteConnector.LoadData<PersonModel>(sql, new Dictionary<string, object>());
    sql = "SELECT * FROM Roles";
    Roles = SqliteConnector.LoadData<PersonModel>(sql, new Dictionary<string, object>());
}

View:

<DataGrid ItemsSource="{Binding Path=People}"
          AutoGenerateColumns="False"
          CanUserDeleteRows="True"
          CanUserReorderColumns="True"
          CanUserAddRows="True"
          AlternatingRowBackground="#dfdfdf"
          cm:Message.Attach="[Event RowEditEnding] = [Action SaveOrUpdate()]">
  <DataGridTemplateColumn Header="Type">
    <DataGridTemplateColumn.CellTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding Path=Role}"/>
      </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
      <DataTemplate>
        <ComboBox DisplayMemberPath="RoleInfo"
                  ItemsSource="{Binding Path=Roles}"
                  SelectedValue="{Binding Path=SelectedRole, UpdateSourceTrigger=PropertyChanged}"
                  SelectedValuePath="Role" />
      </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
  </DataGridTemplateColumn>
</DataGrid>

Solution

  • The DataContext of the "row" elements of the DataGrid is the corresponding item of the ItemsSource collection, i.e. a PersonModel instance - which does of course not have a Roles property. You should have observed a corresponding data binding error message in the Output Window in Visual Studio.

    In order to bind to the Roles property of the parent view model, use an expression like this:

    ItemsSource="{Binding DataContext.Roles,
                          RelativeSource={RelativeSource AncestorType=DataGrid}}"
    

    The SelectedValue Binding could simply be like shown below, because PropertyChanged is already the default UpdateSourceTrigger for that property.

    SelectedValue="{Binding Path=SelectedRole}"