HowTo: Enabling custom attributes to GridView

1 posts, 0 answers
  1. Andreas
    Andreas avatar
    8 posts
    Member since:
    Nov 2012

    Posted 22 Jan 2013 Link to this post

    Hey folks.

    The past 2 months i was implementing an application using the telerik controls.
    Awesome control set by the way. Love them.

    But there is a slight disadvantage as i thought. The setup of columns for the RadGridView.
    There is the possibility to use AutoGenerateColumns or just set them up in your .xaml.
    For your information i am using a MVVM implementation. The problem for me, i have views which are basicly the same.
    They only differ in some additional columns for the grid.

    I have come up that AutoGenerateColumns is just an awesome feature to give a simple ViewItem into a list an set the list as ItemsSource, now my columns just show up. Adding some annotations to the properties is just a cool way to give them special behavior.

    But what about custom annotations? E.g. disable distinct filters and to so on. Fortunatly RadGridView supports basic annotations (System.ComponentModel.DataAnnotations) which is good, but not perfect.

    To enhance this, i have come up to implement CustomAttributes.
    Here you can see my simple CustomAttribute class:
    /// <summary>
    ///     Abstract class for custom attributes.
    ///     This class is used to filter only our custom attribute using reflection.
    /// </summary>
    public abstract class CustomAttribute : System.Attribute
    {
        /// <summary>
        ///     Updates a given colum using the implementers logic.
        /// </summary>
        /// <param name="column">The <see cref="GridViewColumn"/> to update.</param>
        public abstract void UpdateColumn(GridViewColumn column);
    }

    As you can see i have added an abstract method UpdateColumn() this method will be implemented in each attribute you like to use.
    This is used to updated the column which your own logic. As seen here, a simple ShowDistinctFilterAttribute:

    /// <summary>
    ///     Enables or disabled the distinct filter functionality of a <see cref="GridViewColumn"/>
    /// </summary>
    public class ShowDistinctFilterAttribute : CustomAttribute
    {
        public bool DistinctFilters { get; private set; }
     
        public ShowDistinctFilterAttribute(bool b)
        {
            DistinctFilters = b;
        }
     
        /// <summary>
        ///     Updates a given colum using the implementers logic.
        /// </summary>
        /// <param name="column">The <see cref="GridViewColumn"/> to update.</param>
        public override void UpdateColumn(GridViewColumn column)
        {
            column.ShowDistinctFilters = DistinctFilters;
        }
    }

    Now things gettin' serious. We need to intercept the autogenerating of columns.
    We need a class derived from RadGridView. Giving you this:

    public class BaseGridView<TViewItemType> : RadGridView
    {
        /// <summary>
        ///     Raises the AutoGeneratingColumn event.
        /// </summary>
        protected override void OnAutoGeneratingColumn(GridViewAutoGeneratingColumnEventArgs e)
        {
            /**
             * This method gets overridden to update the autogenerated columns
             * with our own custom attributes. The update itself it handled
             * in the attribute class itself using the UpdateColumn() method.
             */
     
            // first we need the type of the current viewitem.
            var viewItemType = typeof (TViewItemType);
            // next up we are getting the property
            // this property should have some attributes assigned to it.
            var property = viewItemType.GetProperty(e.ItemPropertyInfo.Name);
     
            // first off, check if the property even exists
            if (property != null)
            {
                // now we only get custom attributes of a certain type
                // each attribute we want will derive from CustomAttribute class
                var attribs = property.GetCustomAttributes(typeof(CustomAttribute), true);
     
                // check if custom attributes are assigned to the current property
                if (attribs.Any())
                {
                    // iterate through a casted list
                    // this is needed to get reference to the UpdateColumn() method.
                    foreach (var attrib in attribs.Cast<CustomAttribute>().ToArray())
                    {
                        // update our column
                        attrib.UpdateColumn(e.Column);
                    }
                }
            }
     
            // call base functionality
            base.OnAutoGeneratingColumn(e);
        }
    }

    You might ask why this class is a generic type. Well since we are using reflection to get our custom attributes. We need to now which type our items are using. RadGridView itself is a bit "well sealed" of getting the datetype of a column item so i come up with this solution. I am skipping the explanation how this code works, i hope the comment lines are enough for this :)

    Now you simply need to derive from this BaseGridView<T> to create the grid you need.

    public class CustomerGridView : BaseGridView<GridViewItem>
    {
    }

    And the GridViewItem you might want to use with our own attribute:

    public class GridViewItem
    {
        /// <summary>
        ///     Gets or sets the the awesome attribute.
        /// </summary>
        [ShowDistinctFilter(false)]
        public string Attribute
        {
            get { return "Awesome attribute"; }
            set { }
        }
    }

    Now only create a list to set your ItemsSource

    radGridView.ItemsSource = new List<GridViewItem> { new GridViewItem() };


    Hope i could help some of you out there :)
    Greets.
Back to Top