How to fill DataGridComboBoxColumns ItemsSource in child UserControls?

Topics: Prism v4 - Silverlight 4, Prism v4 - WPF 4
Aug 17, 2011 at 12:35 AM

Hi

I have set a ViewModel as the DataContext of my AddressesUserControl in code-behind using Unity. The ViewModel has an ObserveableCollection<Address> as well as an ObserveableCollection<Place> called Places. The AddressesUserControl contains several smaller UserControls who all pick up the DataContext from it's parent. One of those UserControls has a DataGridComboBoxColumn so I set it up like this:

<DataGridComboBoxColumn Header="Place" 
    x:Name="PlaceComboBoxColumn"
    ItemsSource="{Binding Places}"
    SelectedValueBinding="{Binding PlaceID, ValidatesOnDataErrors=True}"
    SelectedValuePath="PlaceID"
    DisplayMemberPath="Name"
/>

Unfortunately that doesn't result in anything, and I can't figure out why. The Places collection is filled, and the Address entity has a PlaceID property. What is wrong?

TIA

Dennis

 

Developer
Aug 17, 2011 at 7:27 PM

Hi Dennis,

Based on my understanding, the reason behind this problem could be that the DataGridComboBoxColumn’s ItemsSource property must be set to a collection of items of type ComboBoxItem as is described in the following link, under the Remarks section:

If this does not solve your problem it would be useful if you could send us a repro sample application portraying this behavior, so we could analyze why it is happening.

Thanks,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Aug 17, 2011 at 8:49 PM

Hi, I've tried to set up a a solution using both a regular list and a list of comboboxitems, but neither of them work.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="620">
    <DataGrid Name="MainDataGrid"
            ItemsSource="{Binding EntityCollection}" 
            SelectedItem="{Binding SelectedEntity, Mode=TwoWay}"
            SelectionMode="Single" 
            AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=Street}" Header="Street" Width="200" />
            <DataGridComboBoxColumn 
                    Header="People" 
                    SelectedValueBinding="{Binding PersonID}"
                    SelectedValuePath="PersonID"
                    DisplayMemberPath="Name"
                    SelectedItemBinding="{Binding SelectedEntity, Mode=TwoWay}" Width="200"
                    />
            <DataGridComboBoxColumn 
                    Header="PeopleCBO" 
                    SelectedValueBinding="{Binding PeopleCBO}"
                    SelectedValuePath="Tag"
                    DisplayMemberPath="Content" Width="*"
                    />
        </DataGrid.Columns>
    </DataGrid>
</Window>

using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MainWindowViewModel vm = new MainWindowViewModel();
            this.DataContext = vm;
        }
    }
}

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Controls;

namespace WpfApplication1
{
    public class MainWindowViewModel : ViewModelBase
    {

        public MainWindowViewModel()
        {
            People = new ObservableCollection<Person>();
            PeopleCBO = new List<ComboBoxItem>();
            EntityCollection = new ObservableCollection<Address>();
            People.Add(new Person { PersonID = 1, Name = "First person" });
            People.Add(new Person { PersonID = 2, Name = "Second person" });
            People.Add(new Person { PersonID = 3, Name = "Third person" });
            People.Add(new Person { PersonID = 4, Name = "Fourth person" });
            People.Add(new Person { PersonID = 5, Name = "Fifth person" });
            EntityCollection.Add(new Address { AddressID = 1, Street = "Street 1", Person = People[0] });
            EntityCollection.Add(new Address { AddressID = 2, Street = "Street 2", Person = People[0] });
            EntityCollection.Add(new Address { AddressID = 3, Street = "Street 3", Person = People[1] });
            PeopleCBO.Add(new ComboBoxItem { Tag = People[0].PersonID, Content = People[0].Name });
            PeopleCBO.Add(new ComboBoxItem { Tag = People[1].PersonID, Content = People[1].Name });
            PeopleCBO.Add(new ComboBoxItem { Tag = People[2].PersonID, Content = People[2].Name });
            PeopleCBO.Add(new ComboBoxItem { Tag = People[3].PersonID, Content = People[3].Name });
            PeopleCBO.Add(new ComboBoxItem { Tag = People[4].PersonID, Content = People[4].Name });
        }

        private ObservableCollection<Address> entityCollection;
        public ObservableCollection<Address> EntityCollection
        {
            get { return entityCollection; }
            set { entityCollection = value; }
        }

        private Address selectedEntity;
        public Address SelectedEntity
        {
            get { return selectedEntity; }
            set { selectedEntity = value; }
        }

        private ObservableCollection<Person> people;
        public ObservableCollection<Person> People
        {
            get { return people; }
            set { people = value; }
        }

        private List<ComboBoxItem> peopleCBO;
        public List<ComboBoxItem> PeopleCBO
        {
            get { return peopleCBO; }
            set { peopleCBO = value; }
        }
    }

    public class Person
    {
        private int personID;
        public int PersonID
        {
            get { return personID; }
            set 
            {
                if (personID != value)
                {
                    personID = value;
                }
            }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set 
            {
                if (name != value)
                {
                    name = value;
                }
            }
        }
    }

    public class Address
    {
        private int addressID;
        public int AddressID
        {
            get { return addressID; }
            set
            {
                if (addressID != value)
                {
                    addressID = value;
                }
            }
        }

        private string street;
        public string Street
        {
            get { return street; }
            set
            {
                if (street != value)
                {
                    street = value;
                }
            }
        }

        private Person person;
        public Person Person
        {
            get { return Person; }
            set
            {
                if (person != value)
                {
                    person = value;
                }
            }
        }
    }

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

TIA
Dennis
Developer
Aug 18, 2011 at 8:21 PM

Hi Dennis,

As a workaround for this you can implement this approach to populate the DataGridComboBoxColumn’s ItemsSource:

<DataGridComboBoxColumn 
                    Header="People" 
                    SelectedValueBinding="{Binding PersonID}"
                    SelectedValuePath="PersonID"
                    DisplayMemberPath="Name"
                    SelectedItemBinding="{Binding SelectedEntity, Mode=TwoWay}" Width="200"
                    >
         <DataGridComboBoxColumn.EditingElementStyle>              <Style TargetType="ComboBox">                  <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=DataContext.People}"/>              </Style>          </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

As this is not strictly related to Prism or the MVVM pattern you might find better support about the use of the DataGridComboBoxColumn control in the WPF Forums:

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini