johannespartin
johannespartin

Reputation: 501

C# WPF - DataGridComboBoxColumn ItemsSource

I'm currently struggling with DataGridComboBoxColumn in C# WPF.

I have the class ToolModel

class ToolModel
{
    public long Id { get; set; }
    public string Number { get; set; }
    public string Name { get; set; }
    public string Coating { get; set; }
    public bool Thread { get; set; }
    public string Kind { get; set; }
    public ToolTypeModel Type { get; set; }
}

and the class ToolTypeModel

public class ToolTypeModel
{
    public long Id { get; set; }
    public string Name { get; set; }
}

The data is stored into a database and loaded into my ViewModel

class ToolsViewModel
{
    public ObservableCollection<ToolModel> Tools { get; set; }
    public ObservableCollection<ToolTypeModel> ToolTypes { get; set; }

    public ToolsViewModel()
    {
        Tools = new ObservableCollection<ToolModel>(ToolModel.GetTools());
        ToolTypes = new ObservableCollection<ToolTypeModel>(ToolTypeModel.GetToolTypes());
    }
}

I want to display the data in a DataGrid and attempted to add a DataGridComboBoxColumn to select a ToolType for the corresponding Tool. Therefore I added following xaml definition (which is already a workaround - but the only way I was able to get it nearly working):

 <DataGrid x:Name="ToolsDataGrid" ItemsSource="{Binding Tools}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Nummer" Binding="{Binding Number}" />
            <DataGridComboBoxColumn 
                    Header="Typ"
                    SelectedValueBinding="{Binding Type, Mode=TwoWay}" 
                    SelectedValuePath="Id"
                    DisplayMemberPath="Name">

                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="{x:Type ComboBox}">
                        <Setter Property="ItemsSource" Value="{Binding Path=DataContext.ToolTypes, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="{x:Type ComboBox}">
                        <Setter Property="ItemsSource" Value="{Binding Path=DataContext.ToolTypes, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>
            </DataGridComboBoxColumn>
        </DataGrid.Columns>
    </DataGrid>

It shows all elements of ToolTypes but not the selected one my Tool has a reference on.

Any ideas how I can look up the ToolTypes into the ComboBoxColumn and show the referenced Type as selected item?

Thanks in advance.

Upvotes: 3

Views: 4119

Answers (1)

SelectedValuePath is the path to a property of the combobox items that will be bound via the SelectedValueBinding. Therefore, SelectedValueBinding must bind to a property of the same type.

<DataGridComboBoxColumn 
    Header="Typ"
    SelectedValueBinding="{Binding Type, Mode=TwoWay}" 
    SelectedValuePath="Id"
    DisplayMemberPath="Name">

If you had a ToolTypeId property, you'd use SelectedValuePath to bind to that:

class ToolModel
{
    public long Id { get; set; }
    public string Number { get; set; }
    public string Name { get; set; }
    public string Coating { get; set; }
    public bool Thread { get; set; }
    public string Kind { get; set; }

    //  Like so
    public long ToolTypeId { get; set; }

    public ToolTypeModel Type { get; set; }
}

And in the XAML:

<DataGridComboBoxColumn 
    Header="Typ"
    SelectedValueBinding="{Binding ToolTypeId}" 
    SelectedValuePath="Id"
    DisplayMemberPath="Name">

But I don't think that's what you want. I think it's pretty clear you want to get an actual ToolTypeModel instance in your Type property.

So this should work (I just tested it). Take car, however: Overriding Equals() is a little sketchy because it changes the semantics of the C# = and != operators for that class, which can bite you.

public class ToolTypeModel
{
    public long Id { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return (obj is ToolTypeModel)
                    ? (obj as ToolTypeModel).Id == Id
                    : false;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

XAML:

<DataGridComboBoxColumn
    Header="Type"
    SelectedItemBinding="{Binding Type}" 
    DisplayMemberPath="Name"
    >

(Also, get rid of Mode=TwoWay -- that's the default for bindings on that property, you'll get it anyway).

Upvotes: 5

Related Questions