1
votes

I need to dynamically set the contents within the template of a DataGrid based on information in an external settings file. That settings file specifies which data fields should display in the DataGrid. The administrator of the application can edit the settings to change the fields to display. I cannot hard-code the fields to display.

I can easily add the columns (DataGridTextColumn's) to the DataGrid at runtime. I set a binding to a field in the item source based on the settings, and that displays fine.

Now I need to display details when the user clicks a row. I set up a RowDetailsTemplate with DataTemplate, and added a Grid (or a StackPanel) inside to format the details. If I add to the markup the TextBlocks with bindings to fields, it displays the details just fine.

But how can I set the content of the Grid/StackPanel in the details template programmatically? The Grid/StackPanel controls are null if I try to reference them by name on startup (e.g., in the page Loaded event). I have tried using the Loaded event on the Grid/StackPanel to add the details. That code runs and appears to add the content to the Grid/StackPanel, but nothing actually appears when I click the row. I'm guessing that the problem is that the template/Grid is already loaded and ignores the changes I'm making.

Here's a sample of the code I'm using in the handler for the Loaded event. Even if I do something as simple as this, the details pane doesn't appear when clicking on the row.

<data:DataGrid.RowDetailsTemplate>
    <DataTemplate>
        <Border Background="LightBlue" >
            <StackPanel x:Name="resultsDetailsPanel"
                Orientation="Vertical"
                Loaded="resultsDetailsPanel_Loaded">
            </StackPanel>
        </Border>
    </DataTemplate>
</data:DataGrid.RowDetailsTemplate>



    private void resultsDetailsPanel_Loaded(object sender, RoutedEventArgs e)
    {
        if (_resultsGridLoaded)
            return;

        StackPanel detailsPanel = sender as StackPanel;

        TextBlock fieldNameTextBlock = new TextBlock();
        fieldNameTextBlock.Text = "TESTING";
        detailsPanel.Children.Add(fieldNameTextBlock);

        _resultsGridLoaded = true;
    }
1

1 Answers

1
votes

I actually tried your code and is working. Two things you should check:

  • Is your _resultsGridLoaded variable initialized as false?
  • Did you set RowDetailsVisibilityMode="VisibleWhenSelected" on your DataGrid?

UPDATE: For some reason is not working anymore. But I did found two ways you can fix it:

  1. Remove the resultsGridLoaded logic.
  2. If you need that logic, you can add a handler for the SelectionChanged event on the DataGrid, in there you can set the _resultsGridLoaded variable to false so the new StackPanel gets its content added correctly:


    
        
            
                
                
            
        
    


And the code behind:

private void resultsPanel_Loaded(object sender, RoutedEventArgs e)
{
    if (_resultsGridLoaded)
        return;

    StackPanel pane = (StackPanel)sender;

    TextBlock newChild = new TextBlock()
    {
        Text = "New text"
    };

    pane.Children.Add(newChild);

    _resultsGridLoaded = true;
}

private void grid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    _resultsGridLoaded = false;
}

Hope this helps