Denis Schaf
Denis Schaf

Reputation: 2759

WPF Datagrid enum combobox column

In a WPF DataGrid, if I use AutoGenerateColumns and bind it to my collection of class objects, it displays enums as a combobox automatically where I can choose between all options available in the enum:

<DataGrid ItemsSource="{Binding SettingsList}"/>

enter image description here

However, if I explicitly declare it in XAML:

<DataGrid.Columns>
    <DataGridComboBoxColumn Header="Mirroring" SelectedValuePath="{Binding Mirroring}"/>
</DataGrid.Columns>

enter image description here

It seems to not recognize the options available in the enum. I am certain I am missing something minor, like setting the item source to something, but I can't figure out what to set it to to make it work out of the box like when using auto generate, of course I can write a custom converter to get all values to set the item source, but it feels like I am missing a builtin way to make it work.

Upvotes: 0

Views: 72

Answers (1)

IV.
IV.

Reputation: 9438

You said:

I am certain I am missing something minor, like setting the item source to something.


For setting the item source (and in general) what works best for me is managing the columns in code-behind, and since column definitions are part of the UI's presentation logic and don’t include business logic or state management, this doesn’t violate MVVM.


XAML: DataGrid AutoGenerateColumns=False

<Window ...>
    <Window.DataContext>
        <local:MainWindowViewModel x:Name="MainWindowViewModel"/>
    </Window.DataContext>
    <Grid>
        <DataGrid  
            Name="dataGrid" ItemsSource="{Binding Items}" AutoGenerateColumns="False"
            CanUserAddRows="False" FontSize="14" RowHeight="30">
        </DataGrid>
    </Grid>
</Window>
Configure columns in Code-Behind
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Loaded += (sender, e) =>
        {
            dataGrid.Columns.Add(new DataGridComboBoxColumn 
            {
                Header = nameof(Item.Mirroring),
                SelectedValueBinding = new Binding(nameof(Item.Mirroring)),
                ItemsSource = Enum.GetValues<Mirroring>(),
                Width = 150,
            });
            dataGrid.Columns.Add(new DataGridTextColumn
            {
                Header = nameof(Item.Name),                    
                Binding = new Binding(nameof(Item.Name)), 
                Width = new DataGridLength(1, DataGridLengthUnitType.Star)
            });
        };
    }
}

XAML Approach

If you prefer to stick with the XAML column declarations, one way to do it is have the view model provide the items source (here I made a singleton to do the enumeration one time). But now we strain a little to express in XAML what is so straightforward in code-behind.

class MainWindowViewModel
{
    public ObservableCollection<Item> Items { get; } =
        new(Enumerable.Range(0,5).Select(_=>new Item(_)));

    public Array ComboBoxValues
    {
        get
        {
            if (_comboBoxValues is null)
            {
                _comboBoxValues = Enum.GetValues<Mirroring>();
            }
            return _comboBoxValues;
        }
    }
    static Array? _comboBoxValues = default;
}

<Window ...>
    <Window.DataContext>
        <local:MainWindowViewModel x:Name="MainWindowViewModel"/>
    </Window.DataContext>
    <Grid>
        <DataGrid  
            Name="dataGrid" ItemsSource="{Binding Items}" AutoGenerateColumns="False"
            CanUserAddRows="False" FontSize="14" RowHeight="30">
            <DataGrid.Columns>
                <DataGridComboBoxColumn
                    Header="Mirroring" 
                    SelectedValueBinding="{Binding Mirroring}"               
                    ItemsSource="{Binding ComboBoxValues, Source={x:Reference MainWindowViewModel}}"
                    Width="150" />
                <DataGridTextColumn
                    Header="Name" 
                    Binding="{Binding Name}"
                    Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Either Way

enum values showing

Upvotes: 1

Related Questions