Reputation: 856
I have a DataGrid filled with data. What I would like to do is modifying the template of a particular row in order to display both the row and a new header. For example:
Header 1 | Header 2 | Header 3
Data 1 | Data 2 | Data 3 (row 1)
Data 1 | Data 2 | Data 3 (row 2)
Header 1 | Header 2 | Header 3 | Header 4 | Header 5 (row 3)
Data 1 | Data 2 | Data 3 | Data 4 | Data 5 (row 3)
Data 1 | Data 2 | Data 3 (row 4)
Here is a screen shot illustrating my needs.
Is there a way to achieve this? Thank you.
Upvotes: 0
Views: 2518
Reputation: 856
I finally found a way to achieve what I was trying to do:
I set the DataGrid.ItemTemplateSelector property with a Selector derived from DataTemplateSelector. In the SelectTemplate() method of this selector, I return null for a normal row (to apply the default template), otherwise I create and return the DataTemplate (dynamically, thanks to XamlReader) corresponding to the special row. This template is composed of a DataGrid. The ItemsSource property of the DataGrid is set using a converter (row data converted into an object list).
Upvotes: 2
Reputation: 22702
I have managed to create the following:
If I understand correctly, in this case, you must use a nested DataGrid
. This effect can be achieved by DataGridTemplateColumn.CellTemplate -> your DataTemplate
. Also, the pattern should be "normal" TextBlock
, so it shows some value when nested DataGrid
hidden. Checks will be carried out using DataTrigger
in DataTemplate
.
XAML code:
<DataGrid Name="SimpleDataGrid" AutoGenerateColumns="False" RowHeaderWidth="0" CanUserAddRows="False" CanUserResizeColumns="False" CanUserResizeRows="False" Loaded="SimpleDataGrid_Loaded">
<DataGrid.Columns>
<DataGridTemplateColumn Width="1.5*" Header="HeaderWithDataGrid" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<!-- Nested DataGrid -->
<DataGrid Name="InsertedDataGrid" AutoGenerateColumns="False" RowHeaderWidth="0" Loaded="InsertedDataGrid_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Header="InsertedHeader1" Width="1.5*" Binding="{Binding Name}" IsReadOnly="False" />
<DataGridTextColumn Header="InsertedHeader2" Width="1.5*" Binding="{Binding Age}" IsReadOnly="False" />
<DataGridTextColumn Header="InsertedHeader3" Width="1.5*" Binding="{Binding Name}" IsReadOnly="False" />
</DataGrid.Columns>
</DataGrid>
<!-- Simply value, if nested DataGrid will be Hidden -->
<TextBlock Name="SimpleValue" Text="{Binding Age}" Visibility="Hidden" />
</Grid>
<DataTemplate.Triggers>
<!-- It checks for Hidden NestedDataGrid -->
<DataTrigger Binding="{Binding ShowInsertedGrid}" Value="Hidden">
<Setter TargetName="InsertedDataGrid" Property="Visibility" Value="Collapsed" />
<Setter TargetName="SimpleValue" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Simply column -->
<DataGridTextColumn Header="SimpleHeader" Width="1.5*" Binding="{Binding Name}" IsReadOnly="False" />
</DataGrid.Columns>
</DataGrid>
Listing of Person class:
public class Person
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
// For clarity using string.
// In real project using a bool.
public string ShowInsertedGrid
{
get;
set;
}
}
Two ObservableCollection
for DataGrid's:
private ObservableCollection<Person> DataForDataGrid = new ObservableCollection<Person>();
private ObservableCollection<Person> DataForInsertedDataGrid = new ObservableCollection<Person>();
In handler Loaded
event set data for main DataGrid:
private void SimpleDataGrid_Loaded(object sender, RoutedEventArgs e)
{
DataForDataGrid.Add(new Person()
{
Age = 2,
Name = "Nick",
ShowInsertedGrid = "Hidden", // Hidden NestedDataGrid
});
DataForDataGrid.Add(new Person()
{
Age = 1,
Name = "Sam",
});
DataForDataGrid.Add(new Person()
{
Name = "Kate",
Age = 15,
ShowInsertedGrid = "Hidden", // Hidden NestedDataGrid
});
SimpleDataGrid.ItemsSource = DataForDataGrid;
}
Loaded
event handler for NestedDataGrid:
private void InsertedDataGrid_Loaded(object sender, RoutedEventArgs e)
{
DataGrid MyDataGrid = sender as DataGrid;
DataForInsertedDataGrid.Add(new Person()
{
Name = "Bob",
Age = 15,
});
DataForInsertedDataGrid.Add(new Person()
{
Name = "SpanchBob",
Age = 151,
});
MyDataGrid.ItemsSource = DataForInsertedDataGrid;
}
For beauty and for improving the appearance using the Styles
.
EDIT:
If you want your Nested DataGrid
was on the whole Row, then I can suggest the following solution (not the fact that it is the best solution, but I can only offer this):
For each cell will use DataTemplate. Therefore SimpleHeader
transformed into:
<DataGridTemplateColumn Width="1.5*" Header="SimpleHeader" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<!-- Nested DataGrid -->
<DataGrid Name="InsertedDataGrid2" AutoGenerateColumns="False" RowHeaderWidth="0" Loaded="InsertedDataGrid2_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Header="InsertedHeader4" Width="1.5*" Binding="{Binding Name}" IsReadOnly="False" />
<DataGridTextColumn Header="InsertedHeader5" Width="1.5*" Binding="{Binding Age}" IsReadOnly="False" />
<DataGridTextColumn Header="InsertedHeader6" Width="1.5*" Binding="{Binding Name}" IsReadOnly="False" />
</DataGrid.Columns>
</DataGrid>
<!-- Simply value, if nested DataGrid will be Hidden -->
<TextBlock Name="SimpleValue" Text="{Binding Name}" Visibility="Hidden" />
</Grid>
<DataTemplate.Triggers>
<!-- It checks for Hidden NestedDataGrid -->
<DataTrigger Binding="{Binding ShowInsertedGrid}" Value="Hidden">
<Setter TargetName="InsertedDataGrid2" Property="Visibility" Value="Collapsed" />
<Setter TargetName="SimpleValue" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Where InsertedDataGrid2_Loaded
you set the data:
private void InsertedDataGrid2_Loaded(object sender, RoutedEventArgs e)
{
DataGrid MyDataGrid = sender as DataGrid;
DataForInsertedDataGrid2.Add(new Person()
{
Name = "Bob2",
Age = 215,
});
DataForInsertedDataGrid2.Add(new Person()
{
Name = "SpanchBob2",
Age = 251,
});
MyDataGrid.ItemsSource = DataForInsertedDataGrid2;
}
For each column using DataGrid
, and the code you load data for it. Hence, calculate the total number of columns for the main and nested DataGrid
.
Upvotes: 1