File

projects/wms-framework/src/lib/baseframework/collectionViews.ts

Description

Defines a collection of elements to be displayed in a view

Extends

Iterable

Index

Properties

Properties

SortDescriptions
SortDescriptions: SortDescriptionCollection
Type : SortDescriptionCollection

Gets the instance of SortDescriptionCollection object that contains all sort criterias

import { Dependency } from '../basecomponentmodel/Dependency';
import { DependencyObject } from '../basecomponentmodel/DependencyObject';
import { DependencyProperty } from '../basecomponentmodel/DependencyProperty';
import { DependencyPropertyChangedEventArgs } from '../basecomponentmodel/DependencyPropertyChangedEventArgs';
import { INotifyPropertyChanged } from '../basecomponentmodel/INotifyPropertyChanged';
import { IItemsSource } from '../models';
import { SubscriptionEvent } from '../utils/SubscriptionEvent';
import {
  CollectionChangeAction,
  CollectionChangeInfo,
  INotifyCollectionChanged,
  SimpleList,
  SortDescriptionCollection,
} from './collections';
import { SortDescription } from './SortDescription';

/**
 *
 * Defines a collection of elements to be displayed in a view
 * @export
 * @interface ICollectionView
 * @extends {Iterable<unknown>}
 * @extends {INotifyCollectionChanged}
 * @wInterface System.ComponentModel.ICollectionView
 */
export interface ICollectionView
  extends Iterable<unknown>,
    INotifyCollectionChanged {
  /**
   * Gets the instance of {@link SortDescriptionCollection} object that contains all
   * sort criterias
   *
   * @type {SortDescriptionCollection}
   * @memberof ICollectionView
   */
  SortDescriptions: SortDescriptionCollection;
}

/**
 * Concrete implementation of {@link ICollectionView } object that just delegates all element operations
 * on a given {@link Iterable } object.
 */
export class CollectionView implements ICollectionView, IItemsSource {
  private sortDescriptions: SortDescriptionCollection =
    new SortDescriptionCollection();
  private innerHandler: (e: any, args: CollectionChangeInfo) => void;
  private sortHandler: (e: any, args: CollectionChangeInfo) => void;
  private sortedList: SimpleList<any>;

  // inherited
  get SortDescriptions(): SortDescriptionCollection {
    return this.sortDescriptions;
  }

  /**
   * Creates an instance of CollectionView.
   * @param {Iterable<unknown>} elements
   * @memberof CollectionView
   */
  constructor(private elements: Iterable<unknown>) {
    let notifiable: INotifyCollectionChanged =
      elements as any as INotifyCollectionChanged;
    if (notifiable?.CollectionChanged) {
      this.sortedList = new SimpleList((elements as any).internalArray);
      this.innerHandler = notifiable.CollectionChanged.addHandler(
        (sender, args) => this.handleInnerChanges(sender, args)
      );
    } else {
      this.sortedList = new SimpleList(elements);
    }
    this.sortHandler = this.sortDescriptions.CollectionChanged.addHandler(
      (sender, args) => this.handleSortDescriptionChanges()
    );
  }

  // inherited
  get internalArray() {
    return this.sortedList?.internalArray;
  }

  /**
   * Releases all resources associated to this Collection view object
   *
   * @memberof CollectionView
   */
  release() {
    if (this.innerHandler) {
      let notifiable: INotifyCollectionChanged = this
        .elements as any as INotifyCollectionChanged;
      if (notifiable) {
        notifiable.CollectionChanged.removeHandler(this.innerHandler);
      }
    }
    this.sortDescriptions.CollectionChanged.removeHandler(this.sortHandler);
  }

  /**
   * Handles changes in the Sorted Description object by resorting all elements in the list
   * with the new sorting descriptors
   * @param sender
   * @param args
   */
  private handleSortDescriptionChanges(): void {
    this.sort();
    let args: CollectionChangeInfo = new CollectionChangeInfo(
      CollectionChangeAction.Reset
    );
    this.CollectionChanged.fire([this, args]);
  }

