CollectionViewSource.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Data / CollectionViewSource.cs / 1305600 / CollectionViewSource.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines CollectionViewSource object, the markup-accessible entry 
//              point to CollectionView. 
//
// See spec at http://avalon/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, true)); 
        }

        // a version of the previous method that doesn't create the view (bug 108595)
        private static ICollectionView LazyGetDefaultView(object source) 
        {
            return GetOriginalView(GetDefaultCollectionView(source, false)); 
        } 

        ///  
        /// 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) == LazyGetDefaultView(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, true);
                        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, bool createView)
        {
            if (!IsValidSourceForView(source)) 
                return null;
 
            DataBindEngine engine = DataBindEngine.CurrentDataBindEngine; 
            ViewRecord viewRecord = engine.GetViewRecord(source, DefaultSource, null, createView);
 
            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, true);

            // 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) 
        {
            // remember which property caused the context - BindingExpression wants to know 
            // (this must happen before calling AddInheritanceContext, so that the answer 
            // is ready during the InheritanceContextChanged event)
            if (!_hasMultipleInheritanceContexts && _inheritanceContext == null) 
            {
                _propertyForInheritanceContext = property;
            }
            else 
            {
                _propertyForInheritanceContext = null; 
            } 

            InheritanceContextHelper.AddInheritanceContext(context, 
                                                              this,
                                                              ref _hasMultipleInheritanceContexts,
                                                              ref _inheritanceContext );
        } 

        // 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; 

            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 
            ICollectionView view = null;
 
            if (source != null) 
            {
                DataBindEngine engine = DataBindEngine.CurrentDataBindEngine; 
                ViewRecord viewRecord = engine.GetViewRecord(source, this, collectionViewType, true);

                if (viewRecord != null)
                { 
                    view = viewRecord.View;
                    _isViewInitialized = viewRecord.IsInitialized; 
 
                    // bring view up to date with the CollectionViewSource
                    if (_version != viewRecord.Version) 
                    {
                        ApplyPropertiesToView(view);
                        viewRecord.Version = _version;
                    } 
                }
            } 
 
            // 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();
                } 
                GC.SuppressFinalize(this);
            } 
 
            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