Ken
Ken

Reputation: 3096

DataGridComboBoxColumn does not display ObservableCollection

Sample code:

class GameListViewModel {
    private IGameRepository repository;
    public GameViewModel GameViewModel { get; set; }
    public ObservableCollection<GameViewModel> Games { get; set; }
    public ObservableCollection<GenreViewModel> Genres { get; set; }
    public ICommand AddGame_ { get; set; }

    public GameListViewModel() {
        repository = new DummyGameRepository();
        GameViewModel = new GameViewModel();
        Games = new ObservableCollection<GameViewModel>(repository.GameList().Select(game => new GameViewModel(game)));
        Genres = new ObservableCollection<GenreViewModel>(repository.GameList().Select(game => game.Genre).Distinct().Select(genre => new GenreViewModel(genre)));
        AddGame_ = new RelayCommand(AddGame, CanAddGame);
    }
}

class Game {
    public string Title { get; set; }
    public string SubTitle { get; set; }
    public int Pegi { get; set; }
    public Genre Genre { get; set; }
}

XAML:

    <DataGrid ItemsSource="{Binding Games}" AutoGenerateColumns="False" Margin="0,32">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Title" Binding="{Binding Title}" />
            <DataGridTextColumn Header="Sub-Title" Binding="{Binding SubTitle}" />
            <DataGridTextColumn Header="Pegi" Binding="{Binding Pegi}" />
            <DataGridTextColumn Header="Genre" Binding="{Binding Genre.Name}" />

            <DataGridComboBoxColumn Header="Test" ItemsSource="{Binding Genres}" DisplayMemberPath="Name" />
        </DataGrid.Columns>
    </DataGrid>

The problem is, I want the combobox to show all the possible genres added to games, dynamically. For that I have created a ObservableCollection within GameListViewModel. It does not work! I have been struggling with this now for 2 hours... Later I want the selected value to be the Genre within the Game.

Upvotes: 1

Views: 1718

Answers (1)

Andrew
Andrew

Reputation: 1492

Ahhh, you have discovered the source of many WPF developer's fustrations - the DataGrid does not forward it's DataContext to the columns. You can't really rely on statements like ItemsSource={Binding Genres}" in the column, because the framework can't resolve it. It's super-annoying.

Also, you have not set your SelectedItemBinding - here is a working example:

xaml:

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <CollectionViewSource Source="{Binding Possibilities}" x:Key="possibilities"/>
    </Grid.Resources>

    <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" x:Name="dataGrid">
        <DataGrid.Columns>
            <DataGridComboBoxColumn Header="test" 
                                    SelectedItemBinding="{Binding Selection}"
                                    ItemsSource="{Binding Source={StaticResource possibilities} }">

            </DataGridComboBoxColumn>

        </DataGrid.Columns>
    </DataGrid>
</Grid>
</Window>

cs code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel()
        {
            Items = new ObservableCollection<Item>()
            {
                new Item(){
                    Selection ="A"
                }
            }
        };
    }
}

public class Item : ViewModelBase
{
    private string _selection = null;

    public string Selection
    {
        get { return _selection; }
        set { _selection = value; OnPropertyChanged("Selection"); }
    }
}

public class ViewModel : ViewModelBase
{
    private ObservableCollection<Item> _items = new ObservableCollection<Item>();

    public ObservableCollection<Item> Items
    {
        get { return _items; }
        set { _items = value; OnPropertyChanged("Items"); }
    }

    private ObservableCollection<string> _possibilities = new ObservableCollection<string>()
    {
        "A", "B", "C"
    };

    public ObservableCollection<string> Possibilities
    {
        get
        {
            return _possibilities;
        }
        set
        {
            _possibilities = value;
            OnPropertyChanged("Possibilites");
        }
    }
}

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        var propChanged = PropertyChanged;
        if (propChanged != null)
            propChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Here are some helpful links: this one should work: http://blogs.msdn.com/b/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx

the last solution shown here is particularly relevant: http://blogs.msdn.com/b/vinsibal/archive/2008/12/17/wpf-datagrid-dynamically-updating-datagridcomboboxcolumn.aspx

Upvotes: 6

Related Questions