|
namespace System.Windows.Forms {
using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")] // Shipped in Everett
public abstract class BindingManagerBase
{
private BindingsCollection bindings;
private bool pullingData = false;
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.onCurrentChangedHandler"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected EventHandler onCurrentChangedHandler;
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.onPositionChangedHandler"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected EventHandler onPositionChangedHandler;
// Hook BindingComplete events on all owned Binding objects, and propagate those events through our own BindingComplete event
private BindingCompleteEventHandler onBindingCompleteHandler = null;
// same deal about the new currentItemChanged event
internal EventHandler onCurrentItemChangedHandler;
// Event handler for the DataError event
internal BindingManagerDataErrorEventHandler onDataErrorHandler;
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.Bindings"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public BindingsCollection Bindings {
get {
if (bindings == null) {
bindings = new ListManagerBindingsCollection(this);
// Hook collection change events on collection, so we can hook or unhook the BindingComplete events on individual bindings
bindings.CollectionChanging += new CollectionChangeEventHandler(OnBindingsCollectionChanging);
bindings.CollectionChanged += new CollectionChangeEventHandler(OnBindingsCollectionChanged);
}
return bindings;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.OnBindingComplete"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal protected void OnBindingComplete(BindingCompleteEventArgs args) {
if (onBindingCompleteHandler != null) {
onBindingCompleteHandler(this, args);
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.OnCurrentChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal protected abstract void OnCurrentChanged(EventArgs e);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.OnCurrentItemChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal protected abstract void OnCurrentItemChanged(EventArgs e);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.OnDataError"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal protected void OnDataError(Exception e) {
if (onDataErrorHandler != null) {
onDataErrorHandler(this, new BindingManagerDataErrorEventArgs(e));
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.Current"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract Object Current {
get;
}
internal abstract void SetDataSource(Object dataSource);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.BindingManagerBase"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public BindingManagerBase() { }
[
SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors") // If the constructor does not call SetDataSource
// it would be a breaking change.
]
internal BindingManagerBase(Object dataSource) {
this.SetDataSource(dataSource);
}
internal abstract Type BindType{
get;
}
internal abstract PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.GetItemProperties"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public virtual PropertyDescriptorCollection GetItemProperties() {
return GetItemProperties(null);
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.GetItemProperties1"]/*' />
protected internal virtual PropertyDescriptorCollection GetItemProperties(ArrayList dataSources, ArrayList listAccessors) {
IList list = null;
if (this is CurrencyManager) {
list = ((CurrencyManager)this).List;
}
if (list is ITypedList) {
PropertyDescriptor[] properties = new PropertyDescriptor[listAccessors.Count];
listAccessors.CopyTo(properties, 0);
return ((ITypedList)list).GetItemProperties(properties);
}
return this.GetItemProperties(this.BindType, 0, dataSources, listAccessors);
}
// listType is the type of the top list in the list.list.list.list reference
// offset is how far we are in the listAccessors
// listAccessors is the list of accessors (duh)
//
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.GetItemProperties2"]/*' />
protected virtual PropertyDescriptorCollection GetItemProperties(Type listType, int offset, ArrayList dataSources, ArrayList listAccessors) {
if (listAccessors.Count < offset)
return null;
if (listAccessors.Count == offset) {
if (typeof(IList).IsAssignableFrom(listType)) {
System.Reflection.PropertyInfo[] itemProps = listType.GetProperties();
// PropertyDescriptorCollection itemProps = TypeDescriptor.GetProperties(listType);
for (int i = 0; i < itemProps.Length; i ++) {
if ("Item".Equals(itemProps[i].Name) && itemProps[i].PropertyType != typeof(object))
return TypeDescriptor.GetProperties(itemProps[i].PropertyType, new Attribute[] {new BrowsableAttribute(true)});
}
// return the properties on the type of the first element in the list
IList list = dataSources[offset - 1] as IList;
if (list != null && list.Count > 0)
return TypeDescriptor.GetProperties(list[0]);
} else {
return TypeDescriptor.GetProperties(listType);
}
return null;
}
System.Reflection.PropertyInfo[] props = listType.GetProperties();
// PropertyDescriptorCollection props = TypeDescriptor.GetProperties(listType);
if (typeof(IList).IsAssignableFrom(listType)) {
PropertyDescriptorCollection itemProps = null;
for (int i = 0; i < props.Length; i++) {
if ("Item".Equals(props[i].Name) && props[i].PropertyType != typeof(object)) {
// get all the properties that are not marked as Browsable(false)
//
itemProps = TypeDescriptor.GetProperties(props[i].PropertyType, new Attribute[] {new BrowsableAttribute(true)});
}
}
if (itemProps == null) {
// use the properties on the type of the first element in the list
// if offset == 0, then this means that the first dataSource did not have a strongly typed Item property.
// the dataSources are added only for relatedCurrencyManagers, so in this particular case
// we need to use the dataSource in the currencyManager. See ASURT 83035.
IList list;
if (offset == 0)
list = this.DataSource as IList;
else
list = dataSources[offset - 1] as IList;
if (list != null && list.Count > 0) {
itemProps = TypeDescriptor.GetProperties(list[0]);
}
}
if (itemProps != null) {
for (int j=0; j<itemProps.Count; j++) {
if (itemProps[j].Equals(listAccessors[offset]))
return this.GetItemProperties(itemProps[j].PropertyType, offset + 1, dataSources, listAccessors);
}
}
} else {
for (int i = 0; i < props.Length; i++) {
if (props[i].Name.Equals(((PropertyDescriptor)listAccessors[offset]).Name))
return this.GetItemProperties(props[i].PropertyType, offset + 1, dataSources, listAccessors);
}
}
return null;
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.BindingComplete"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public event BindingCompleteEventHandler BindingComplete {
add {
onBindingCompleteHandler += value;
}
remove {
onBindingCompleteHandler -= value;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.CurrentChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public event EventHandler CurrentChanged {
add {
onCurrentChangedHandler += value;
}
remove {
onCurrentChangedHandler -= value;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.CurrentItemChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public event EventHandler CurrentItemChanged {
add {
onCurrentItemChangedHandler += value;
}
remove {
onCurrentItemChangedHandler -= value;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.DataError"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public event BindingManagerDataErrorEventHandler DataError {
add {
onDataErrorHandler += value;
}
remove {
onDataErrorHandler -= value;
}
}
internal abstract String GetListName();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.CancelCurrentEdit"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract void CancelCurrentEdit();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.EndCurrentEdit"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract void EndCurrentEdit();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.AddNew"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract void AddNew();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.RemoveAt"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract void RemoveAt(int index);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.Position"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public abstract int Position{get; set;}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.PositionChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public event EventHandler PositionChanged {
add {
this.onPositionChangedHandler += value;
}
remove {
this.onPositionChangedHandler -= value;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.UpdateIsBinding"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected abstract void UpdateIsBinding();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.GetListName"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal abstract String GetListName(ArrayList listAccessors);
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.SuspendBinding"]/*' />
public abstract void SuspendBinding();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.ResumeBinding"]/*' />
public abstract void ResumeBinding();
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.PullData"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected void PullData() {
bool success;
PullData(out success);
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.PullData1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal void PullData(out bool success) {
success = true;
pullingData = true;
try {
UpdateIsBinding();
int numLinks = Bindings.Count;
for (int i = 0; i < numLinks; i++) {
if (Bindings[i].PullData()) {
success = false;
}
}
}
finally {
pullingData = false;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.PushData"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected void PushData() {
bool success;
PushData(out success);
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.PushData1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
internal void PushData(out bool success) {
success = true;
if (pullingData)
return;
UpdateIsBinding();
int numLinks = Bindings.Count;
for (int i = 0; i < numLinks; i++) {
if (Bindings[i].PushData()) {
success = false;
}
}
}
internal abstract object DataSource {
get;
}
internal abstract bool IsBinding {
get;
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.IsBindingSuspended"]/*' />
/// <devdoc>
/// <devdoc>
public bool IsBindingSuspended {
get {
return !IsBinding;
}
}
/// <include file='doc\BindingMAnagerBase.uex' path='docs/doc[@for="BindingManagerBase.Count"]/*' />
public abstract int Count {
get;
}
// BindingComplete events on individual Bindings are propagated up through the BindingComplete event on
// the owning BindingManagerBase. To do this, we have to track changes to the bindings collection, adding
// or removing handlers on items in the collection as appropriate.
//
// For the Add and Remove cases, we hook the collection 'changed' event, and add or remove handler for
// specific binding.
//
// For the Refresh case, we hook both the 'changing' and 'changed' events, removing handlers for all
// items that were in the collection before the change, then adding handlers for whatever items are
// in the collection after the change.
//
private void OnBindingsCollectionChanged(object sender, CollectionChangeEventArgs e) {
Binding b = e.Element as Binding;
switch (e.Action) {
case CollectionChangeAction.Add:
b.BindingComplete += new BindingCompleteEventHandler(Binding_BindingComplete);
break;
case CollectionChangeAction.Remove:
b.BindingComplete -= new BindingCompleteEventHandler(Binding_BindingComplete);
break;
case CollectionChangeAction.Refresh:
foreach (Binding bi in bindings) {
bi.BindingComplete += new BindingCompleteEventHandler(Binding_BindingComplete);
}
break;
}
}
private void OnBindingsCollectionChanging(object sender, CollectionChangeEventArgs e) {
if (e.Action == CollectionChangeAction.Refresh) {
foreach (Binding bi in bindings) {
bi.BindingComplete -= new BindingCompleteEventHandler(Binding_BindingComplete);
}
}
}
internal void Binding_BindingComplete(object sender, BindingCompleteEventArgs args) {
this.OnBindingComplete(args);
}
}
}
|