CollectionViewSource.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Data / CollectionViewSource.cs / 2 / CollectionViewSource.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines CollectionViewSource object, the markup-accessible entry 
//              point to CollectionView. 
//
// See spec at [....]/connecteddata/Specs/CollectionViewSource.mht 
//
//---------------------------------------------------------------------------

using System; 
using System.Collections;           // IEnumerable
using System.Collections.ObjectModel;   // ObservableCollection 
using System.Collections.Specialized;   // NotifyCollectionChanged* 
using System.Globalization;         // CultureInfo
using System.ComponentModel;        // ICollectionView 
using System.Windows.Markup;        // XmlLanguage
using MS.Internal;                  // Invariant.Assert
using MS.Internal.Data;             // DataBindEngine
 
namespace System.Windows.Data
{ 
    ///  
    ///  Describes a collection view.
    ///  
    public class CollectionViewSource : DependencyObject, ISupportInitialize, IWeakEventListener
    {
        #region Constructors
 
        //
        //  Constructors 
        // 

        ///  
        ///     Initializes a new instance of the CollectionViewSource class.
        /// 
        public CollectionViewSource()
        { 
            _sort = new SortDescriptionCollection();
            ((INotifyCollectionChanged)_sort).CollectionChanged += new NotifyCollectionChangedEventHandler(OnForwardedCollectionChanged); 
 
            _groupBy = new ObservableCollection();
            ((INotifyCollectionChanged)_groupBy).CollectionChanged += new NotifyCollectionChangedEventHandler(OnForwardedCollectionChanged); 
        }

        #endregion Constructors
 
        #region Public Properties
 
        // 
        //  Public Properties
        // 

        /// 
        ///     The key needed to define a read-only property.
        ///  
        private static readonly DependencyPropertyKey ViewPropertyKey
            = DependencyProperty.RegisterReadOnly( 
                    "View", 
                    typeof(ICollectionView),
                    typeof(CollectionViewSource), 
                    new FrameworkPropertyMetadata((ICollectionView)null));

        /// 
        ///     The DependencyProperty for the View property. 
        ///     Flags:              None
        ///     Other:              Read-Only 
        ///     Default Value:      null 
        /// 
        public static readonly DependencyProperty ViewProperty 
            = ViewPropertyKey.DependencyProperty;

        /// 
        ///     Returns the ICollectionView currently affiliated with this CollectionViewSource. 
        /// 
        [ReadOnly(true)] 
        public ICollectionView View 
        {
            get 
            {
                return GetOriginalView(CollectionView);
            }
        } 

 
 
        /// 
        ///     The DependencyProperty for the Source property. 
        ///     Flags:              none
        ///     Default Value:      null
        /// 
        public static readonly DependencyProperty SourceProperty 
            = DependencyProperty.Register(
                    "Source", 
                    typeof(object), 
                    typeof(CollectionViewSource),
                    new FrameworkPropertyMetadata( 
                            (object)null,
                            new PropertyChangedCallback(OnSourceChanged)),
                    new ValidateValueCallback(IsSourceValid));
 
        /// 
        ///     Source is the underlying collection. 
        ///  
        public object Source
        { 
            get { return (object) GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }
 
        /// 
        ///     Called when SourceProperty is invalidated on "d." 
        ///  
        /// The object on which the property was invalidated.
        /// Argument. 
        private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CollectionViewSource ctrl = (CollectionViewSource) d;
 
            ctrl.OnSourceChanged(e.OldValue, e.NewValue);
            ctrl.EnsureView(); 
        } 

        ///  
        ///     This method is invoked when the Source property changes.
        /// 
        /// The old value of the Source property.
        /// The new value of the Source property. 
        protected virtual void OnSourceChanged(object oldSource, object newSource)
        { 
        } 

        private static bool IsSourceValid(object o) 
        {
            return (o == null ||
                        o is IEnumerable ||
                        o is IListSource || 
                        o is DataSourceProvider) &&
                    !(o is ICollectionView); 
        } 

        private static bool IsValidSourceForView(object o) 
        {
            return (o == null ||
                        o is IEnumerable ||
                        o is IListSource); 
        }
 
 

