Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Smart Behavior for DataGrid.AutoGenerateColumns

0.00/5 (No votes)
27 Sep 2014 1  
Using AutoGenerateColumns to generate exactly as needed data columns

Introduction

When you use the DateGrid control to populate tabular data, the DataGrid.AutoGenerateColumns property provides a handy approach to generate data columns dynamically. However, the DataGrid actually displays all properties with property name instead of header name. It would be helpful if you have control about the column generation. This article presents a solution to easily specify the header information while getting the benefits from the DataGrid.AutoGenerateColumns.

Using the Code

The solution introduces a smart Behavior object plugged into the DateGrid so that the header information specified in the attributes of the data item will be generated automatically. In the data item:

  1. You can specify the string to be displayed for each column header
  2. You can specify a blank header; and
  3. You can decide which columns to show or hide with little effort

It takes three steps to use the Behavior object.

  1. Add the reference of System.Windows.Interactivity, and add the SmartColumnBehavior.cs to the project.
  2. Specify the header in the property of the data item with the attribute. If you don’t want to display the property, don’t add the attribute. Here is a self-explanatory example of “attributed” Data Item.
    public class DataItem
    {
        // Don't create this column
        public int Id { get; set; }
    
        // Blank header
        [DisplayName(" ")]
        public bool AddToBag { get; set; }
    
        [DisplayName("Theme Name")]
        public string ThemeName { get; set; }
    } 
  3. In the XAML file, plug in the Behavior object as follows:
    <Window ...
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:local="clr-namespace:AttributtedDataColumn" /> 
    
    <DataGrid ItemsSource="{Binding DataItems}" >
        <i:Interaction.Behaviors>
            <local:SmartColumnBehavior />
        </i:Interaction.Behaviors>
    </DataGrid> 

And now, you are ready to compile and run!

Under the Hood

The DataGrid.AutoGeneratingColumn event offers you an opportunity to manipulate the data columns during the process of column generation if you set the DataGrid.AutoGenerateColumns property to true. There are many ways to implement the event handler. I elect to wrap it in a Behavior object to make it pluggable and reusable. When being attached to the DataGrid control, it gives the DataGrid an additional behavior. In this implementation, the logic in the event handler detects the attribute of data item’s property, and returns information for generating the column and header information according. Furthermore, if you need more features such as icons, filters, etc., you can add your extension to the Behavior object. Following is the source code of the Behavior.

public class ColumnHeaderBehavior : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        AssociatedObject.AutoGeneratingColumn += 
            new EventHandler<DataGridAutoGeneratingColumnEventArgs>(OnAutoGeneratingColumn);       
    }

    protected override void OnDetaching()
    {
        AssociatedObject.AutoGeneratingColumn -= 
            new EventHandler<DataGridAutoGeneratingColumnEventArgs>(OnAutoGeneratingColumn);
    }

    protected void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        string displayName = GetPropertyDisplayName(e.PropertyDescriptor);
        if (!string.IsNullOrEmpty(displayName))
        {
            e.Column.Header = displayName;
        }
        else
        {
            e.Cancel = true;
        }
    }

    protected static string GetPropertyDisplayName(object descriptor)
    {
        PropertyDescriptor pd = descriptor as PropertyDescriptor;
        if (pd != null)
        {               
            DisplayNameAttribute attr = pd.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
            if ((attr != null) && (attr != DisplayNameAttribute.Default))
            {
                return attr.DisplayName;
            }
        }
        else
        {
            PropertyInfo pi = descriptor as PropertyInfo;
            if (pi != null)
            {
                Object[] attrs = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true);
                foreach (var att in attrs)
                {
                    DisplayNameAttribute attribute = att as DisplayNameAttribute;
                    if ((attribute != null) && (attribute != DisplayNameAttribute.Default))
                    {
                        return attribute.DisplayName;
                    }
                }
            }
        }
        return null;
    }
}   

The Behavior class is a generic class design to attach additional behaviors to a control. In the example, the control type is the DataGrid. Therefore I derive the SmartColumnBehavior class from Behavior. I then override the OnAttached() method. The class encapsulates the column generation logic, and will be attached to the DataGrid in the XAML. When the DataGrid generates data columns, DataGrid.AutoGeneratingColumn event will be fired for each data column. This is the place to handle the custom column generation. In the Behavior object, I subscribed the AutoGeneratingColumn event, and detected the header display name. For each property in the data item, if I can find the display name in the attribute, I assign it to the column header in e.Column.Header. If I cannot find the attribute, I cancel the column generation by setting e.Cancel to true. The e.Column property contains a lot of properties for custom column generation. The above is just a simple implementation.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here