sr28 sr28 - 1 year ago 60
C# Question

How can I bind DataGrid Column to a property within an anonymous type as part of LINQ GroupBy?

I've got a WPF project, which contains a DataGrid. Here is the grid:

<DataGrid Name="dgMyGrid" AutoGenerateColumns="False" Height="120">
<DataGridTextColumn Header="File Name" Binding="{Binding source}" />
<DataGridTextColumn Header="Count" Binding="{Binding count}" />

As you can see, I'm hoping to bind the first column to a property called 'source' and the second column to a property called 'count'.

My data source for the datagrid is created like this:

var fileList = listFlaws.OrderBy(x => x.sourceFile)
.GroupBy(y => new {
sourcePath = y.sourceFilePath,
source = y.sourceFile,
count = listFlaws.Where(z => z.sourceFilePath == y.sourceFilePath).Count()

dgMyGrid.ItemsSource = fileList;

The datagrid is blank when I try and bind to the properties in the anonymous type. However, I do seem to be able to bind to the properties on the type within listFlaws, such as sourceFile. Unfortunately, the whole point of the anonymous type is to try and give me a way to bind a count property as well.

So how can I bind to the properties within the anonymous type, mainly 'source' and 'count'?

Answer Source

Because you used GroupBy, fileList is a sequence of Group objects, not a sequence of your anonymous type. Since you're grouping by the anonymous object, that'll be in the Key property of the Group. That's what GroupBy does: The selector lambda returns a key, and GroupBy returns/yields/whatever a sequence of Group objects, representing the original sequence grouped by whatever set of keys your selector gave it.

<DataGridTextColumn Header="File Name" Binding="{Binding Key.source}" />
<DataGridTextColumn Header="Count" Binding="{Binding Key.count}" />

The Group itself is enumerable. If you were to bind that to an ItemsSource somewhere, that would enumerate the items from listFlaws that were grouped by the anonymous-typed key value for that Group, if you care about those.

For example,

var evenOdd = Enumerable.Range(1, 6)
              .GroupBy(y => (y & 1) == 0)

That will yield a sequence of the following two Groups:

Group.Key == false
((IEnumerable)Group) == [1, 3, 5]

Group.Key == true
((IEnumerable)Group) == [2, 4, 6]