        ///  
        ///     The DependencyProperty for the CollectionViewType property.
        ///     Flags:              none
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty CollectionViewTypeProperty
            = DependencyProperty.Register( 
                    "CollectionViewType", 
                    typeof(Type),
                    typeof(CollectionViewSource), 
                    new FrameworkPropertyMetadata(
                            (Type)null,
                            new PropertyChangedCallback(OnCollectionViewTypeChanged)),
                    new ValidateValueCallback(IsCollectionViewTypeValid)); 

        ///  
        ///     CollectionViewType is the desired type of the View. 
        /// 
        ///  
        ///     This property may only be set during initialization.
        /// 
        public Type CollectionViewType
        { 
            get { return (Type) GetValue(CollectionViewTypeProperty); }
            set { SetValue(CollectionViewTypeProperty, value); } 
        } 

        private static void OnCollectionViewTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            CollectionViewSource ctrl = (CollectionViewSource) d;

            Type oldCollectionViewType = (Type) e.OldValue; 
            Type newCollectionViewType = (Type) e.NewValue;
 
            if (!ctrl._isInitializing) 
                throw new InvalidOperationException(SR.Get(SRID.CollectionViewTypeIsInitOnly));
 
            ctrl.OnCollectionViewTypeChanged(oldCollectionViewType, newCollectionViewType);
            ctrl.EnsureView();
        }
 
        /// 
        ///     This method is invoked when the CollectionViewType property changes. 
        ///  
        /// The old value of the CollectionViewType property.
        /// The new value of the CollectionViewType property. 
        protected virtual void OnCollectionViewTypeChanged(Type oldCollectionViewType, Type newCollectionViewType)
        {
        }
 
        private static bool IsCollectionViewTypeValid(object o)
        { 
            Type type = (Type)o; 

            return type == null || 
                typeof(ICollectionView).IsAssignableFrom(type);
        }

