AdditionalDataFieldNames/RetrieveAllDataFields
By default Telerik RadGrid will fetch all bindable property values from the data source you use for control structure generation. They will be further used in sorting, filtering, grouping or other operations. In some cases, however, you may not need your grid instance to iterate through all the fields in your data source upon binding. Generally, this can be a requirement when you have custom collection of business objects which you pass to the DataSource property of Telerik RadGrid to generate its content.
To prevent the grid from traversing all data fields in that collection you just have to set the property RadGridInstance.MasterTableView.RetrieveAllDataFields to false. In this case, the additional fields that you might use when sorting, grouping or used in DataKeyNames should be included in the AdditionalDataFieldNames array. With the settings specified in this paragraph, only the properties that are used as column DataFields or those specified in the AdditionalDataFieldNames will be extracted.
Alternative binding to custom collections
Currently Telerik RadGrid supports sorting, filtering and grouping natively. This is represented by three collections of corresponding expressions:
GridTableView.SortExpressions
GridTableView.GroupByExpressions
GridTableView.FilterExpression
All these features are not tightly coupled with the column declarations of the grid but with the data that the grid is bound to.
To clarify the idea, let us consider this scenario:
For example, you have a grid instance on webform with 2 columns - ProductName and ProductCategory. In the DataSource, you have these fields: ProductID, Units, TotalOrders, TotalCost, etc. Imagine that this is a table (or business object collection) describing orders of products.
Then you can display the grid with two columns and a group by expression: ProductCategory, ProductID, Sum(TotalCost), Sum(TotalOrders), Group By ProductID, ProductCategory. It is obvious that columns declaration and grouping, sorting, etc. can have different meanings. That is why, by default Telerik RadGrid processes all bindable properties of your business object collection.
When it comes to designing the business objects collections, Telerik RadGrid would be smart enough to comply with .NET standards when binding to ITypedList, IListSource, IEnumerable and so on.
The example web page below has 2 RadGrid and 2 GridView controls, binding to an object data source, with corresponding auto-generated or pre-defined column sets. The business object implements ICustomTypeDescriptor with modified presentation structure using attributes.
The properties that are not visible for presentation have the [PresentationHidden] attribute. Here is the code-behind:
BusinesObject
| C# |
Copy Code |
|
using System; using System.Web; using System.Collections.Generic; using System.ComponentModel; using System.Web.UI;
using BusinessObjects;
public class BusinessObjectList : BindingList<BusinessObject>, ITypedList { public BusinessObjectList() { this.Add( new BusinessObject(null, null, new SubObject("Four"))); this.Add( new BusinessObject(1, "1", new SubObject("One"))); this.Add( new BusinessObject(2, "3", new SubObject("Two"))); this.Add( new BusinessObject(3, "2", new SubObject("Three"))); this.Add( new BusinessObject(4, "1", new SubObject("Four"))); }
public BindingList<BusinessObject> GetList() { return this; }
#region ITypedList Members
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) { return CustomTypeDescriptorHelper.GetExtendedProperties( typeof(BusinessObject)); }
public string GetListName(PropertyDescriptor[] listAccessors) { return "DefaultView"; }
#endregion }
public class SubObject { private string _name;
public SubObject(string name) { this._name = name; }
public string Name { get { return _name; } set { _name = value; } } }
public class BusinessObject: ICustomTypeDescriptor { private long? _objectId; private string _stringProperty; private SubObject _subObject;
public BusinessObject(int? objectId, string stringProperty, SubObject subObject) { this._objectId = objectId; this._stringProperty = stringProperty; this._subObject = subObject; }
public long? ObjectId { get { return _objectId; } set { _objectId = value; } }
public string StringProperty { get { return _stringProperty; } set { _stringProperty = value; } }
//The PresentationHidden attribute would "hide" the property from GridView and RadGrid [PresentationHidden] public string ShouldNotBeAccesseed { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
//using the IntroduceObject attribute the custom type descriptor helper would //recognize the objects to introduce sub-properties [IntroduceObject] public SubObject SubObjectProperty { get { return _subObject; } set { _subObject = value; } }
//----------------------------------------------------------------------------------------- //This implementation of ICustomTypeDescriptor is general for all types of objects //that should serve as data-items in a data-list controls including RadGrid, DataGrid, //GridView, DataList, etc. //Note that the columns should be defined for the propertes of sub objects - no //auto-generated columns can be used, unless the collection oif object bound to the data-list //control implements the ITypedList intereface. //The DataField of such columns showing sub-properties should be constructed //from the name of the property + _ + name of the sub-property: //if sub-property is accessed using "SubProperty.Name" the DataField should be "SubProperty_Name". //Copy-paste the implementation to other business objects or implement in their base class. //Do not forget to mark the object, which contain subproperties as [IntroduceObject]. //----------------------------------------------------------------------------------------- #region ICustomTypeDescriptor Members
System.ComponentModel.AttributeCollection ICustomTypeDescriptor.GetAttributes() { return new System.ComponentModel.AttributeCollection(null); }
string ICustomTypeDescriptor.GetClassName() { return null; }
string ICustomTypeDescriptor.GetComponentName() { return null; }
TypeConverter ICustomTypeDescriptor.GetConverter() { return null; }
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return null; }
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { return null; }
object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return null; }
EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { return new EventDescriptorCollection(null); }
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { return new EventDescriptorCollection(null); }
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() { return ((ICustomTypeDescriptor)this).GetProperties(null); }
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) { return CustomTypeDescriptorHelper.GetExtendedProperties( TypeDescriptor.GetProperties(this, true) ); }
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) { return this; }
#endregion } |
| VB.NET |
Copy Code |
|
Imports System Imports System.ComponentModel Imports System.Web.UI
Namespace BusinessObjects
Friend Class IntroduceObjectAttribute Inherits Attribute End Class
Friend Class PresentationHidden Inherits Attribute End Class
Friend Class CustomTypeDescriptorHelper
Overloads Public Shared Function GetExtendedProperties(originalProperties As PropertyDescriptorCollection) As PropertyDescriptorCollection Dim originalArray(originalProperties.Count) As PropertyDescriptor originalProperties.CopyTo(originalArray, 0) Dim res As New PropertyDescriptorCollection(originalArray, False)
Dim aggObjectDescriptor As PropertyDescriptor For Each aggObjectDescriptor In originalProperties If Not (aggObjectDescriptor.Attributes(GetType(IntroduceObjectAttribute)) Is Nothing) Then Try Dim subObjectType As Type = aggObjectDescriptor.PropertyType Dim desc As PropertyDescriptor For Each desc In TypeDescriptor.GetProperties(subObjectType) If Telerik.WebControls.RadGrid.IsBindableType(desc.PropertyType) Then Dim descriptor As New AggregatedObjectPropertyDescriptor(aggObjectDescriptor.Name, desc) res.Add(descriptor) End If Next desc Catch Else End Try ElseIf Not (aggObjectDescriptor.Attributes(GetType(PresentationHidden)) Is Nothing) Then res.Remove(aggObjectDescriptor) End If Next aggObjectDescriptor
Return res End Function
Overloads Public Shared Function GetExtendedProperties(sourceType As Type) As PropertyDescriptorCollection Dim originalProperties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(sourceType) Return GetExtendedProperties(originalProperties) End Function End Class
Friend Class AggregatedObjectPropertyDescriptor Inherits PropertyDescriptor Private parentPropertyName As String Private subPropertyDesc As PropertyDescriptor
Private Const SubPropertySplitter As String = "_"
Friend Sub New(parentPropertyName As String, subPropertyDesc As PropertyDescriptor) MyBase.New(parentPropertyName + SubPropertySplitter + subPropertyDesc.Name, CType(Nothing, Attribute())) Me.subPropertyDesc = subPropertyDesc Me.parentPropertyName = parentPropertyName End Sub
Public Overrides Function CanResetValue(component As Object) As Boolean Throw New Exception("The method or operation is not implemented.") End Function
Public Overrides ReadOnly Property ComponentType() As Type Get Throw New Exception("The method or operation is not implemented.") End Get End Property
Public Overrides Function GetValue(component As Object) As Object Return subPropertyDesc.GetValue(DataBinder.GetPropertyValue(component, parentPropertyName)) End Function
Public Overrides ReadOnly Property IsReadOnly() As Boolean Get Return subPropertyDesc.IsReadOnly End Get End Property
Public Overrides ReadOnly Property PropertyType() As Type Get Return subPropertyDesc.PropertyType End Get End Property
Public Overrides Sub ResetValue(component As Object) Throw New Exception("The method or operation is not implemented.") End Sub
Public Overrides Sub SetValue(component As Object, value As Object) subPropertyDesc.SetValue(DataBinder.GetPropertyValue(component, parentPropertyName), value) End Sub
Public Overrides Function ShouldSerializeValue(component As Object) As Boolean Throw New Exception("The method or operation is not implemented.") End Function End Class End Namespace |
CustomTypeDescriptorHelper
| C# |
Copy Code |
|
using System; using System.ComponentModel; using System.Web.UI;
namespace BusinessObjects {
internal class IntroduceObjectAttribute : Attribute { }
internal class PresentationHidden : Attribute { }
internal class CustomTypeDescriptorHelper { public static PropertyDescriptorCollection GetExtendedProperties(PropertyDescriptorCollection originalProperties) { PropertyDescriptor[] originalArray = new PropertyDescriptor[originalProperties.Count]; originalProperties.CopyTo(originalArray, 0); PropertyDescriptorCollection res = new PropertyDescriptorCollection(originalArray, false);
foreach (PropertyDescriptor aggObjectDescriptor in originalProperties) { if (aggObjectDescriptor.Attributes[typeof(IntroduceObjectAttribute)] != null) { try { //This can be a recursive method to extract property values even deeper. Type subObjectType = aggObjectDescriptor.PropertyType; foreach (PropertyDescriptor desc in TypeDescriptor.GetProperties(subObjectType)) { if (Telerik.WebControls.RadGrid.IsBindableType(desc.PropertyType)) { AggregatedObjectPropertyDescriptor descriptor = new AggregatedObjectPropertyDescriptor(aggObjectDescriptor.Name, desc); res.Add(descriptor); } } } catch { //Is object's getter throws, just ignore } } else if (aggObjectDescriptor.Attributes[typeof(PresentationHidden)] != null) { res.Remove(aggObjectDescriptor); } }
return res; }
public static PropertyDescriptorCollection GetExtendedProperties(Type sourceType) { PropertyDescriptorCollection originalProperties = TypeDescriptor.GetProperties(sourceType); return GetExtendedProperties(originalProperties); } }
internal class AggregatedObjectPropertyDescriptor : PropertyDescriptor { private string parentPropertyName; private PropertyDescriptor subPropertyDesc;
private const string SubPropertySplitter = "_";
internal AggregatedObjectPropertyDescriptor( string parentPropertyName, PropertyDescriptor subPropertyDesc) : base(parentPropertyName + SubPropertySplitter + subPropertyDesc.Name, (Attribute[])null) { this.subPropertyDesc = subPropertyDesc; this.parentPropertyName = parentPropertyName; }
public override bool CanResetValue(object component) { throw new Exception("The method or operation is not implemented."); }
public override Type ComponentType { get { throw new Exception("The method or operation is not implemented."); } }
public override object GetValue(object component) { return subPropertyDesc.GetValue(DataBinder.GetPropertyValue(component, parentPropertyName)); }
public override bool IsReadOnly { get { return subPropertyDesc.IsReadOnly; } }
public override Type PropertyType { get { return subPropertyDesc.PropertyType; } }
public override void ResetValue(object component) { throw new Exception("The method or operation is not implemented."); }
public override void SetValue(object component, object value) { subPropertyDesc.SetValue(DataBinder.GetPropertyValue(component, parentPropertyName), value); }
public override bool ShouldSerializeValue(object component) { throw new Exception("The method or operation is not implemented."); } } } |
| VB.NET |
Copy Code |
|
Imports System Imports System.ComponentModel Imports System.Web.UI
Namespace BusinessObjects _
Friend Class IntroduceObjectAttribute Inherits Attribute End Class _
Friend Class PresentationHidden Inherits Attribute End Class _
Friend Class CustomTypeDescriptorHelper
Overloads Public Shared Function GetExtendedProperties(originalProperties As PropertyDescriptorCollection) As PropertyDescriptorCollection Dim originalArray(originalProperties.Count) As PropertyDescriptor originalProperties.CopyTo(originalArray, 0) Dim res As New PropertyDescriptorCollection(originalArray, False)
Dim aggObjectDescriptor As PropertyDescriptor For Each aggObjectDescriptor In originalProperties If Not (aggObjectDescriptor.Attributes(GetType(IntroduceObjectAttribute)) Is Nothing) Then Try Dim subObjectType As Type = aggObjectDescriptor.PropertyType Dim desc As PropertyDescriptor For Each desc In TypeDescriptor.GetProperties(subObjectType) If Telerik.WebControls.RadGrid.IsBindableType(desc.PropertyType) Then Dim descriptor As New AggregatedObjectPropertyDescriptor(aggObjectDescriptor.Name, desc) res.Add(descriptor) End If Next desc Catch End Try Else If Not (aggObjectDescriptor.Attributes(GetType(PresentationHidden)) Is Nothing) Then res.Remove(aggObjectDescriptor) End If End If Next aggObjectDescriptor Return res End Function
Overloads Public Shared Function GetExtendedProperties(sourceType As Type) As PropertyDescriptorCollection Dim originalProperties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(sourceType) Return GetExtendedProperties(originalProperties) End Function End Class _
Friend Class AggregatedObjectPropertyDescriptor Inherits PropertyDescriptor Private parentPropertyName As String Private subPropertyDesc As PropertyDescriptor
Private SubPropertySplitter As String = "_"
Friend Sub New(parentPropertyName As String, subPropertyDesc As PropertyDescriptor) MyBase. New(parentPropertyName + SubPropertySplitter + subPropertyDesc.Name, CType(Nothing, Attribute())) Me.subPropertyDesc = subPropertyDesc Me.parentPropertyName = parentPropertyName End Sub
Public Overrides Function CanResetValue(component As Object) As Boolean Throw New Exception("The method or operation is not implemented.") End Function
Public Overrides ReadOnly Property ComponentType() As Type Get Throw New Exception("The method or operation is not implemented.") End Get End Property
Public Overrides Function GetValue(component As Object) As Object Return subPropertyDesc.GetValue(DataBinder.GetPropertyValue(component, parentPropertyName)) End Function
Public Overrides ReadOnly Property IsReadOnly() As Boolean Get Return subPropertyDesc.IsReadOnly End Get End Property
Public Overrides ReadOnly Property PropertyType() As Type Get Return subPropertyDesc.PropertyType End Get End Property
Public Overrides Sub ResetValue(component As Object) Throw New Exception("The method or operation is not implemented.") End Sub
Public Overrides Sub SetValue(component As Object, value As Object) subPropertyDesc.SetValue(DataBinder.GetPropertyValue(component, parentPropertyName), value) End Sub
Public Overrides Function ShouldSerializeValue(component As Object) As Boolean Throw New Exception("The method or operation is not implemented.") End Function End Class End Namespace |
This implementation also allows both RadGrid and GridView (and other similar) controls to bind to properties of "sub-objects", which appear as properties of the business object, by just specifying the [IntroduceObject] attribute. The implementation of the ICustomTypeDescriptor interface for your business object constructs programmatically a new set of properties for the type, containing the properties of the sub-objects in a "flat" manner. This is similar to what the DataRowView generally does, for instance.
The implementation of ITypedList for the business-objects collection allows RadGrid and GridView to enumerate the properties of the business objects in the collection. This also allows Telerik RadGrid to automatically sort, group-by and filter these extended properties.