  /**
   * Sorts the underlying list with current SortDescription object
   *
   * @private
   * @memberof CollectionView
   */
  private sort() {
    this.sortedList.sort((x: any, y: any) =>
      SortDescription.sortFunction(this.sortDescriptions, x, y)
    );
  }

  /**
   * Handles the underlying INotifyCollectionChanged changes by recreating the list and sorting it
   * with the new changes
   *
   * @private
   * @param {*} sender
   * @param {CollectionChangeInfo} args
   * @memberof CollectionView
   */
  private handleInnerChanges(sender: any, args: CollectionChangeInfo) {
    this.sortedList = new SimpleList((this.elements as any).internalArray);
    this.sort();
    this.CollectionChanged.fire([sender, args]);
  }

  // inherited
  *[Symbol.iterator](): Iterator<unknown, any, undefined> {
    for (const e of this.sortedList) {
      yield e;
    }
  }

  // inherited
  CollectionChanged: SubscriptionEvent<
    (e: any, args: CollectionChangeInfo) => void
  > = new SubscriptionEvent();
}

/**
 * Provides a binding mechanism that is strongly coupled with the component bound to
 *
 * @export
 * @class CollectionViewSource
 * @extends {DependencyObject}
 * @wType System.Windows.Data.CollectionViewSource
 */
export class CollectionViewSource
  extends DependencyObject
  implements INotifyPropertyChanged
{
  PropertyChanged: SubscriptionEvent<
    (o: any, args: { PropertyName: string }) => void
  > = new SubscriptionEvent<(o: any, args: { PropertyName: string }) => void>();

  /**
   * SourceProperty dependency property
   *
   * @static
   * @type {DependencyProperty}
   * @memberof CollectionViewSource
   */
  static SourceProperty: DependencyProperty = new DependencyProperty(
    'Source',
    null,
    CollectionViewSource.sourceChanged
  );

  /**
   * Provides a source to be strongly bound to a control, acting as a proxy between the component
   * and the given source.
   * ViewProperty dependency property
   *
   * @static
   * @type {DependencyProperty}
   * @memberof CollectionViewSource
   */
  static ViewProperty: DependencyProperty = new DependencyProperty(
    'View',
    null,
    CollectionViewSource.viewChanged
  );

  /**
   *  Gets/sets the data source for this { CollectionViewSource } object.
   *
   * @type {*}
   * @memberof ListBox
   */
  @Dependency(CollectionViewSource.SourceProperty)
  public Source: any;

  /**
   *  Gets/sets the { IViewCollection } object used to render this data.
   *
   * @type {*}
   * @memberof ListBox
   */
  @Dependency(CollectionViewSource.ViewProperty)
  public View: ICollectionView;

  /**
   * A change handler responsible for handlingchanges of source property
   * @param sender the sender object
   * @param args a {@link DependencyPropertyChangedEventArgs } object that has the changed values
   */
  public static sourceChanged(
    sender: DependencyObject,
    args: DependencyPropertyChangedEventArgs
  ): void {
    let collection: CollectionViewSource = sender as CollectionViewSource;
    if (collection) {
      let newSource: Iterable<unknown> = args.NewValue as Iterable<unknown>;
      collection.View = newSource ? new CollectionView(newSource) : null;
    }
  }

  /**
   * A change handler responsible for handling changes of view property
   * @param sender the sender object
   * @param args a {@link DependencyPropertyChangedEventArgs } object that has the changed values
   */
  public static viewChanged(
    sender: DependencyObject,
    args: DependencyPropertyChangedEventArgs
  ): void {
    let collection: CollectionViewSource = sender as CollectionViewSource;
    if (collection) {
      let oldView: CollectionView = args.OldValue as CollectionView;
      oldView?.release();
      collection.PropertyChanged.fire([collection, { PropertyName: 'View' }]);
    }
  }
}

result-matching ""

    No results matching ""