Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF 4 DataGrid: Showing & Hiding Columns

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.

like image 997
Greg Andora Avatar asked Mar 18 '11 15:03

Greg Andora


2 Answers

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>
like image 78
Rachel Avatar answered Oct 23 '22 12:10

Rachel


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>
like image 45
Gimno Avatar answered Oct 23 '22 12:10

Gimno