Click here to Skip to main content
15,881,248 members
Articles / Desktop Programming / WPF

A Smart Behavior for DataGrid.AutoGenerateColumns

Rate me:
Please Sign up or sign in to vote.
4.87/5 (21 votes)
27 Sep 2014CPOL3 min read 53.3K   1.1K   19   8
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.
    C#
    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:
    XML
    <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.

C#
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<datagrid>. 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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Jagd336-Nov-15 6:23
Jagd336-Nov-15 6:23 
GeneralMy vote of 4 Pin
Roberto Mazzone30-Sep-14 21:34
Roberto Mazzone30-Sep-14 21:34 
QuestionI really appreciate solid, constructive articles like this. Pin
Brian Stevens30-Sep-14 10:44
Brian Stevens30-Sep-14 10:44 
GeneralThanks Pin
sonic4142-Sep-14 22:16
sonic4142-Sep-14 22:16 
GeneralRe: Thanks Pin
Frank W. Wu3-Sep-14 2:41
Frank W. Wu3-Sep-14 2:41 
GeneralGreat Pin
RamNow24-Jul-14 6:03
professionalRamNow24-Jul-14 6:03 
GeneralMy vote of 5 Pin
neyerMat5-Dec-13 5:02
neyerMat5-Dec-13 5:02 
GeneralMy vote of 5 Pin
Saravana Perumal C4-Oct-12 22:35
Saravana Perumal C4-Oct-12 22:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.