How to get DataGridColumnHeader from DataGridColumn?
Asked Answered
D

2

8

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?

Dump answered 27/10, 2010 at 7:11 Comment(0)
R
18

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);
        }
    }
}
Resolute answered 27/10, 2010 at 8:33 Comment(7)
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?!Kesterson
@Vibo: Try the Loaded event for DataGridResolute
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!Kesterson
@Vibo: Otherwise you can use the ItemContainerGenerator.StatusChanged event of DataGrid and compare the status to ContainersGenerated in the event handlerResolute
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.Kesterson
Do you know if there's a way to do this in Silverlight? The DataGridColumnHeader has no Column property to compare against.Vivianna
Is the Visual specific to Silverlight? I can't find it with WPF (.NET 8.0).Glossy
H
6

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 */ }
Heartless answered 8/6, 2014 at 8:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.