123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Text;
- using System.Globalization;
- using System.Diagnostics.CodeAnalysis;
- using System.Collections;
- namespace FastReport.DataVisualization.Charting
- {
- /// <summary>
- /// Base class for all chart element collections
- /// </summary>
- public abstract class ChartElementCollection<T> : Collection<T>, IChartElement, IDisposable
- where T : ChartElement
- {
- #region Member variables
- private IChartElement _parent = null;
- private CommonElements _common = null;
- internal int _suspendUpdates = 0;
- #endregion
- #region Properties
- /// <summary>
- /// Gets or sets the parent.
- /// </summary>
- internal IChartElement Parent
- {
- get { return _parent; }
- set
- {
- _parent = value;
- Invalidate();
- }
- }
- /// <summary>
- /// Gets the CommonElements of the chart.
- /// </summary>
- internal CommonElements Common
- {
- get
- {
- if (_common == null && _parent != null)
- {
- _common = _parent.Common;
- }
- return _common;
- }
- }
- /// <summary>
- /// Gets the chart.
- /// </summary>
- internal Chart Chart
- {
- get
- {
- if (Common != null)
- return Common.Chart;
- else
- return null;
- }
- }
- /// <summary>
- /// Gets the items as List<T>. Use this property to perform advanced List specific operations (Sorting, etc)
- /// </summary>
- internal List<T> ItemList
- {
- get { return Items as List<T>; }
- }
- internal bool IsSuspended
- {
- get { return _suspendUpdates > 0; }
- }
- #endregion
- #region Constructors
- /// <summary>
- /// Initializes a new instance of the <see cref="ChartElementCollection<T>"/> class.
- /// </summary>
- /// <param name="parent">The parent chart element.</param>
- internal ChartElementCollection(IChartElement parent)
- {
- _parent = parent;
- }
- #endregion
- #region Methods
- /// <summary>
- /// Forces the invalidation of the parent chart element
- /// </summary>
- public virtual void Invalidate()
- {
- if (_parent != null && !IsSuspended)
- _parent.Invalidate();
- }
- /// <summary>
- /// Suspends invalidation
- /// </summary>
- public virtual void SuspendUpdates()
- {
- _suspendUpdates++;
- }
- /// <summary>
- /// Resumes invalidation.
- /// </summary>
- public virtual void ResumeUpdates()
- {
- if (_suspendUpdates>0)
- _suspendUpdates--;
- if (_suspendUpdates==0)
- this.Invalidate();
- }
- /// <summary>
- /// Removes all elements from the <see cref="T:System.Collections.ObjectModel.Collection`1"/>.
- /// </summary>
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
- protected override void ClearItems()
- {
- SuspendUpdates();
- while (this.Count > 0)
- {
- this.RemoveItem(0);
- }
- ResumeUpdates();
- }
- /// <summary>
- /// Deinitializes the specified item.
- /// </summary>
- /// <param name="item">The item.</param>
- internal virtual void Deinitialize( T item)
- {
- }
- /// <summary>
- /// Initializes the specified item.
- /// </summary>
- /// <param name="item">The item.</param>
- internal virtual void Initialize(T item)
- {
- }
- /// <summary>
- /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1"/>.
- /// </summary>
- /// <param name="index">The zero-based index of the element to remove.</param>
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
- protected override void RemoveItem(int index)
- {
- this.Deinitialize(this[index]);
- this[index].Parent = null;
- base.RemoveItem(index);
- Invalidate();
- }
- /// <summary>
- /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1"/> at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
- /// <param name="item">The object to insert. The value can be null for reference types.</param>
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
- protected override void InsertItem(int index, T item)
- {
- this.Initialize(item);
- item.Parent = this;
- base.InsertItem(index, item);
- Invalidate();
- if(Chart != null)
- Chart.CallOnModifing(this);
- }
- /// <summary>
- /// Replaces the element at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index of the element to replace.</param>
- /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
- protected override void SetItem(int index, T item)
- {
- this.Initialize(item);
- item.Parent = this;
- base.SetItem(index, item);
- Invalidate();
- }
- #endregion
- #region IChartElement Members
- IChartElement IChartElement.Parent
- {
- get { return this.Parent; }
- set { this.Parent = value; }
- }
- void IChartElement.Invalidate()
- {
- this.Invalidate();
- }
- CommonElements IChartElement.Common
- {
- get{ return this.Common; }
- }
- #endregion
- #region IDisposable Members
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- // Dispose managed resources
- foreach (T element in this)
- {
- element.Dispose();
- }
- }
- }
- /// <summary>
- /// Performs freeing, releasing, or resetting managed resources.
- /// </summary>
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
- public void Dispose()
- {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
- #endregion
- }
- /// <summary>
- /// Base class for all collections of named chart elements. Performs the name management and enforces the uniquness of the names
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class ChartNamedElementCollection<T> : ChartElementCollection<T>, INameController
- where T : ChartNamedElement
- {
- #region Fields
- private List<T> _cachedState = null;
- private int _disableDeleteCount = 0;
- #endregion
- #region Properties
- /// <summary>
- /// Gets the name prefix that is used to create unique chart element names.
- /// </summary>
- /// <value>The default name prefix of the chart elements stored in the collection.</value>
- protected virtual string NamePrefix
- {
- get { return typeof(T).Name; }
- }
- /// <summary>
- /// Gets or sets the chart element with the specified name.
- /// </summary>
- /// <value></value>
- public T this[string name]
- {
- get
- {
- int index = this.IndexOf(name);
- if (index != -1)
- {
- return this[index];
- }
- throw new ArgumentException(SR.ExceptionNameNotFound(name, this.GetType().Name));
- }
- set
- {
- int nameIndex = this.IndexOf(name);
- int itemIndex = this.IndexOf(value);
- bool nameFound = nameIndex > -1;
- bool itemFound = itemIndex > -1;
- if (!nameFound && !itemFound)
- this.Add(value);
- else if (nameFound && !itemFound)
- this[nameIndex] = value;
- else if (!nameFound && itemFound)
- throw new ArgumentException(SR.ExceptionNameAlreadyExistsInCollection(name, this.GetType().Name));
-
- else if (nameFound && itemFound && nameIndex != itemIndex)
- throw new ArgumentException(SR.ExceptionNameAlreadyExistsInCollection(name, this.GetType().Name));
-
- }
- }
- #endregion
- #region Constructors
- /// <summary>
- /// Initializes a new instance of the <see cref="ChartNamedElementCollection<T>"/> class.
- /// </summary>
- /// <param name="parent">The parent chart element.</param>
- internal ChartNamedElementCollection(IChartElement parent)
- : base(parent)
- {
- }
- #endregion
- #region Events
- internal event EventHandler<NameReferenceChangedEventArgs> NameReferenceChanged;
- internal event EventHandler<NameReferenceChangedEventArgs> NameReferenceChanging;
- #endregion
- #region Methods
- /// <summary>
- /// Determines whether the chart element with the specified name already exists in the collection.
- /// </summary>
- /// <param name="name">The new chart element name.</param>
- /// <returns>
- /// <c>true</c> if new chart element name is unique; otherwise, <c>false</c>.
- /// </returns>
- public virtual bool IsUniqueName(string name)
- {
- return FindByName(name)==null;
- }
- /// <summary>
- /// Finds the unique name for a new element being added to the collection
- /// </summary>
- /// <returns>Next unique chart element name</returns>
- public virtual string NextUniqueName()
- {
- // Find unique name
- string result = string.Empty;
- string prefix = this.NamePrefix;
- for (int i = 1; i < System.Int32.MaxValue; i++)
- {
- result = prefix + i.ToString(CultureInfo.InvariantCulture);
- // Check whether the name is unique
- if (IsUniqueName(result))
- {
- break;
- }
- }
- return result;
- }
- /// <summary>
- /// Indexes the of chart element with the specified name.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns></returns>
- public int IndexOf(string name)
- {
- int i = 0;
- foreach (T namedObj in this)
- {
- if (namedObj.Name == name)
- return i;
- i++;
- }
- return -1;
- }
- /// <summary>
- /// Verifies the name reference to a chart named element stored in this collection and throws the argument exception if its not valid.
- /// </summary>
- /// <param name="name">Chart element name.</param>
- internal void VerifyNameReference(string name)
- {
- if (Chart!=null && !Chart.serializing && !IsNameReferenceValid(name))
- throw new ArgumentException(SR.ExceptionNameNotFound(name, this.GetType().Name));
- }
- /// <summary>
- /// Verifies the name reference to a chart named element stored in this collection.
- /// </summary>
- /// <param name="name">Chart element name.</param>
- internal bool IsNameReferenceValid(string name)
- {
- return String.IsNullOrEmpty(name) ||
- name == Constants.NotSetValue ||
- IndexOf(name) >= 0;
- }
- /// <summary>
- /// Finds the chart element by the name.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns></returns>
- public virtual T FindByName(string name)
- {
- foreach (T namedObj in this)
- {
- if (namedObj.Name == name)
- return namedObj;
- }
- return null;
- }
- /// <summary>
- /// Inserts the specified item in the collection at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index where the item is to be inserted.</param>
- /// <param name="item">The object to insert.</param>
- protected override void InsertItem(int index, T item)
- {
- if (String.IsNullOrEmpty(item.Name))
- item.Name = this.NextUniqueName();
- else if (!IsUniqueName(item.Name))
- throw new ArgumentException(SR.ExceptionNameAlreadyExistsInCollection(item.Name, this.GetType().Name));
- //If the item references other named references we might need to fix the references
- FixNameReferences(item);
- base.InsertItem(index, item);
- if (this.Count == 1 && item != null)
- {
- // First element is added to the list -> fire the NameReferenceChanged event to update all the dependent elements
- ((INameController)this).OnNameReferenceChanged(new NameReferenceChangedEventArgs(null, item));
- }
- }
- /// <summary>
- /// Replaces the element at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index of the element to replace.</param>
- /// <param name="item">The new value for the element at the specified index.</param>
- protected override void SetItem(int index, T item)
- {
- if (String.IsNullOrEmpty(item.Name))
- item.Name = this.NextUniqueName();
- else if (!IsUniqueName(item.Name) && IndexOf(item.Name) != index)
- throw new ArgumentException(SR.ExceptionNameAlreadyExistsInCollection(item.Name, this.GetType().Name));
- //If the item references other named references we might need to fix the references
- FixNameReferences(item);
- // Remember the removedElement
- ChartNamedElement removedElement = index<Count ? this[index] : null;
-
- ((INameController)this).OnNameReferenceChanging(new NameReferenceChangedEventArgs(removedElement, item));
- base.SetItem(index, item);
- // Fire the NameReferenceChanged event to update all the dependent elements
- ((INameController)this).OnNameReferenceChanged(new NameReferenceChangedEventArgs(removedElement, item));
- }
- /// <summary>
- /// Removes the element at the specified index of the collection.
- /// </summary>
- /// <param name="index">The zero-based index of the element to remove.</param>
- protected override void RemoveItem(int index)
- {
- // Remember the removedElement
- ChartNamedElement removedElement = index < Count ? this[index] : null;
- if (_disableDeleteCount == 0)
- {
- ((INameController)this).OnNameReferenceChanged(new NameReferenceChangedEventArgs(removedElement, null));
- }
- base.RemoveItem(index);
- if (_disableDeleteCount == 0)
- {
- // All elements referencing the removed element will be redirected to the first element in collection
- // Fire the NameReferenceChanged event to update all the dependent elements
- ChartNamedElement defaultElement = this.Count > 0 ? this[0] : null;
- ((INameController)this).OnNameReferenceChanged(new NameReferenceChangedEventArgs(removedElement, defaultElement));
- }
- }
- /// <summary>
- /// Fixes the name references of the item.
- /// </summary>
- internal virtual void FixNameReferences(T item)
- {
- //Nothing to fix at the base class...
- }
- #endregion
- #region INameController Members
- /// <summary>
- /// Determines whether is the name us unique.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>
- /// <c>true</c> if is the name us unique; otherwise, <c>false</c>.
- /// </returns>
- bool INameController.IsUniqueName(string name)
- {
- return this.IsUniqueName(name);
- }
- /// <summary>
- /// Gets or sets a value indicating whether this instance is in edit mode by collecrtion editor.
- /// </summary>
- /// <value>
- /// <c>true</c> if this instance the colection is editing; otherwise, <c>false</c>.
- /// </value>
- bool INameController.IsColectionEditing
- {
- get
- {
- return _disableDeleteCount == 0;
- }
- set
- {
- _disableDeleteCount += value ? 1 : -1;
- }
- }
- /// <summary>
- /// Raises the <see cref="E:NameReferenceChanging"/> event.
- /// </summary>
- /// <param name="e">The <see cref="NameReferenceChangedEventArgs"/> instance containing the event data.</param>
- void INameController.OnNameReferenceChanging(NameReferenceChangedEventArgs e)
- {
- if (!IsSuspended)
- {
- if (this.NameReferenceChanging != null)
- this.NameReferenceChanging(this, e);
- }
- }
- /// <summary>
- /// Raises the <see cref="E:NameReferenceChanged"/> event.
- /// </summary>
- /// <param name="e">The <see cref="NameReferenceChangedEventArgs"/> instance containing the event data.</param>
- void INameController.OnNameReferenceChanged(NameReferenceChangedEventArgs e)
- {
- if (!IsSuspended)
- {
- if (this.NameReferenceChanged != null)
- this.NameReferenceChanged(this, e);
- }
- }
- /// <summary>
- /// Does the snapshot of collection items.
- /// </summary>
- /// <param name="save">if set to <c>true</c> collection items will be saved.</param>
- /// <param name="changingCallback">The changing callback.</param>
- /// <param name="changedCallback">The changed callback.</param>
- void INameController.DoSnapshot(bool save,
- EventHandler<NameReferenceChangedEventArgs> changingCallback,
- EventHandler<NameReferenceChangedEventArgs> changedCallback)
- {
- if (save)
- {
- _cachedState = new List<T>(this);
- if (changingCallback != null) this.NameReferenceChanging += changingCallback;
- if (changedCallback != null) this.NameReferenceChanged += changedCallback;
- }
- else
- {
- if (changingCallback != null) this.NameReferenceChanging -= changingCallback;
- if (changedCallback != null) this.NameReferenceChanged -= changedCallback;
- _cachedState.Clear();
- _cachedState = null;
- }
- }
- /// <summary>
- /// Gets the snapshot of saved collection items.
- /// </summary>
- /// <value>The snapshot.</value>
- IList INameController.Snapshot
- {
- get { return _cachedState; }
- }
- #endregion
-
- }
- }
|