1 // Permission is hereby granted, free of charge, to any person obtaining 2 // a copy of this software and associated documentation files (the 3 // "Software"), to deal in the Software without restriction, including 4 // without limitation the rights to use, copy, modify, merge, publish, 5 // distribute, sublicense, and/or sell copies of the Software, and to 6 // permit persons to whom the Software is furnished to do so, subject to 7 // the following conditions: 8 // 9 // The above copyright notice and this permission notice shall be 10 // included in all copies or substantial portions of the Software. 11 // 12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 // 20 // Copyright (c) 2007 Novell, Inc. 21 // 22 // Author: 23 // Carlos Alberto Cortez <calberto.cortez@gmail.com> 24 // Ivan Zlatev <contact@i-nz.net> 25 // 26 27 using System; 28 using System.Collections; 29 using System.ComponentModel; 30 using System.Reflection; 31 using System.Collections.Generic; 32 33 namespace System.Windows.Forms 34 { 35 36 public static class ListBindingHelper 37 { GetList(object list)38 public static object GetList (object list) 39 { 40 if (list is IListSource) 41 return ((IListSource) list).GetList (); 42 return list; 43 } 44 GetList(object dataSource, string dataMember)45 public static object GetList (object dataSource, string dataMember) 46 { 47 dataSource = GetList (dataSource); 48 if (dataSource == null || dataMember == null || dataMember.Length == 0) 49 return dataSource; 50 51 PropertyDescriptor property = GetListItemProperties (dataSource).Find (dataMember, true); 52 if (property == null) 53 throw new ArgumentException ("dataMember"); 54 55 object item = null; 56 57 ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider; 58 if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) { 59 CurrencyManager currencyManager = currencyManagerProvider.CurrencyManager; 60 if (currencyManager != null && currencyManager.Count > 0 && currencyManager.Current != null) 61 item = currencyManager.Current; 62 } 63 64 if (item == null) { 65 if (dataSource is IEnumerable) { 66 if (dataSource is IList) { 67 IList list = (IList) dataSource; 68 item = list.Count > 0 ? list[0] : null; 69 } else { 70 IEnumerator e = ((IEnumerable) dataSource).GetEnumerator (); 71 if (e != null && e.MoveNext ()) 72 item = e.Current; 73 } 74 } else { 75 item = dataSource; 76 } 77 } 78 79 if (item != null) 80 return property.GetValue (item); 81 return null; 82 } 83 GetListItemType(object list)84 public static Type GetListItemType (object list) 85 { 86 return GetListItemType (list, String.Empty); 87 } 88 GetListItemType(object dataSource, string dataMember)89 public static Type GetListItemType (object dataSource, string dataMember) 90 { 91 if (dataSource == null) 92 return null; 93 94 if (dataMember != null && dataMember.Length > 0) { 95 PropertyDescriptor property = GetProperty (dataSource, dataMember); 96 if (property == null) 97 return typeof (object); 98 99 return property.PropertyType; 100 } 101 102 if (dataSource is Array) 103 return dataSource.GetType ().GetElementType (); 104 105 // IEnumerable seems to have higher precedence over IList 106 if (dataSource is IEnumerable) { 107 IEnumerator enumerator = ((IEnumerable) dataSource).GetEnumerator (); 108 if (enumerator.MoveNext () && enumerator.Current != null) 109 return enumerator.Current.GetType (); 110 111 if (dataSource is IList || dataSource.GetType () == typeof (IList<>)) { 112 PropertyInfo property = GetPropertyByReflection (dataSource.GetType (), "Item"); 113 if (property != null) // `Item' could be interface-explicit, and thus private 114 return property.PropertyType; 115 } 116 117 // fallback to object 118 return typeof (object); 119 } 120 121 return dataSource.GetType (); 122 } 123 GetListItemProperties(object list)124 public static PropertyDescriptorCollection GetListItemProperties (object list) 125 { 126 return GetListItemProperties (list, null); 127 } 128 GetListItemProperties(object list, PropertyDescriptor [] listAccessors)129 public static PropertyDescriptorCollection GetListItemProperties (object list, PropertyDescriptor [] listAccessors) 130 { 131 list = GetList (list); 132 133 if (list == null) 134 return new PropertyDescriptorCollection (null); 135 136 if (list is ITypedList) 137 return ((ITypedList)list).GetItemProperties (listAccessors); 138 139 if (listAccessors == null || listAccessors.Length == 0) { 140 Type item_type = GetListItemType (list); 141 return TypeDescriptor.GetProperties (item_type, 142 new Attribute [] { new BrowsableAttribute (true) }); 143 } 144 145 // Take into account only the first property 146 Type property_type = listAccessors [0].PropertyType; 147 if (typeof (IList).IsAssignableFrom (property_type) || typeof (IList<>).IsAssignableFrom (property_type)) { 148 149 PropertyInfo property = GetPropertyByReflection (property_type, "Item"); 150 return TypeDescriptor.GetProperties (property.PropertyType); 151 } 152 153 return new PropertyDescriptorCollection (new PropertyDescriptor [0]); 154 } 155 GetListItemProperties(object dataSource, string dataMember, PropertyDescriptor [] listAccessors)156 public static PropertyDescriptorCollection GetListItemProperties (object dataSource, string dataMember, 157 PropertyDescriptor [] listAccessors) 158 { 159 throw new NotImplementedException (); 160 } 161 GetListName(object list, PropertyDescriptor [] listAccessors)162 public static string GetListName (object list, PropertyDescriptor [] listAccessors) 163 { 164 if (list == null) 165 return String.Empty; 166 167 Type item_type = GetListItemType (list); 168 return item_type.Name; 169 } 170 GetProperty(object obj, string property_name)171 static PropertyDescriptor GetProperty (object obj, string property_name) 172 { 173 return TypeDescriptor.GetProperties (obj, 174 new Attribute [] { new BrowsableAttribute (true) })[property_name]; 175 } 176 177 // 178 // Need to use reflection as we need to bypass the TypeDescriptor.GetProperties () limitations 179 // GetPropertyByReflection(Type type, string property_name)180 static PropertyInfo GetPropertyByReflection (Type type, string property_name) 181 { 182 foreach (PropertyInfo prop in type.GetProperties (BindingFlags.Public | BindingFlags.Instance)) 183 if (prop.Name == property_name) 184 return prop; 185 186 return null; 187 } 188 } 189 } 190