1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Web.Util;
namespace System.Web.UI.WebControls {
public class GridViewColumnsGenerator : AutoFieldsGenerator {
public override List<AutoGeneratedField> CreateAutoGeneratedFields(object dataObject, Control control) {
if (!(control is GridView)) {
throw new ArgumentException(SR.GetString(SR.InvalidDefaultAutoFieldGenerator, GetType().FullName, typeof(GridView).FullName));
}
Debug.Assert(dataObject == null || dataObject is PagedDataSource);
PagedDataSource dataSource = dataObject as PagedDataSource;
GridView gridView = control as GridView;
if (dataSource == null) {
// note that we're not throwing an exception in this case, and the calling
// code should be able to handle a null arraylist being returned
return null;
}
List<AutoGeneratedField> generatedFields = new List<AutoGeneratedField>();
PropertyDescriptorCollection propDescs = null;
bool throwException = true;
// try ITypedList first
// A PagedDataSource implements this, but returns null, if the underlying data source
// does not implement it.
propDescs = ((ITypedList)dataSource).GetItemProperties(new PropertyDescriptor[0]);
if (propDescs == null) {
Type sampleItemType = null;
object sampleItem = null;
IEnumerable realDataSource = dataSource.DataSource;
Debug.Assert(realDataSource != null, "Must have a real data source when calling CreateAutoGeneratedColumns");
Type dataSourceType = realDataSource.GetType();
// try for a typed Row property, which should be present on strongly typed collections
PropertyInfo itemProp = dataSourceType.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, null, new Type[] { typeof(int) }, null);
if (itemProp != null) {
sampleItemType = itemProp.PropertyType;
}
if ((sampleItemType == null) || (sampleItemType == typeof(object))) {
// last resort... try to get ahold of the first item by beginning the
// enumeration
IEnumerator e = dataSource.GetEnumerator();
if (e.MoveNext()) {
sampleItem = e.Current;
}
else {
// we don't want to throw an exception if we're bound to an IEnumerable
// data source with no records... we'll simply bail and not show any data
throwException = false;
}
if (sampleItem != null) {
sampleItemType = sampleItem.GetType();
}
// We must store the enumerator regardless of whether we got back an item from it
// because we cannot start the enumeration again, in the case of a DataReader.
// Code in CreateChildControls must deal appropriately for the case where
// there is a stored enumerator, but a null object as the first item.
gridView.StoreEnumerator(e, sampleItem);
}
if ((sampleItem != null) && (sampleItem is ICustomTypeDescriptor)) {
// Get the custom properties of the object
propDescs = TypeDescriptor.GetProperties(sampleItem);
}
else if (sampleItemType != null) {
// directly bindable types: strings, ints etc. get treated specially, since we
// don't care about their properties, but rather we care about them directly
if (ShouldGenerateField(sampleItemType, gridView)) {
AutoGeneratedFieldProperties fieldProps = new AutoGeneratedFieldProperties();
((IStateManager)fieldProps).TrackViewState();
fieldProps.Type = sampleItemType;
fieldProps.Name = "Item";
fieldProps.DataField = AutoGeneratedField.ThisExpression;
AutoGeneratedField field = CreateAutoGeneratedFieldFromFieldProperties(fieldProps);
if (field != null) {
generatedFields.Add(field);
AutoGeneratedFieldProperties.Add(fieldProps);
}
}
else {
// complex type... we get its properties
propDescs = TypeDescriptor.GetProperties(sampleItemType);
}
}
}
else {
if (propDescs.Count == 0) {
// we don't want to throw an exception if we're bound to an ITypedList
// data source with no records... we'll simply bail and not show any data
throwException = false;
}
}
if ((propDescs != null) && (propDescs.Count != 0)) {
string[] dataKeyNames = gridView.DataKeyNames;
int keyNamesLength = dataKeyNames.Length;
string[] dataKeyNamesCaseInsensitive = new string[keyNamesLength];
for (int i = 0; i < keyNamesLength; i++) {
dataKeyNamesCaseInsensitive[i] = dataKeyNames[i].ToLowerInvariant();
}
foreach (PropertyDescriptor pd in propDescs) {
Type propertyType = pd.PropertyType;
if (ShouldGenerateField(propertyType, gridView)) {
string name = pd.Name;
bool isKey = ((IList)dataKeyNamesCaseInsensitive).Contains(name.ToLowerInvariant());
AutoGeneratedFieldProperties fieldProps = new AutoGeneratedFieldProperties();
((IStateManager)fieldProps).TrackViewState();
fieldProps.Name = name;
fieldProps.IsReadOnly = isKey;
fieldProps.Type = propertyType;
fieldProps.DataField = name;
AutoGeneratedField field = CreateAutoGeneratedFieldFromFieldProperties(fieldProps);
if (field != null) {
generatedFields.Add(field);
AutoGeneratedFieldProperties.Add(fieldProps);
}
}
}
}
if ((generatedFields.Count == 0) && throwException) {
// this handles the case where we got back something that either had no
// properties, or all properties were not bindable.
throw new InvalidOperationException(SR.GetString(SR.GridView_NoAutoGenFields, gridView.ID));
}
return generatedFields;
}
private bool ShouldGenerateField(Type propertyType, GridView gridView) {
if (gridView.RenderingCompatibility < VersionUtil.Framework45 && AutoGenerateEnumFields == null) {
//This is for backward compatibility. Before 4.5, auto generating fields used to call into this method
//and if someone has overriden this method to force generation of columns, the scenario should still
//work.
return gridView.IsBindableType(propertyType);
}
else {
//If AutoGenerateEnumFileds is null here, the rendering compatibility must be 4.5
return DataBoundControlHelper.IsBindableType(propertyType, enableEnums: AutoGenerateEnumFields ?? true);
}
}
}
}
|