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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
28 using System
.Reflection
;
29 using System
.Collections
;
30 using System
.ComponentModel
;
32 namespace System
.Windows
.Forms
{
33 public class CurrencyManager
: BindingManagerBase
{
35 protected int listposition
;
36 protected Type finalType
;
39 private bool binding_suspended
;
41 private object data_source
;
45 internal CurrencyManager ()
49 internal CurrencyManager (object data_source
)
51 SetDataSource (data_source
);
58 public override object Current
{
60 if (listposition
== -1 || listposition
>= list
.Count
)
61 throw new IndexOutOfRangeException ("list position");
62 return list
[listposition
];
66 public override int Count
{
67 get { return list.Count; }
70 public override int Position
{
77 if (value == list
.Count
)
78 value = list
.Count
- 1;
79 if (listposition
== value)
82 if (listposition
!= -1)
86 OnCurrentChanged (EventArgs
.Empty
);
87 OnPositionChanged (EventArgs
.Empty
);
91 internal void SetDataSource (object data_source
)
93 if (this.data_source
is IBindingList
)
94 ((IBindingList
)this.data_source
).ListChanged
-= new ListChangedEventHandler (ListChangedHandler
);
96 if (data_source
is IListSource
)
97 data_source
= ((IListSource
)data_source
).GetList();
99 this.data_source
= data_source
;
100 if (data_source
!= null)
101 this.finalType
= data_source
.GetType();
104 if (this.data_source
is IBindingList
)
105 ((IBindingList
)this.data_source
).ListChanged
+= new ListChangedEventHandler (ListChangedHandler
);
107 list
= (IList
)data_source
;
109 // XXX this is wrong. MS invokes OnItemChanged directly, which seems to call PushData.
110 ListChangedHandler (null, new ListChangedEventArgs (ListChangedType
.Reset
, -1));
113 public override PropertyDescriptorCollection
GetItemProperties ()
116 Type element
= list
.GetType ().GetElementType ();
117 return TypeDescriptor
.GetProperties (element
);
120 if (list
is ITypedList
) {
121 return ((ITypedList
)list
).GetItemProperties (null);
124 PropertyInfo
[] props
= data_source
.GetType().GetProperties ();
125 for (int i
= 0; i
< props
.Length
; i
++) {
126 if (props
[i
].Name
== "Item") {
127 Type t
= props
[i
].PropertyType
;
128 if (t
== typeof (object))
130 return GetBrowsableProperties (t
);
134 if (list
.Count
> 0) {
135 return GetBrowsableProperties (list
[0].GetType ());
138 return new PropertyDescriptorCollection (null);
141 public override void RemoveAt (int index
)
143 list
.RemoveAt (index
);
146 public override void SuspendBinding ()
148 binding_suspended
= true;
151 public override void ResumeBinding ()
153 binding_suspended
= false;
156 internal override bool IsSuspended
{
157 get { return binding_suspended; }
160 // XXX this needs re-addressing once DataViewManager.AllowNew is implemented
161 internal bool CanAddRows
{
163 /* if we're readonly, don't even bother checking if we can add new rows */
167 if (list
is IBindingList
) {
169 //return ((IBindingList)list).AllowNew;
176 public override void AddNew ()
178 if (list
as IBindingList
== null)
179 throw new NotSupportedException ();
181 (list
as IBindingList
).AddNew ();
185 listposition
= list
.Count
- 1;
187 OnCurrentChanged (EventArgs
.Empty
);
188 OnPositionChanged (EventArgs
.Empty
);
194 IEditableObject editable
= Current
as IEditableObject
;
196 if (editable
!= null) {
198 editable
.BeginEdit ();
202 /* swallow exceptions in IEditableObject.BeginEdit () */
207 public override void CancelCurrentEdit ()
209 if (listposition
== -1)
212 IEditableObject editable
= Current
as IEditableObject
;
214 if (editable
!= null) {
216 editable
.CancelEdit ();
217 OnItemChanged (new ItemChangedEventArgs (Position
));
221 public override void EndCurrentEdit ()
223 if (listposition
== -1)
226 IEditableObject editable
= Current
as IEditableObject
;
228 if (editable
!= null) {
234 public void Refresh ()
236 ListChangedHandler (null, new ListChangedEventArgs (ListChangedType
.Reset
, -1));
239 protected void CheckEmpty ()
241 if (list
== null || list
.Count
< 1)
242 throw new Exception ("List is empty.");
246 protected internal override void OnCurrentChanged (EventArgs e
)
250 if (onCurrentChangedHandler
!= null) {
251 onCurrentChangedHandler (this, e
);
255 protected virtual void OnItemChanged (ItemChangedEventArgs e
)
257 if (ItemChanged
!= null)
258 ItemChanged (this, e
);
261 protected virtual void OnPositionChanged (EventArgs e
)
263 if (onPositionChangedHandler
!= null)
264 onPositionChangedHandler (this, e
);
267 protected internal override string GetListName (ArrayList accessors
)
269 if (list
is ITypedList
) {
270 PropertyDescriptor
[] pds
= null;
271 if (accessors
!= null) {
272 pds
= new PropertyDescriptor
[accessors
.Count
];
273 accessors
.CopyTo (pds
, 0);
275 return ((ITypedList
) list
).GetListName (pds
);
277 else if (finalType
!= null) {
278 return finalType
.Name
;
283 protected override void UpdateIsBinding ()
287 foreach (Binding binding
in Bindings
)
288 binding
.UpdateIsBinding ();
291 private void UpdateItem ()
293 // Probably should be validating or something here
294 if (listposition
!= -1) {
297 else if (list
.Count
> 0) {
305 internal object this [int index
] {
306 get { return list [index]; }
309 private PropertyDescriptorCollection
GetBrowsableProperties (Type t
)
311 Attribute
[] att
= new System
.Attribute
[1];
312 att
[0] = new BrowsableAttribute (true);
313 return TypeDescriptor
.GetProperties (t
, att
);
316 private void OnMetaDataChanged (EventArgs args
)
318 if (MetaDataChanged
!= null)
319 MetaDataChanged (this, args
);
322 private void ListChangedHandler (object sender
, ListChangedEventArgs e
)
324 switch (e
.ListChangedType
) {
325 case ListChangedType
.PropertyDescriptorAdded
:
326 case ListChangedType
.PropertyDescriptorDeleted
:
327 case ListChangedType
.PropertyDescriptorChanged
:
328 OnMetaDataChanged (EventArgs
.Empty
);
330 case ListChangedType
.ItemDeleted
:
331 if (listposition
== e
.NewIndex
) {
332 listposition
= e
.NewIndex
- 1;
333 OnCurrentChanged (EventArgs
.Empty
);
334 OnPositionChanged (EventArgs
.Empty
);
337 OnItemChanged (new ItemChangedEventArgs (-1));
339 case ListChangedType
.ItemAdded
:
340 if (listposition
== -1) {
341 /* do we need this logic up above in ItemDeleted as well? */
342 listposition
= e
.NewIndex
== 0 ? 0 : e
.NewIndex
- 1;
343 OnCurrentChanged (EventArgs
.Empty
);
344 OnPositionChanged (EventArgs
.Empty
);
347 OnItemChanged (new ItemChangedEventArgs (-1));
349 case ListChangedType
.ItemChanged
:
351 OnItemChanged (new ItemChangedEventArgs (e
.NewIndex
));
355 OnItemChanged (new ItemChangedEventArgs (-1));
356 // UpdateIsBinding ();
361 public event ItemChangedEventHandler ItemChanged
;
362 public event EventHandler MetaDataChanged
;