PageRenderTime 28ms CodeModel.GetById 10ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/V4/MVVM RI/MVVM.Client/Infrastructure/Behaviors/SynchronizeSelectedItems.cs

#
C# | 160 lines | 121 code | 17 blank | 22 comment | 13 complexity | effd91d1d4b634ba5cbb6c4b02edf672 MD5 | raw file
  1//===================================================================================
  2// Microsoft patterns & practices
  3// Composite Application Guidance for Windows Presentation Foundation and Silverlight
  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//===================================================================================
 17using System;
 18using System.Collections;
 19using System.Collections.Specialized;
 20using System.Diagnostics.CodeAnalysis;
 21using System.Windows;
 22using System.Windows.Controls;
 23using System.Windows.Interactivity;
 24
 25namespace MVVM.Client.Infrastructure.Behaviors
 26{
 27    /// <summary>
 28    /// Custom behavior that synchronizes the list in <see cref="ListBox.SelectedItems"/> with a collection.
 29    /// </summary>
 30    /// <remarks>
 31    /// This behavior uses a weak event handler to listen for changes on the synchronized collection.
 32    /// </remarks>
 33    public class SynchronizeSelectedItems : Behavior<ListBox>
 34    {
 35        public static readonly DependencyProperty SelectionsProperty =
 36            DependencyProperty.Register(
 37                "Selections",
 38                typeof(IList),
 39                typeof(SynchronizeSelectedItems),
 40                new PropertyMetadata(null, OnSelectionsPropertyChanged));
 41
 42        private bool updating;
 43        private WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs> currentWeakHandler;
 44
 45        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
 46            Justification = "Dependency property")]
 47        public IList Selections
 48        {
 49            get { return (IList)this.GetValue(SelectionsProperty); }
 50            set { this.SetValue(SelectionsProperty, value); }
 51        }
 52
 53        protected override void OnAttached()
 54        {
 55            base.OnAttached();
 56
 57            this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
 58            this.UpdateSelectedItems();
 59        }
 60
 61        protected override void OnDetaching()
 62        {
 63            this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
 64
 65            base.OnDetaching();
 66        }
 67
 68        private static void OnSelectionsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
 69        {
 70            var behavior = d as SynchronizeSelectedItems;
 71
 72            if (behavior != null)
 73            {
 74                if (behavior.currentWeakHandler != null)
 75                {
 76                    behavior.currentWeakHandler.Detach();
 77                    behavior.currentWeakHandler = null;
 78                }
 79
 80                if (e.NewValue != null)
 81                {
 82                    var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
 83                    if (notifyCollectionChanged != null)
 84                    {
 85                        behavior.currentWeakHandler =
 86                            new WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs>(
 87                                behavior,
 88                                (instance, sender, args) => instance.OnSelectionsCollectionChanged(sender, args),
 89                                (listener) => notifyCollectionChanged.CollectionChanged -= listener.OnEvent);
 90                        notifyCollectionChanged.CollectionChanged += behavior.currentWeakHandler.OnEvent;
 91                    }
 92
 93                    behavior.UpdateSelectedItems();
 94                }
 95            }
 96        }
 97
 98        private void OnSelectedItemsChanged(object sender, SelectionChangedEventArgs e)
 99        {
100            this.UpdateSelections(e);
101        }
102
103        private void UpdateSelections(SelectionChangedEventArgs e)
104        {
105            this.ExecuteIfNotUpdating(
106                () =>
107                {
108                    if (this.Selections != null)
109                    {
110                        foreach (var item in e.AddedItems)
111                        {
112                            this.Selections.Add(item);
113                        }
114
115                        foreach (var item in e.RemovedItems)
116                        {
117                            this.Selections.Remove(item);
118                        }
119                    }
120                });
121        }
122
123        private void OnSelectionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
124        {
125            this.UpdateSelectedItems();
126        }
127
128        private void UpdateSelectedItems()
129        {
130            this.ExecuteIfNotUpdating(
131                () =>
132                {
133                    if (this.AssociatedObject != null)
134                    {
135                        this.AssociatedObject.SelectedItems.Clear();
136                        foreach (var item in this.Selections ?? new object[0])
137                        {
138                            this.AssociatedObject.SelectedItems.Add(item);
139                        }
140                    }
141                });
142        }
143
144        private void ExecuteIfNotUpdating(Action execute)
145        {
146            if (!this.updating)
147            {
148                try
149                {
150                    this.updating = true;
151                    execute();
152                }
153                finally
154                {
155                    this.updating = false;
156                }
157            }
158        }
159    }
160}