PageRenderTime 30ms CodeModel.GetById 18ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/V1/trunk/Source/CAL/Composite.Wpf/Regions/ViewsCollection.cs

#
C# | 207 lines | 144 code | 17 blank | 46 comment | 15 complexity | 423149b2a188eabc9fd1ce9cd7140386 MD5 | raw file
  1//===============================================================================
  2// Microsoft patterns & practices
  3// Composite Application Guidance for Windows Presentation Foundation
  4//===============================================================================
  5// Copyright (c) Microsoft Corporation.  All rights reserved.
  6// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9// FITNESS FOR A PARTICULAR PURPOSE.
 10//===============================================================================
 11// The example companies, organizations, products, domain names,
 12// e-mail addresses, logos, people, places, and events depicted
 13// herein are fictitious.  No association with any real company,
 14// organization, product, domain name, email address, logo, person,
 15// places, or events is intended or should be inferred.
 16//===============================================================================
 17
 18using System;
 19using System.Collections;
 20using System.Collections.Generic;
 21using System.Collections.ObjectModel;
 22using System.Collections.Specialized;
 23using System.Linq;
 24using Microsoft.Practices.Composite.Regions;
 25
 26namespace Microsoft.Practices.Composite.Wpf.Regions
 27{
 28    /// <summary>
 29    /// Implementation of <see cref="IViewsCollection"/> that takes an <see cref="ObservableCollection{T}"/> of <see cref="ItemMetadata"/>
 30    /// and filters it to display an <see cref="INotifyCollectionChanged"/> collection of
 31    /// <see cref="object"/> elements (the items which the <see cref="ItemMetadata"/> wraps).
 32    /// </summary>
 33    public class ViewsCollection : IViewsCollection
 34    {
 35        private readonly ObservableCollection<ItemMetadata> subjectCollection;
 36        private readonly Predicate<ItemMetadata> filter;
 37
 38        private readonly List<object> filteredCollection = new List<object>();
 39
 40        /// <summary>
 41        /// Initializes a new instance of <see cref="ViewsCollection"/>.
 42        /// </summary>
 43        /// <param name="list">The list to wrap and filter.</param>
 44        /// <param name="filter">A predicate to filter the <paramref name="list"/> collection.</param>
 45        public ViewsCollection(ObservableCollection<ItemMetadata> list, Predicate<ItemMetadata> filter)
 46        {
 47            this.subjectCollection = list;
 48            this.filter = filter;
 49            Initialize();
 50            subjectCollection.CollectionChanged += UnderlyingCollection_CollectionChanged;
 51        }
 52
 53        /// <summary>
 54        /// Determines whether the collection contains a specific value.
 55        /// </summary>
 56        /// <param name="value">The object to locate in the collection.</param>
 57        /// <returns><see langword="true" /> if <paramref name="value"/> is found in the collection; otherwise, <see langword="false" />.</returns>
 58        public bool Contains(object value)
 59        {
 60            return filteredCollection.Contains(value);
 61        }
 62
 63        ///<summary>
 64        ///Returns an enumerator that iterates through the collection.
 65        ///</summary>
 66        ///<returns>
 67        ///A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
 68        ///</returns>
 69        public IEnumerator<object> GetEnumerator()
 70        {
 71            return filteredCollection.GetEnumerator();
 72        }
 73
 74        ///<summary>
 75        ///Returns an enumerator that iterates through a collection.
 76        ///</summary>
 77        ///<returns>
 78        ///An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
 79        ///</returns>
 80        IEnumerator IEnumerable.GetEnumerator()
 81        {
 82            return GetEnumerator();
 83        }
 84
 85        /// <summary>
 86        /// Occurs when the collection changes.
 87        /// </summary>
 88        public event NotifyCollectionChangedEventHandler CollectionChanged;
 89
 90        private void AddAndNotify(object item)
 91        {
 92            AddAndNotify(new List<object>(1) { item });
 93        }
 94
 95        private void AddAndNotify(IList items)
 96        {
 97            if (items.Count > 0)
 98            {
 99                filteredCollection.AddRange(items.Cast<object>());
100                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items));
101            }
102        }
103
104        private void RemoveAndNotify(object item)
105        {
106            RemoveAndNotify(new List<object>(1) { item });
107        }
108
109        private void RemoveAndNotify(IList items)
110        {
111            if (items.Count > 0)
112            {
113                int index = -1;
114                if (items.Count == 1)
115                {
116                    index = filteredCollection.IndexOf(items[0]);
117                }
118                foreach (object item in items)
119                {
120                    filteredCollection.Remove(item);
121                }
122                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items, index));
123            }
124        }
125
126        private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
127        {
128            NotifyCollectionChangedEventHandler Handler = CollectionChanged;
129            if (Handler != null) Handler(this, e);
130        }
131
132        private void Reset()
133        {
134            foreach (ItemMetadata itemMetadata in subjectCollection)
135            {
136                itemMetadata.MetadataChanged -= itemMetadata_MetadataChanged;
137            }
138            filteredCollection.Clear();
139            Initialize();
140            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
141        }
142
143        private void Initialize()
144        {
145            foreach (ItemMetadata itemMetadata in subjectCollection)
146            {
147                itemMetadata.MetadataChanged += itemMetadata_MetadataChanged;
148                if (filter(itemMetadata))
149                {
150                    filteredCollection.Add(itemMetadata.Item);
151                }
152            }
153        }
154
155        void UnderlyingCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
156        {
157            List<object> changedItems = new List<object>();
158            switch (e.Action)
159            {
160                case NotifyCollectionChangedAction.Add:
161                    foreach (ItemMetadata itemMetadata in e.NewItems)
162                    {
163                        itemMetadata.MetadataChanged += itemMetadata_MetadataChanged;
164                        if (filter(itemMetadata))
165                        {
166                            changedItems.Add(itemMetadata.Item);
167                        }
168                    }
169                    AddAndNotify(changedItems);
170                    break;
171                case NotifyCollectionChangedAction.Remove:
172                    foreach (ItemMetadata itemMetadata in e.OldItems)
173                    {
174                        itemMetadata.MetadataChanged -= itemMetadata_MetadataChanged;
175                        if (filteredCollection.Contains(itemMetadata.Item))
176                        {
177                            changedItems.Add(itemMetadata.Item);
178                        }
179                    }
180                    RemoveAndNotify(changedItems);
181                    break;
182                default:
183                    Reset();
184                    break;
185            }
186        }
187
188        void itemMetadata_MetadataChanged(object sender, EventArgs e)
189        {
190            ItemMetadata itemMetadata = (ItemMetadata)sender;
191            if (filteredCollection.Contains(itemMetadata.Item))
192            {
193                if (filter(itemMetadata) == false)
194                {
195                    RemoveAndNotify(itemMetadata.Item);
196                }
197            }
198            else
199            {
200                if (filter(itemMetadata) == true)
201                {
202                    AddAndNotify(itemMetadata.Item);
203                }
204            }
205        }
206    }
207}