DataGridComboBoxColumn binding to ObservableCollection

Dmitry Z picture Dmitry Z · Apr 30, 2013 · Viewed 10.2k times · Source

I have the class Devices with Platform as one of the properties:

public partial class DevicesCollection : ObservableCollection<Device>
{
    public DevicesCollection() : base()
    { }
}

public partial class Device : INotifyPropertyChanged
{
    private string hostIP;
    private string password;
    private int platform;
    private string status = "";
    private int loop = 1;

    public Device() { }

    public Device(string ip, string pswd, int tp)
    {
        HostIP    = ip;
        Password  = pswd;
        Platform  = tp;
        Status    = "Disconnected";
        Loop = 1;
    }        

As well as I have Platform class:

public partial class PlatformsCollection : ObservableCollection<Platform>
{
    public PlatformsCollection()
        : base()
    {
        Add(new Platform(1, "iOS"));
        Add(new Platform(2, "Android"));
        Add(new Platform(3, "Windows"));
        Add(new Platform(4, "Blackberry"));
    }
}

public partial class Platform : INotifyPropertyChanged
{
    private string platformName;
    private int platformId;

    public Platform(int id, string name)
    {
        PlatformName = name;
        PlatformId = id;
    }
....

I have a DataGrid which is bound to Devices class and one of the columns is a ComboBox Platform which I'm trying to bind to Platform class:

<DataGridComboBoxColumn x:Name="platform" Header="Platform" CanUserResize="False"
                        ItemsSource="{Binding Platform}"
                        SelectedValueBinding="{Binding Path=Platform.PlatformId}"
                        SelectedValuePath="PlatformId"
                        DisplayMemberPath="PlatformName" Width="100">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding Path=Platform.PlatformName}" />
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>

I see the dropbox with the values, but after selecting any value when I trying to receive the DataGrid.ItemsSource column Platform is empty. What I'm doing wrong? I tried to change the column to template with combobox inside - same result. I'll appreciate any help or at least direction to dig in.

Answer

Justin picture Justin · May 1, 2013

Are you attempting to bind the DataGridComboBoxColumn's ItemsSource property to an ObservableCollection (PlatformsCollection) or to a Property (Platform)?

You should be able to accomplish this with something like..

<DataGridComboBoxColumn Header="Platform" ItemsSource="{Binding PlatformsCollection}"
    SelectedValue="{Binding SelectedPlatform}" DisplayMemberPath="PlatformName"/>

You'll need to add another member to your model called SelectedPlatform which will store/update each time the user changes the selected platform.

Additionally, you may want to look into using a CellTemplate/CellEditingTemplate combination with a DataGridTemplateColumn for this which looks a bit nicer. The user is only presented with a textbox unless they click into the cell at which point the combobox would appear.

The markup for this would be something like

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding SelectedPlatform.PlatformName}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding PlatformsCollection}" 
                SelectedValue="{Binding SelectedPlatform}" 
                DisplayMemberPath="PlatformName"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn

Hopefully that helps. Let me know if you have any questions.