SourceCode/PROMS/DotNetBar Source Code/ItemVisualGenerator.cs

563 lines
20 KiB
C#

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
{
/// <summary>
/// Provides binding support for ItemPanel control.
/// </summary>
public class ItemVisualGenerator
{
#region Constructor
private IBindingSupport _Parent = null;
/// <summary>
/// Initializes a new instance of the ItemVisualGenerator class.
/// </summary>
/// <param name="parent"></param>
public ItemVisualGenerator(IBindingSupport parent)
{
_Parent = parent;
}
#endregion
#region Implementation
private object _DataSource = null;
/// <summary>
/// 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.
/// </summary>
[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<BindingDef> 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<BindingDef> _Bindings = new List<BindingDef>();
public List<BindingDef> Bindings
{
get { return _Bindings; }
set
{
if (value != _Bindings)
{
List<BindingDef> oldValue = _Bindings;
_Bindings = value;
OnBindingsChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when Bindings property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnBindingsChanged(List<BindingDef> oldValue, List<BindingDef> 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<object> col = (CustomCollection<object>)_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<object> col = (CustomCollection<object>) _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;
/// <summary>
/// Gets or sets the visual template that is generated for each data item.
/// </summary>
public ICloneable VisualTemplate
{
get { return _VisualTemplate; }
set
{
if (value != _VisualTemplate)
{
ICloneable oldValue = _VisualTemplate;
_VisualTemplate = value;
OnVisualTemplateChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when VisualTemplate property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnVisualTemplateChanged(ICloneable oldValue, ICloneable newValue)
{
//OnPropertyChanged(new PropertyChangedEventArgs("VisualTemplate"));
}
/// <summary>
/// When overridden in a derived class, sets the specified array of objects in a collection in the derived class.
/// </summary>
/// <param name="items">An array of items.</param>
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();
}
/// <summary>
/// Creates a new item from template for the data.
/// </summary>
/// <param name="item">Data to create item for.</param>
/// <returns>New instance of the BaseItem.</returns>
private object CreateVisualItem(IList parent, object item, int itemIndex, List<BindingDef> 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<BindingDef> 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);
}
}
}
/// <summary>
/// When overridden in a derived class, sets the object with the specified index in the derived class.
/// </summary>
/// <param name="index">The array index of the object.</param>
/// <param name="value">The object.</param>
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();
}
/// <summary>
/// When overridden in a derived class, resynchronizes the item data with the contents of the data source.
/// </summary>
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;
/// <summary>
/// Indicates that generator should recognize when CustomCollection<T> is set as DataSource and bind to it instead of going through DataManager route.
/// </summary>
public bool CustomCollectionBinding
{
get { return _CustomCollectionBinding; }
set
{
_CustomCollectionBinding = value;
}
}
#endregion
public bool IsCustomCollection
{
get
{
return _CustomCollectionBinding && _DataSource is CustomCollection<object>;
}
}
}
public interface IBindingSupport
{
/// <summary>
/// Gets or sets whether selection is allowed.
/// </summary>
bool AllowSelection { get;set;}
/// <summary>
/// Gets or sets the selected item index.
/// </summary>
int SelectedIndex { get;set;}
/// <summary>
/// Gets or sets the BindingContext.
/// </summary>
BindingContext BindingContext { get;set;}
IList ItemsCollection { get; }
void BeginUpdate();
void EndUpdate();
void InvokeDataNodeCreated(DataItemVisualEventArgs e);
}
/// <summary>
/// Defines delegate for data visual creation based events.
/// </summary>
public delegate void DataItemVisualEventHandler(object sender, DataItemVisualEventArgs e);
/// <summary>
/// Defines event arguments for data visual creation based events.
/// </summary>
public class DataItemVisualEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the visual that is created for data item.
/// </summary>
public object Visual = null;
/// <summary>
/// Gets the data-item node is being created for.
/// </summary>
public readonly object DataItem = null;
/// <summary>
/// Initializes a new instance of the DataNodeEventArgs class.
/// </summary>
/// <param name="node"></param>
/// <param name="dataItem"></param>
public DataItemVisualEventArgs(object visual, object dataItem)
{
Visual = visual;
DataItem = dataItem;
}
}
}