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?

BartoszKP
  • 34,786
  • 15
  • 102
  • 130

2 Answers2

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);
        }
    }
}
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
  • 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?! – Konrad Morawski Aug 04 '11 at 10:06
  • @Vibo: Try the Loaded event for DataGrid – Fredrik Hedblad Aug 04 '11 at 10:34
  • 1
    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! – Konrad Morawski Aug 04 '11 at 10:43
  • 1
    @Vibo: Otherwise you can use the ItemContainerGenerator.StatusChanged event of DataGrid and compare the status to ContainersGenerated in the event handler – Fredrik Hedblad Aug 04 '11 at 11:50
  • 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. – Konrad Morawski Aug 04 '11 at 11:59
  • Do you know if there's a way to do this in Silverlight? The DataGridColumnHeader has no Column property to compare against. – Tevin Jun 13 '12 at 13:55
5

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 */ }
Community
  • 1
  • 1
Ben
  • 3,241
  • 4
  • 35
  • 49