I have a DataTable that has several columns defined. I then added another columns that should contain an icon based on the data of the table itself, i.e. the data contains the icon ID than in the proper row in the column "Icons" the right icon shall appear.
My data is generated like this:
var cat = ReportTexts.Instance.Sheets.Param;
workSheet = excel.Workbook.Worksheets[cat];
outReport.ParametersDT = workSheet.ToDataTable(true);
outReport.ParametersDT.Columns.Add("Icons", typeof(BitmapImage));
foreach (DataRow row in outReport.ParametersDT.Rows)
row["Icons"] = this.GetIconImageFromParameterReference(row[ReportTexts.Instance.Headers.Type]);
Then in my xaml file i did this:
<TabControl DockPanel.Dock="Top" TabStripPlacement="Top">
<TabItem Header="{Binding Path=LoadedReport.Configuration.Title}">
<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="TEMP" />
<DataGrid
AutoGenerateColumns="True"
DataContext="{Binding Path=LoadedReport.ParametersDT.DefaultView, Source={StaticResource ResourceKey=VM}}"
DockPanel.Dock="Top"
ItemsSource="{Binding Path=LoadedReport.ParametersDT.DefaultView.Table, Source={StaticResource ResourceKey=VM}}"/>
</DockPanel>
</TabItem>
</TabControl>
The result is similar to what I am looking to but not quite, as shown in the screenshot:
After looking around here in SO i found that the good idea would be to define a DataGidCellTemplate and then filetr it by header, so I did this:
<TabControl DockPanel.Dock="Top" TabStripPlacement="Top">
<TabItem Header="{Binding Path=LoadedReport.Configuration.Title}">
<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="TEMP" />
<DataGrid
AutoGenerateColumns="True"
DataContext="{Binding Path=LoadedReport.ParametersDT.DefaultView, Source={StaticResource ResourceKey=VM}}"
DockPanel.Dock="Top"
ItemsSource="{Binding Path=LoadedReport.ParametersDT.DefaultView.Table, Source={StaticResource ResourceKey=VM}}">
<DataGridTemplateColumn Header="Icons">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image
Width="50"
Height="25"
Source="{Binding UriSource}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
</DockPanel>
</TabItem>
</TabControl>
Sadly, this compiles but then throws a System.InvalidOperationException
stating that the elements' collection must be empty before using ItemsSource. (my native language is italian, so the translation might be a little off, here is the VS one: 'La raccolta di elementi deve essere vuota prima di poter utilizzare ItemsSource.')
I am a bit stuck here, what am I doing wrong?
EDIT and ANSWERS:
I was pointed to 2 solutions, one entirely base on xaml and one that relies on code behind.
the first one simply consists in inserting the whole DataGridTemplateColumn
node inside a DataGrid.Columns
node, like this:
<DataGrid.Columns>
<DataGridTemplateColumn CellTemplate="{StaticResource ResourceKey=IconColumn}" Header="NewColumnHeader" />
</DataGrid.Columns>
Since I need to do the exact addition to several tables i declared the template as StaticResource
and bound the data with a Converter
that manages the various cases.
The main issue with this approach is that instead of changing the template of the existing column I am adding a new one, hence the header "NewColumnHeader".
The second solution is the one linked by @ASh, where you manage the automatic column generation event in the code behind to change the existing column to your desire. This solution let me do what I intended in the first place, but more importantly let me work even deeper in the column structure. this is the question link: Answer to the question about images in datagrid by @ASh