        ///  
        /// CultureInfo used for sorting, comparisons, etc.
        /// This property is forwarded to any collection view created from this source. 
        ///  
        [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))]
        public CultureInfo Culture 
        {
            get { return _culture; }
            set { _culture = value; OnForwardedPropertyChanged(); }
        } 

        ///  
        /// Collection of SortDescriptions, describing sorting. 
        /// This property is forwarded to any collection view created from this source.
        ///  
        public SortDescriptionCollection SortDescriptions
        {
            get { return _sort; }
        } 

        ///  
        /// Collection of GroupDescriptions, describing grouping. 
        /// This property is forwarded to any collection view created from this source.
        ///  
        public ObservableCollection GroupDescriptions
        {
            get { return _groupBy; }
        } 

        #endregion Public Properties 
 
        #region Public Events
 
        /// 
        ///     An event requesting a filter query.
        /// 
        public event FilterEventHandler Filter 
        {
            add 
            { 
                // Get existing event hanlders
                FilterEventHandler handlers = FilterHandlersField.GetValue(this); 
                if (handlers != null)
                {
                    // combine to a multicast delegate
                    handlers = (FilterEventHandler)Delegate.Combine(handlers, value); 
                }
                else 
                { 
                    handlers = value;
                } 
                // Set the delegate as an uncommon field
                FilterHandlersField.SetValue(this, handlers);

                OnForwardedPropertyChanged(); 
            }
            remove 
            { 
                // Get existing event hanlders
                FilterEventHandler handlers = FilterHandlersField.GetValue(this); 
                if (handlers != null)
                {
                    // Remove the given handler
                    handlers = (FilterEventHandler)Delegate.Remove(handlers, value); 
                    if (handlers == null)
                    { 
                        // Clear the value for the uncommon field 
                        // cause there are no more handlers
                        FilterHandlersField.ClearValue(this); 
                    }
                    else
                    {
                        // Set the remaining handlers as an uncommon field 
                        FilterHandlersField.SetValue(this, handlers);
                    } 
                } 

                OnForwardedPropertyChanged(); 
            }
        }

        #endregion Public Events 

        #region Public Methods 
 
        //
        //  Public Methods 
        //

        /// 
        /// Return the default view for the given source.  This view is never 
        /// affiliated with any CollectionViewSource.
        ///  
        public static ICollectionView GetDefaultView(object source) 
        {
            return GetOriginalView(GetDefaultCollectionView(source)); 
        }

        /// 
        /// Return true if the given view is the default view for its source. 
        /// 
        public static bool IsDefaultView(ICollectionView view) 
        { 
            if (view != null)
            { 
                object source = view.SourceCollection;
                return (GetOriginalView(view) == GetDefaultView(source));
            }
            else 
            {
                return true; 
            } 
        }
 
        /// 
        /// Enter a Defer Cycle.
        /// Defer cycles are used to coalesce changes to the ICollectionView.
        ///  
        public IDisposable DeferRefresh()
        { 
            return new DeferHelper(this); 
        }
 
        #endregion Public Methods

        //
        //  Interfaces 
        //
 
        #region ISupportInitialize 

        /// Signals the object that initialization is starting. 
        void ISupportInitialize.BeginInit()
        {
            _isInitializing = true;
        } 

        /// Signals the object that initialization is complete. 
        void ISupportInitialize.EndInit() 
        {
            _isInitializing = false; 
            EnsureView();
        }

        #endregion ISupportInitialize 

        #region IWeakEventListener 
 
        /// 
        /// Handle events from the centralized event table 
        /// 
        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            return ReceiveWeakEvent(managerType, sender, e); 
        }
 
        ///  
        /// Handle events from the centralized event table
        ///  
        protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            if (managerType == typeof(DataChangedEventManager))
            { 
                EnsureView();
            } 
            else 
            {
                return false;       // unrecognized event 
            }

            return true;
        } 

        #endregion IWeakEventListener 
 
        #region Internal Properties
 
        //
        //  Internal Properties
        //
 
        // Returns the CollectionView currently affiliate with this CollectionViewSource.
        // This may be a CollectionViewProxy over the original view. 
        internal CollectionView CollectionView 
        {
            get 
            {
                ICollectionView view = (ICollectionView)GetValue(ViewProperty);

                if (view != null && !_isViewInitialized) 
                {
                    // leak prevention: re-fetch ViewRecord instead of keeping a reference to it, 
                    // to be sure that we don't inadvertently keep it alive. 
                    object source = Source;
                    DataSourceProvider dataProvider = source as DataSourceProvider; 

                    // if the source is DataSourceProvider, use its Data instead
                    if (dataProvider != null)
                    { 
                        source = dataProvider.Data;
                    } 
 
                    if (source != null)
                    { 
                        DataBindEngine engine = DataBindEngine.CurrentDataBindEngine;
                        ViewRecord viewRecord = engine.GetViewRecord(source, this, CollectionViewType);
                        if (viewRecord != null)
                        { 
                            viewRecord.InitializeView();
                            _isViewInitialized = true; 
                        } 
                    }
                } 

                return (CollectionView)view;
            }
        } 

        // Returns the property through which inheritance context was established 
        internal DependencyProperty PropertyForInheritanceContext 
        {
            get { return _propertyForInheritanceContext; } 
        }

        #endregion Internal Properties
 
        #region Internal Methods
 
        // 
        //  Internal Methods
        // 

        // Return the default view for the given source.  This view is never
        // affiliated with any CollectionViewSource.  It may be a
        // CollectionViewProxy over the original view 
        static internal CollectionView GetDefaultCollectionView(object source)
        { 
            if (!IsValidSourceForView(source)) 
                return null;
 
            DataBindEngine engine = DataBindEngine.CurrentDataBindEngine;
            ViewRecord viewRecord = engine.GetViewRecord(source, DefaultSource, null);

            return (viewRecord != null) ? (CollectionView)viewRecord.View : null; 
        }
 
        ///  
        /// Return the default view for the given source.  This view is never
        /// affiliated with any CollectionViewSource.  The internal version sets 
        /// the culture on the view from the xml:Lang of the host object.
        /// 
        internal static CollectionView GetDefaultCollectionView(object source, DependencyObject d)
        { 
            CollectionView view = GetDefaultCollectionView(source);
 
            // at first use of a view, set its culture from the xml:lang of the 
            // element that's using the view
            if (view != null && view.Culture == null) 
            {
                XmlLanguage language = (d != null) ? (XmlLanguage)d.GetValue(FrameworkElement.LanguageProperty) : null;
                if (language != null)
                { 
                    try
                    { 
                        view.Culture = language.GetSpecificCulture(); 
                    }
                    catch (InvalidOperationException) 
                    {
                    }
                }
            } 

            return view; 
        } 

        // Define the DO's inheritance context 
        internal override DependencyObject InheritanceContext
        {
            get { return _inheritanceContext; }
        } 

        // Receive a new inheritance context (this will be a FE/FCE) 
        internal override void AddInheritanceContext(DependencyObject context, DependencyProperty property) 
        {
            InheritanceContextHelper.AddInheritanceContext(context, 
                                                              this,
                                                              ref _hasMultipleInheritanceContexts,
                                                              ref _inheritanceContext );
 
            // remember which property caused the context - BindingExpression wants to know
            if (!_hasMultipleInheritanceContexts && _inheritanceContext != null) 
            { 
                _propertyForInheritanceContext = property;
            } 
            else
            {
                _propertyForInheritanceContext = null;
            } 
        }
 
        // Remove an inheritance context (this will be a FE/FCE) 
        internal override void RemoveInheritanceContext(DependencyObject context, DependencyProperty property)
        { 
            InheritanceContextHelper.RemoveInheritanceContext(context,
                                                                  this,
                                                                  ref _hasMultipleInheritanceContexts,
                                                                  ref _inheritanceContext); 

            // after removing a context, we don't know which property caused it 
            _propertyForInheritanceContext = null; 
        }
 
        // Says if the current instance has multiple InheritanceContexts
        internal override bool HasMultipleInheritanceContexts
        {
            get { return _hasMultipleInheritanceContexts; } 
        }
 
        // 

        internal bool IsShareableInTemplate() 
        {
            return false;
        }
 
        #endregion Internal Methods
 
        #region Private Methods 

        // 
        //  Private Methods
        //

        // Obtain the view affiliated with the current source.  This may create 
        // a new view, or re-use an existing one.
        void EnsureView() 
        { 
            EnsureView(Source, CollectionViewType);
        } 

        void EnsureView(object source, Type collectionViewType)
        {
            if (_isInitializing || _deferLevel > 0) 
                return;
 
            ICollectionView view; 
            DataSourceProvider dataProvider = source as DataSourceProvider;
 
            // listen for DataChanged events from an DataSourceProvider
            if (dataProvider != _dataProvider)
            {
                if (_dataProvider != null) 
                {
                    DataChangedEventManager.RemoveListener(_dataProvider, this); 
                } 

                _dataProvider = dataProvider; 

                if (_dataProvider != null)
                {
                    DataChangedEventManager.AddListener(_dataProvider, this); 
                    _dataProvider.InitialLoad();
                } 
            } 

            // if the source is DataSourceProvider, use its Data instead 
            if (dataProvider != null)
            {
                source = dataProvider.Data;
            } 

            // get the view 
            if (source != null) 
            {
                DataBindEngine engine = DataBindEngine.CurrentDataBindEngine; 
                ViewRecord viewRecord = engine.GetViewRecord(source, this, collectionViewType);
                view = viewRecord.View;
                _isViewInitialized = viewRecord.IsInitialized;
 
                // bring view up to date with the CollectionViewSource
                if (_version != viewRecord.Version) 
                { 
                    ApplyPropertiesToView(view);
                    viewRecord.Version = _version; 
                }
            }
            else
            { 
                view = null;
            } 
 
            // update the View property
            SetValue(ViewPropertyKey, view); 
        }

        // Forward properties from the CollectionViewSource to the CollectionView
        void ApplyPropertiesToView(ICollectionView view) 
        {
            if (view == null || _deferLevel > 0) 
                return; 

            using (view.DeferRefresh()) 
            {
                int i, n;

                // Culture 
                if (Culture != null)
                { 
                    view.Culture = Culture; 
                }
 
                // Sort
                if (view.CanSort)
                {
                    view.SortDescriptions.Clear(); 
                    for (i=0, n=SortDescriptions.Count;  i < n;  ++i)
                    { 
                        view.SortDescriptions.Add(SortDescriptions[i]); 
                    }
                } 
                else if (SortDescriptions.Count > 0)
                    throw new InvalidOperationException(SR.Get(SRID.CannotSortView, view));

                // Filter 
                Predicate filter;
                if (FilterHandlersField.GetValue(this) != null) 
                { 
                    filter = FilterWrapper;
                } 
                else
                {
                    filter = null;
                } 

                if (view.CanFilter) 
                { 
                    view.Filter = filter;
                } 
                else if (filter != null)
                    throw new InvalidOperationException(SR.Get(SRID.CannotFilterView, view));

                // GroupBy 
                if (view.CanGroup)
                { 
                    view.GroupDescriptions.Clear(); 
                    for (i=0, n=GroupDescriptions.Count;  i < n;  ++i)
                    { 
                        view.GroupDescriptions.Add(GroupDescriptions[i]);
                    }
                }
                else if (GroupDescriptions.Count > 0) 
                    throw new InvalidOperationException(SR.Get(SRID.CannotGroupView, view));
            } 
        } 

        // return the original (un-proxied) view for the given view 
        static ICollectionView GetOriginalView(ICollectionView view)
        {
            for (   CollectionViewProxy proxy = view as CollectionViewProxy;
                    proxy != null; 
                    proxy = view as CollectionViewProxy)
            { 
                view = proxy.ProxiedView; 
            }
 
            return view;
        }

        Predicate FilterWrapper 
        {
            get 
            { 
                if (_filterStub == null)
                { 
                    _filterStub = new FilterStub(this);
                }

                return _filterStub.FilterWrapper; 
            }
        } 
 
        bool WrapFilter(object item)
        { 
            FilterEventArgs args = new FilterEventArgs(item);
            FilterEventHandler handlers = FilterHandlersField.GetValue(this);

            if (handlers != null) 
            {
                handlers(this, args); 
            } 

            return args.Accepted; 
        }

        // a change occurred in one of the collections that we forward to the view
        void OnForwardedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
        {
            OnForwardedPropertyChanged(); 
        } 

        // a change occurred in one of the properties that we forward to the view 
        void OnForwardedPropertyChanged()
        {
            // increment the version number.  This causes the change to get applied
            // to dormant views when they become active. 
            unchecked {++ _version;}
 
            // apply the change to the current view 
            ApplyPropertiesToView(View);
        } 

        // defer changes
        void BeginDefer()
        { 
            ++ _deferLevel;
        } 
 
        void EndDefer()
        { 
            if (--_deferLevel == 0)
            {
                EnsureView();
            } 
        }
 
        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject 
        //  2. This is a performance optimization
        //
        internal override int EffectiveValuesInitialSize
        { 
            get { return 3; }
        } 
 
        #endregion Private Methods
 
        #region Private Types

        //
        //  Private Types 
        //
 
        private class DeferHelper : IDisposable 
        {
            public DeferHelper(CollectionViewSource target) 
            {
                _target = target;
                _target.BeginDefer();
            } 

            public void Dispose() 
            { 
                if (_target != null)
                { 
                    CollectionViewSource target = _target;
                    _target = null;
                    target.EndDefer();
                } 
            }
 
            private CollectionViewSource _target; 
        }
 
        // This class is used to break the reference chain from a collection
        // view to a UI element (typically Window or Page), created when the
        // app adds a handler (belonging to the Window or Page) to the Filter
        // event.  This class uses a weak reference to the CollectionViewSource 
        // to break the chain and avoid a leak (bug 123012)
        private class FilterStub 
        { 
            public FilterStub(CollectionViewSource parent)
            { 
                _parent = new WeakReference(parent);
                _filterWrapper = new Predicate(WrapFilter);
            }
 
            public Predicate FilterWrapper
            { 
                get { return _filterWrapper; } 
            }
 
            bool WrapFilter(object item)
            {
                CollectionViewSource parent = (CollectionViewSource)_parent.Target;
                if (parent != null) 
                {
                    return parent.WrapFilter(item); 
                } 
                else
                { 
                    return true;
                }
            }
 
            WeakReference _parent;
            Predicate _filterWrapper; 
        } 

        #endregion Private Types 

        #region Private Data

        // 
        //  Private Data
        // 
 
        // properties that get forwarded to the view
        CultureInfo                             _culture; 
        SortDescriptionCollection               _sort;
        ObservableCollection  _groupBy;

        // other state 
        bool                _isInitializing;
        bool                _isViewInitialized; // view is initialized when it is first retrieved externally 
        int                 _version;       // timestamp of last change to a forwarded property 
        int                 _deferLevel;    // counts nested calls to BeginDefer
        DataSourceProvider  _dataProvider;  // DataSourceProvider whose DataChanged event we want 
        FilterStub          _filterStub;    // used to support the Filter event

        // Fields to implement DO's inheritance context
        DependencyObject    _inheritanceContext; 
        bool                _hasMultipleInheritanceContexts;
        DependencyProperty  _propertyForInheritanceContext; 
 
        // the placeholder source for all default views
        internal static readonly CollectionViewSource DefaultSource = new CollectionViewSource(); 

        // This uncommon field is used to store the handlers for the Filter event
        private  static readonly UncommonField FilterHandlersField = new UncommonField();
 
        #endregion Private Data
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK