views:

492

answers:

1

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;
    }
A: 

Hello, 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

Arturo Molina
That's interesting that it works for you. I'll try a simpler version of my page - must be something else going on. I do initialize the _resultsGridLoaded to false, and the RowDetailsVisibilityMode is set to VisibleWhenSelected, so it must be something else, but thanks for the clues!
Bryan B
I think I found the problem. Check the solution on my updated post. For some reason, StackOverflow is now showing my XMAL, but I basically just added the SelectionChange event to the DataGrid. Let me know if it helps, good luck!
Arturo Molina
Thanks! It works now. The key was indeed in resetting the _resultsGridLoaded flag to false in the SelectionChanged handler for the DataGrid. That causes the data to be loaded each time the details view is opened. Seems strange that you'd need to do that every time, but it works. BTW, I don't have enough points to mark your answer as helpful, otherwise I would.
Bryan B
Glad I could help, don't worry about marking the answer as useful. But I think you can mark it as the accepted answer. Regards
Arturo Molina