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