using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.Collections; using System.Windows.Forms; using System.Reflection; using System.Globalization; using DevComponents.DotNetBar.Primitives; namespace DevComponents.DotNetBar { /// /// Provides binding support for ItemPanel control. /// public class ItemVisualGenerator { #region Constructor private IBindingSupport _Parent = null; /// /// Initializes a new instance of the ItemVisualGenerator class. /// /// public ItemVisualGenerator(IBindingSupport parent) { _Parent = parent; } #endregion #region Implementation private object _DataSource = null; /// /// Gets or sets the data source for the ComboTree. Expected is an object that implements the IList or IListSource interfaces, /// such as a DataSet or an Array. The default is null. /// [AttributeProvider(typeof(IListSource)), Description("Indicates data source for the ComboTree."), Category("Data"), DefaultValue(null), RefreshProperties(RefreshProperties.Repaint)] public object DataSource { get { return _DataSource; } set { if (((value != null) && !(value is IList)) && !(value is IListSource)) { throw new ArgumentException("Data type is not supported for complex data binding"); } if (_DataSource != value) { if (DesignMode) _DataSource = value; else this.SetDataConnection(value, true); } } } private bool DesignMode { get { if (_Parent is IComponent && ((IComponent)_Parent).Site != null) return ((IComponent)_Parent).Site.DesignMode; if (_Parent is Control && ((Control)_Parent).Site != null) return ((Control)_Parent).Site.DesignMode; return false; } } private bool _InSetDataConnection = false; private void SetDataConnection(object newDataSource, bool force) { bool dataSourceChanged = _DataSource != newDataSource; if (!_InSetDataConnection) { try { if (force || dataSourceChanged) { _InSetDataConnection = true; IList list = (this.DataManager != null) ? this.DataManager.List : null; bool isDataManagerNull = this.DataManager == null; this.UnwireDataSource(); _DataSource = newDataSource; this.WireDataSource(); if (_IsDataSourceInitialized && !IsCustomCollection) { CurrencyManager manager = null; if (((newDataSource != null) && (_Parent.BindingContext != null)) && (newDataSource != Convert.DBNull)) { string bindingPath = ""; if (_Bindings != null && _Bindings.Count > 0) bindingPath = _Bindings[0].BindingMemberInfo.BindingPath; manager = (CurrencyManager)_Parent.BindingContext[newDataSource, bindingPath]; } if (_DataManager != manager) { if (_DataManager != null) { _DataManager.ItemChanged -= new ItemChangedEventHandler(this.DataManager_ItemChanged); _DataManager.PositionChanged -= new EventHandler(this.DataManager_PositionChanged); } _DataManager = manager; if (_DataManager != null) { _DataManager.ItemChanged += new ItemChangedEventHandler(this.DataManager_ItemChanged); _DataManager.PositionChanged += new EventHandler(this.DataManager_PositionChanged); } } if (((_DataManager != null) && (dataSourceChanged)) && !ValidateDisplayMembers(_Bindings)) { throw new ArgumentException("Wrong Bindings parameter", "newBindings"); } if ((_DataManager != null && (dataSourceChanged || force)) && (dataSourceChanged || (force && ((list != _DataManager.List) || isDataManagerNull)))) { DataManager_ItemChanged(_DataManager, null); } } _Converters.Clear(); } } finally { _InSetDataConnection = false; } } } private bool ValidateDisplayMembers(List members) { if (members == null || members.Count == 0) return true; foreach (BindingDef item in members) { if (item.BindingMemberInfo != null && !BindingMemberInfoInDataManager(item.BindingMemberInfo)) return false; } return true; } private bool BindingMemberInfoInDataManager(BindingMemberInfo bindingMemberInfo) { if (_DataManager != null) { PropertyDescriptorCollection itemProperties = _DataManager.GetItemProperties(); int count = itemProperties.Count; for (int i = 0; i < count; i++) { if (!typeof(IList).IsAssignableFrom(itemProperties[i].PropertyType) && itemProperties[i].Name.Equals(bindingMemberInfo.BindingField)) { return true; } } for (int j = 0; j < count; j++) { if (!typeof(IList).IsAssignableFrom(itemProperties[j].PropertyType) && (string.Compare(itemProperties[j].Name, bindingMemberInfo.BindingField, true, CultureInfo.CurrentCulture) == 0)) { return true; } } } return false; } private List _Bindings = new List(); public List Bindings { get { return _Bindings; } set { if (value != _Bindings) { List oldValue = _Bindings; _Bindings = value; OnBindingsChanged(oldValue, value); } } } /// /// Called when Bindings property has changed. /// /// Old property value /// New property value protected virtual void OnBindingsChanged(List oldValue, List newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("Bindings")); } private CurrencyManager _DataManager = null; internal CurrencyManager DataManager { get { return _DataManager; } } private bool _IsDataSourceInitEventHooked = false; private void UnwireDataSource() { if (IsCustomCollection) { CustomCollection col = (CustomCollection)_DataSource; col.CollectionChanged -= CustomCollectionChanged; } else { if (_DataSource is IComponent) { ((IComponent) _DataSource).Disposed -= new EventHandler(DataSourceDisposed); } ISupportInitializeNotification dataSource = _DataSource as ISupportInitializeNotification; if ((dataSource != null) && _IsDataSourceInitEventHooked) { dataSource.Initialized -= new EventHandler(DataSourceInitialized); _IsDataSourceInitEventHooked = false; } } } private void CustomCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { _Parent.BeginUpdate(); try { if (e.Action == NotifyCollectionChangedAction.Add) { int i = e.NewStartingIndex; foreach (object item in e.NewItems) { CreateVisualItem(_Parent.ItemsCollection, item, i, _Bindings); i++; } } else if (e.Action == NotifyCollectionChangedAction.Remove) { _Parent.ItemsCollection.RemoveAt(e.OldStartingIndex); //_Parent.ItemsCollection.RemoveAt(e.NewStartingIndex); } else if (e.Action == NotifyCollectionChangedAction.Replace) { SetItemCore(e.NewStartingIndex, e.NewItems[0]); } else if (e.Action == NotifyCollectionChangedAction.Reset) { RefreshItems(); } } finally { _Parent.EndUpdate(); } } private void DataSourceDisposed(object sender, EventArgs e) { this.SetDataConnection(null, true); } private bool _IsDataSourceInitialized = false; private void WireDataSource() { if (IsCustomCollection) { CustomCollection col = (CustomCollection) _DataSource; col.CollectionChanged += CustomCollectionChanged; _IsDataSourceInitialized = true; } else { if (_DataSource is IComponent) { ((IComponent) _DataSource).Disposed += new EventHandler(DataSourceDisposed); } ISupportInitializeNotification dataSource = _DataSource as ISupportInitializeNotification; if ((dataSource != null) && !dataSource.IsInitialized) { dataSource.Initialized += new EventHandler(DataSourceInitialized); _IsDataSourceInitEventHooked = true; _IsDataSourceInitialized = false; } else { _IsDataSourceInitialized = true; } } } private void DataSourceInitialized(object sender, EventArgs e) { this.SetDataConnection(_DataSource, true); } private void DataManager_ItemChanged(object sender, ItemChangedEventArgs e) { if (_Parent is Control) { Control parentControl = (Control)_Parent; if (parentControl.InvokeRequired) { parentControl.Invoke(new ItemChangedEventHandler(DataManager_ItemChanged), sender, e); return; } } if (_DataManager != null) { if (e == null || e.Index == -1) { this.SetItemsCore(_DataManager.List); if (_Parent.AllowSelection) { _Parent.SelectedIndex = _DataManager.Position; } } else { this.SetItemCore(e.Index, _DataManager.List[e.Index]); } } } private void DataManager_PositionChanged(object sender, EventArgs e) { if ((_DataManager != null) && _Parent.AllowSelection) { _Parent.SelectedIndex = _DataManager.Position; } } private ICloneable _VisualTemplate = null; /// /// Gets or sets the visual template that is generated for each data item. /// public ICloneable VisualTemplate { get { return _VisualTemplate; } set { if (value != _VisualTemplate) { ICloneable oldValue = _VisualTemplate; _VisualTemplate = value; OnVisualTemplateChanged(oldValue, value); } } } /// /// Called when VisualTemplate property has changed. /// /// Old property value /// New property value protected virtual void OnVisualTemplateChanged(ICloneable oldValue, ICloneable newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("VisualTemplate")); } /// /// When overridden in a derived class, sets the specified array of objects in a collection in the derived class. /// /// An array of items. protected virtual void SetItemsCore(IList items) { _Parent.BeginUpdate(); _Parent.ItemsCollection.Clear(); for (int i = 0; i < items.Count; i++) { object item = items[i]; CreateVisualItem(_Parent.ItemsCollection, item, i, _Bindings); } _Parent.EndUpdate(); } /// /// Creates a new item from template for the data. /// /// Data to create item for. /// New instance of the BaseItem. private object CreateVisualItem(IList parent, object item, int itemIndex, List bindings) { if(IsCustomCollection && item is ListBoxItem) { if (parent.Count <= itemIndex) parent.Add(item); else parent.Insert(itemIndex, item); if (bindings.Count == 0) return item; SetVisualItemData(item, item, bindings, itemIndex); return item; } object visualItem = _VisualTemplate.Clone(); if (parent.Count <= itemIndex) parent.Add(visualItem); else parent.Insert(itemIndex, visualItem); SetVisualItemData(visualItem, item, bindings, itemIndex); DataItemVisualEventArgs eventArgs = new DataItemVisualEventArgs(visualItem, item); _Parent.InvokeDataNodeCreated(eventArgs); return eventArgs.Visual; } private void SetVisualItemData(object visualItem, object item, List bindings, int bindingIndex) { PropertyInfo tagProperty = visualItem.GetType().GetProperty("Tag"); if (tagProperty != null) tagProperty.SetValue(visualItem, new ItemBindingData(item, bindingIndex), null); if (bindings.Count == 0) { if (visualItem is BaseItem) { if (item is string) ((BaseItem)visualItem).Text = (string)item; else if (item != null) ((BaseItem)visualItem).Text = item.ToString(); } } else { foreach (BindingDef binding in bindings) { binding.Update(this, visualItem, item); } } } /// /// When overridden in a derived class, sets the object with the specified index in the derived class. /// /// The array index of the object. /// The object. protected virtual void SetItemCore(int index, object value) { object visual = _Parent.ItemsCollection[index]; if (visual == null) return; _Parent.BeginUpdate(); SetVisualItemData(visual, value, _Bindings, index); _Parent.EndUpdate(); } /// /// When overridden in a derived class, resynchronizes the item data with the contents of the data source. /// public virtual void RefreshItems() { _Parent.ItemsCollection.Clear(); if (_DataManager != null) { SetItemsCore(_DataManager.List); if (_Parent.AllowSelection) { _Parent.SelectedIndex = _DataManager.Position; } } else if (_DataSource is IList) SetItemsCore((IList)_DataSource); } private Hashtable _Converters = new Hashtable(); internal TypeConverter GetFieldConverter(string fieldName) { if (_Converters.ContainsKey(fieldName)) return (TypeConverter)_Converters[fieldName]; if (_DataManager != null) { PropertyDescriptorCollection itemProperties = _DataManager.GetItemProperties(); if (itemProperties != null) { PropertyDescriptor descriptor = itemProperties.Find(fieldName, true); if (descriptor != null) { _Converters.Add(fieldName, descriptor.Converter); return descriptor.Converter; } } } return null; } private bool _CustomCollectionBinding = false; /// /// Indicates that generator should recognize when CustomCollection is set as DataSource and bind to it instead of going through DataManager route. /// public bool CustomCollectionBinding { get { return _CustomCollectionBinding; } set { _CustomCollectionBinding = value; } } #endregion public bool IsCustomCollection { get { return _CustomCollectionBinding && _DataSource is CustomCollection; } } } public interface IBindingSupport { /// /// Gets or sets whether selection is allowed. /// bool AllowSelection { get;set;} /// /// Gets or sets the selected item index. /// int SelectedIndex { get;set;} /// /// Gets or sets the BindingContext. /// BindingContext BindingContext { get;set;} IList ItemsCollection { get; } void BeginUpdate(); void EndUpdate(); void InvokeDataNodeCreated(DataItemVisualEventArgs e); } /// /// Defines delegate for data visual creation based events. /// public delegate void DataItemVisualEventHandler(object sender, DataItemVisualEventArgs e); /// /// Defines event arguments for data visual creation based events. /// public class DataItemVisualEventArgs : EventArgs { /// /// Gets or sets the visual that is created for data item. /// public object Visual = null; /// /// Gets the data-item node is being created for. /// public readonly object DataItem = null; /// /// Initializes a new instance of the DataNodeEventArgs class. /// /// /// public DataItemVisualEventArgs(object visual, object dataItem) { Visual = visual; DataItem = dataItem; } } }