Requirements
I would like to add a column with comboboxes to a WPF DataGrid meeting the following requirements:
Sample Application
The application uses the code provided in the DataGridComboBoxColumn. It works, but has 2 problems:
the Details DropDown lists the entries alphabetically. In my real application I have many more entries and it is very difficult to find the right one when they are not sorted.
It takes 4 mouse clicks to change a ComboBox value.
Code
XAML:
<Window x:Class="SortedComboBoxDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SortedComboBoxDataGrid"
xmlns:core="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<CollectionViewSource x:Key="SamplesViewSource" CollectionViewType="ListCollectionView"/>
<ObjectDataProvider x:Key="myEnum" MethodName="GetValues" ObjectType="{x:Type core:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type Type="local:DetailEnum"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<DataGrid x:Name="MainDataGrid" DataContext="{StaticResource SamplesViewSource}" ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=SomeText}" Header="SomeText"/>
<DataGridComboBoxColumn Header="Detail" SelectedItemBinding="{Binding Detail}"
ItemsSource="{Binding Source={StaticResource myEnum}}"/>
</DataGrid.Columns>
</DataGrid>
</Window>
Enum DetailEnum:
namespace SortedComboBoxDataGrid {
public enum DetailEnum {
No,
Some,
Many,
All
}
Sample class:
public class Sample {
public string SomeText { get; set; }
public DetailEnum Detail { get; set; }
public Sample(string someText, DetailEnum detail) {
SomeText = someText;
Detail = detail;
}
}
}
Window code behind:
using System.Collections.Generic;
using System.Windows;
namespace SortedComboBoxDataGrid {
public partial class MainWindow: Window {
public MainWindow() {
InitializeComponent();
var samples = new List<Sample>() {
new Sample("first", DetailEnum.All),
new Sample("second", DetailEnum.Many),
new Sample("any", DetailEnum.Some),
new Sample("last", DetailEnum.No),
};
var samplesViewSource = ((System.Windows.Data.CollectionViewSource)(FindResource("SamplesViewSource")));
samplesViewSource.Source = samples;
}
}
}
What I have tried already
I tried Displaying sorted enum values in a ComboBox. This sorts enums nicely, but to do so it converts the enum values into strings, then sorts those strings. If the user clicks on a different entry, the grid returns a string and not an enumeration value.
I tried various solutions I found on stackoverflow to reduce the number of tricks, but could not get one working properly with sorted (!) enums.
I wonder if it would be better to use for the ComboBox a list of class instances having the enum value and the enum name as its properties instead of a List ?
public class DetailEnumClass {
public DetailEnum EnumValue { get; set; }
public string EnumName { get; set; }
}
Please read this before marking this question as a duplicate
I am aware there are already many answers on stackoverflow regarding one or the other problem I mentioned here. However, I am not able to come up with a working solution which covers all requirements. So please only mark this question as a duplicate if you have found an answer which provides full code for the complete problem. Thanks.
You could use a DataGridTemplateColumn
with a ComboBox
that binds to a sorted IEnumerable<DetailEnum>
that you create yourself in the code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
Resources.Add("enums",
Enum.GetValues(typeof(DetailEnum)).Cast<DetailEnum>().OrderBy(x => x.ToString()));
InitializeComponent();
...
}
}
XAML:
<DataGrid x:Name="MainDataGrid" AutoGenerateColumns="False">
<DataGrid.Resources>
<DataTemplate x:Key="dt">
<ComboBox ItemsSource="{StaticResource enums}"
SelectedItem="{Binding Detail, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=SomeText}" Header="SomeText"/>
<DataGridTemplateColumn Header="Detail" CellTemplate="{StaticResource dt}" CellEditingTemplate="{StaticResource dt}" />
</DataGrid.Columns>
</DataGrid>