I'm trying to implement column chooser functionality for a DataGrid and am running into problems if I try to define the content of the header for the column as something more than just a string. Below is a very simplified example with all styles, view models, binding, etc all stripped out.
There are 3 columns:
The first column uses a string for the header. The second column tries to set the header content to a Label with a ToolTip. The third column ties to set the header content to a TextBlock with a ToolTip.
Clicking the Toggle Visibility button for Column A works fine. The Toggle Visibility buttons for both Columns B and C cause an InvalidOperationException with the message "Specified element is already the logical child of another element. Disconnect it first."
<Window x:Class="DataGridColumnChoosing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,10">
<TextBlock Margin="15, 0">Toggle Visibility:</TextBlock>
<Button Click="ToggleA">Column A</Button>
<Button Click="ToggleB">Column B</Button>
<Button Click="ToggleC">Column C</Button>
</StackPanel>
<!-- Main Fuel Mileage Datagrid -->
<DataGrid x:Name="mySampleDataGrid" Grid.Row="1"
AutoGenerateColumns="False" CanUserSortColumns="False" CanUserResizeRows="False" CanUserAddRows="False"
GridLinesVisibility="All" RowHeaderWidth="0">
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="colA" Width="40*" IsReadOnly="True" Header="Column A">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="colB" Width="40*" IsReadOnly="True" >
<DataGridTemplateColumn.Header>
<Label Content="Column B" ToolTip="A short explanation of Column B"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="colC" Width="40*" IsReadOnly="True" >
<DataGridTemplateColumn.Header>
<TextBlock Text="Column C" ToolTip="A short explanation of Column C " />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
The simple click event handlers for the buttons that are toggling the visibility in this example are simply modifying the visibility of the columns.
private void ToggleA(object sender, RoutedEventArgs e)
{
colA.Visibility = colA.Visibility == System.Windows.Visibility.Visible ? System.Windows.Visibility.Hidden : System.Windows.Visibility.Visible;
}
private void ToggleB(object sender, RoutedEventArgs e)
{
colB.Visibility = colB.Visibility == System.Windows.Visibility.Visible ? System.Windows.Visibility.Hidden : System.Windows.Visibility.Visible;
}
private void ToggleC(object sender, RoutedEventArgs e)
{
colC.Visibility = colC.Visibility == System.Windows.Visibility.Visible ? System.Windows.Visibility.Hidden : System.Windows.Visibility.Visible;
}
Thanks all.
I had this issue once when I had a control defined in my Resources, and was trying to use it within multiple control's Content areas. That does not work because the control can only belong to one parent.
Instead, I needed to define a Template of some kind which contained the control I wanted, and set the Template of my object instead of the content directly.
Your comment on @Gimno's answer makes me think this is the case.
Try changing it so instead of setting a Label/TextBox in DataGrid.Header's content directly, set DataGrid.HeaderTemplate to a DataTemplate which contains the Label or TextBox.
EDIT
Here's some example code
<DataGridTemplateColumn x:Name="colB" Width="40*" IsReadOnly="True" >
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<Label Content="Column B" ToolTip="A short explanation of Column B"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I think it would be easiest if you just use DataGridTemplateColumn.HeaderStyle
instead of DataGridTemplateColumn.Header
As example for column c:
<DataGridTemplateColumn x:Name="colC" Width="40*" IsReadOnly="True" >
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Column C" ToolTip="A short explanation of Column C "/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.HeaderStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGridTemplateColumn.HeaderStyle>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With