How to get DataGridColumnHeader from DataGridColumn?

15,022

Solution 1

The Header object of the DataGridColumn is actually the visible header of that column, whatever you set it to be. DataGridColumn is not part of the Visual Tree so there is not direct way to access the DataGridColumnHeader for it (we can't even be sure it exists yet). But you can do something like this to try and access it

DataGridColumnHeader headerObj = GetColumnHeaderFromColumn(column);

private DataGridColumnHeader GetColumnHeaderFromColumn(DataGridColumn column)
{
    // dataGrid is the name of your DataGrid. In this case Name="dataGrid"
    List<DataGridColumnHeader> columnHeaders = GetVisualChildCollection<DataGridColumnHeader>(dataGrid);
    foreach (DataGridColumnHeader columnHeader in columnHeaders)
    {
        if (columnHeader.Column == column)
        {
            return columnHeader;
        }
    }
    return null;
}

public List<T> GetVisualChildCollection<T>(object parent) where T : Visual
{
    List<T> visualCollection = new List<T>();
    GetVisualChildCollection(parent as DependencyObject, visualCollection);
    return visualCollection;
}

private void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < count; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, i);
        if (child is T)
        {
            visualCollection.Add(child as T);
        }
        else if (child != null)
        {
            GetVisualChildCollection(child, visualCollection);
        }
    }
}

Solution 2

While Fredrik's answer provides a refactored approach with additional method that could potentially be reused in other parts of the code, I preferred to consolidate his methods in to one single method. There may also be some small performance gain because it can end the search as soon as it finds the header and it does not need to continue to search through all the children in the visual tree (this is most likely negligible for most cases).

private DataGridColumnHeader GetHeader(DataGridColumn column, DependencyObject reference)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(reference, i);

        DataGridColumnHeader colHeader = child as DataGridColumnHeader;
        if ((colHeader != null) && (colHeader.Column == column))
        {
            return colHeader;
        }

        colHeader = GetHeader(column, child);
        if (colHeader != null)
        {
            return colHeader;
        }
    }

    return null;
}

And it is used like so:

DataGridColumnHeader colHeader = GetHeader(column, myDataGrid);
if (colHeader == null) { /* Not found */ }
Share:
15,022
Gurucharan Balakuntla Maheshku
Author by

Gurucharan Balakuntla Maheshku

“My objective is to provide solutions which can change the way people think and have a great impact on them” Software Engineering and Technology leader with 14+ years of experience in the IT industry leading and managing mid-scale to large scale digital systems (as Project Management, Product Management, People Management) across cross-functional teams and delivering highly performant, scalable, and secure systems. Well-versed in managing geographically distributed diverse teams across startups, MNC's and Enterprises. Deep knowledge in ​web architecture ​and ​technologies ​to solve challenging and complex business problems. Vast experience in recruiting and growing a team, instilling the right culture, motivating and retaining the best talents. I have served in diverse domains like Digital Web Apps, eCommerce, Payments, Enterprise applications, CRM, etc. with strong ​product and project management abilities.

Updated on July 28, 2022

Comments

  • Gurucharan Balakuntla Maheshku
    Gurucharan Balakuntla Maheshku almost 2 years

    My code is as follows:

     void mainDataContextObj_CutSelectedColumnEvent(string columnId)
        {
            IList<DataGridColumn> columns = dg.Columns;
    
            for(int i=2; i<dg.Columns.Count; i++)
            {
                DataGridColumnHeader headerObj = dg.Columns[i].Header as DataGridColumnHeader;
    
                 //This always returns headerObj as null!!!
    
            }
        }
    

    I need DataGridColumnHeader from the column. Where am I going wrong?

  • Konrad Morawski
    Konrad Morawski almost 13 years
    It is not available in the AutoGeneratedColumns event (it can't find any headers yet, it returns null). It does work afterwards. So when exactly are these headers created?!
  • Fredrik Hedblad
    Fredrik Hedblad almost 13 years
    @Vibo: Try the Loaded event for DataGrid
  • Konrad Morawski
    Konrad Morawski almost 13 years
    Thanks! I tried it indeed, but the drawback was it was only fired in the beginning, but if you regenerated the columns of the DataGrid by assigning some other data source to its DataContext, it wasn't triggered again. I tried every possible event and I discovered that LayoutUpdated does the trick!
  • Fredrik Hedblad
    Fredrik Hedblad almost 13 years
    @Vibo: Otherwise you can use the ItemContainerGenerator.StatusChanged event of DataGrid and compare the status to ContainersGenerated in the event handler
  • Konrad Morawski
    Konrad Morawski almost 13 years
    Good to know, thanks. Implementing it by LayoutUpdated was bit of a hack actually, because this event is fired quite often. Duct tape style, I just used a ignoreLayoutUpdated bool, setting it to false in those parts of the app where it actually does something to headers so they need to be taken care of, and resetting to true before exiting the event.
  • Tevin
    Tevin about 12 years
    Do you know if there's a way to do this in Silverlight? The DataGridColumnHeader has no Column property to compare against.