Databind itemsource of DataGridComboBoxColumn to collection in view model does not work

165 views Asked by At

What I am trying to do here is databind the Itemsource of a DataGridComboBoxColumn to a collection of strings declared as property of my item view model. The Datagrid itself is bound to another viewmodel which has a collection of viewModels that represent the rows on the datagrid. All my other bindings work properly. The collection is also filled, but the combobox remains empty.

XAML:

<Window.Resources>
    <ResourceDictionary>
        <local:GeneralDataGridViewModel x:Key="generalDataGridVm"/>
    </ResourceDictionary>
</Window.Resources>
<Grid>
      <DataGrid DataContext="{StaticResource generalDataGridVm}"
                  ItemsSource="{Binding Collection}">
     <DataGrid.Columns>

            <DataGridComboBoxColumn x:Name="chbCodes"
                                 Header="Code"                  
                                 ItemsSource="{Binding Path=DataContext.Collection, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
     </DataGrid.Columns>
    </DataGrid>
</Grid>

C# ItemViewModel:

public class ItemViewModel : INotifyPropertyChanged
    {

        private ObservableCollection<string> _collection;


        public ObservableCollection<string> Collection
        {
            get
            {
                return _collection;
            }
        }
        public Model Model { get; set; }


        public string Code
        {
            get { return Model.Code; }
            set { Model.Code = value; }
        }

        public ItemViewModel()
        {

        }



        public ItemViewModel(Model model)
        {
            Model = model;
            _collection = new ObservableCollection<string>();
            _collection.Add(model.Code);
            Model.PropertyChanged += Model_PropertyChanged;
        }


        public void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
        }

    }

c# DataGridViewModel:

public class GeneralDataGridViewModel
{
    private ObservableCollection<ItemViewModel> _collection;
    public ObservableCollection<ItemViewModel> Collection
    {
        get { return _collection; }
        set
        {
            _collection = value;
            NotifyPropertyChanged("Collection");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(String property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    public GeneralDataGridViewModel()
        : base()
    {
        _collection = new ObservableCollection<ItemViewModel>();
    }

    public GeneralDataGridViewModel(List<Model> models)
    {
        _collection = new ObservableCollection<ItemViewModel>((from m in models
                                                               select new ItemViewModel(m)).ToList());
    }
}

C# Model:

public class Model: INotifyPropertyChanged
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(String property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        public override string ToString()
        {
            return Code;
        }

    }
1

There are 1 answers

1
James Harcourt On

The code you have posted does not compile, but looking at it the issue might be with the data context, which you are setting to a static resource. If you are going to do this, the view model must be in your resource dictionary. The bindings in XAML are fine, see below for an example of this working:

XAML:

<Window.Resources>
    <ResourceDictionary>
        <local:GeneralDataGridViewModel x:Key="generalDataGridVm"/>
    </ResourceDictionary>
</Window.Resources>
<StackPanel Orientation="Vertical">
    <DataGrid DataContext="{StaticResource generalDataGridVm}" Name="DataGrid1" ItemsSource="{Binding Collection}">
        <DataGrid.Columns>
            <DataGridComboBoxColumn x:Name="chbCodes"
                         Header="Code"                  
                         ItemsSource="{Binding Path=DataContext.Collection, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
        </DataGrid.Columns>
    </DataGrid>
</StackPanel>

By declaring generalDataGridVm in XAML, the constructor is called in XAML, let's assume that construction supplies the values for the collection:

public GeneralDataGridViewModel() : base()
{
    _collection = new ObservableCollection<ItemViewModel>();

    _collection.Add(new ItemViewModel(new Model("code1")));
    _collection.Add(new ItemViewModel(new Model("code2")));
    _collection.Add(new ItemViewModel(new Model("code3")));
    _collection.Add(new ItemViewModel(new Model("code4")));
}

With this code, it results in a populated list:

enter image description here

So I think you just need to make sure that you are declaring your view model properly (I would suggest not creating this in XAML unless there is some good reason).

Then ensure that the collection is kept up to date properly in that particular instance of your view model.