Click here to Skip to main content
15,893,814 members
Articles / Desktop Programming / WPF

Managing Multiple selection in View Model (.NET Metro Style Apps)

Rate me:
Please Sign up or sign in to vote.
4.44/5 (6 votes)
29 Jun 2012CPOL3 min read 73.8K   3K   11  
This article provides Attached Behavior based approach to manage Multiple Selection in Collection Based UI control from the View Model. All the code in this article is strictly applicable to Win 8 metro style apps. Though the Behaviors can be easily adapted to WPF/Silverlight.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Windows.ApplicationModel;
using Windows.UI.Xaml;

namespace WinRtBehaviors
{
    /// <summary>
    /// Attached dependency property storing 'behaviors'
    /// </summary>
    public static class Interaction
    {
        /// <summary>
        /// Dictionary containing the hash code of a collection and a weak reference to the owner of the collection. This way, the 
        /// <see cref="OnBehaviorsCollectionChanged"/> can be introcuded without causing memory leaks.
        /// </summary>
        private static readonly Dictionary<int, WeakReference<FrameworkElement>> _collectionOwners = new Dictionary<int, WeakReference<FrameworkElement>>(); 

        public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached("Behaviors", typeof (ObservableCollection<Behavior>),
            typeof (Interaction), new PropertyMetadata(DesignMode.DesignModeEnabled ? new ObservableCollection<Behavior>() : null, BehaviorsChanged));


        /// <summary>
        /// Called when Property is retrieved
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ObservableCollection<Behavior> GetBehaviors(DependencyObject obj)
        {
            var behaviors = obj.GetValue(BehaviorsProperty) as ObservableCollection<Behavior>;
            if (behaviors == null)
            {
                behaviors = new ObservableCollection<Behavior>();
                SetBehaviors(obj, behaviors);
            }

            return behaviors;
        }

        /// <summary>
        /// Called when Property is retrieved
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetBehaviors(DependencyObject obj, ObservableCollection<Behavior> value)
        {
            obj.SetValue(BehaviorsProperty, value);
        }

        /// <summary>
        /// Called when the property changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private static void BehaviorsChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var associatedObject = sender as FrameworkElement;
            if (associatedObject != null)
            {
                var oldList = args.OldValue as ObservableCollection<Behavior>;
                if (oldList != null)
                {
                    foreach (var behavior in oldList)
                    {
                        behavior.AssociatedObject = null;
                    }

                    _collectionOwners.Remove(oldList.GetHashCode());
                    oldList.CollectionChanged -= OnBehaviorsCollectionChanged;
                }

                var newList = args.NewValue as ObservableCollection<Behavior>;
                if (newList != null)
                {
                    foreach (var behavior in newList)
                    {
                        behavior.AssociatedObject = sender as FrameworkElement;
                    }

                    _collectionOwners.Add(newList.GetHashCode(), new WeakReference<FrameworkElement>(associatedObject));
                    newList.CollectionChanged += OnBehaviorsCollectionChanged;
                }
            }
        }

        private static void OnBehaviorsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            FrameworkElement associatedObject;
            if (!_collectionOwners[sender.GetHashCode()].TryGetTarget(out associatedObject))
            {
                return;
            }

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    {
                        foreach (Behavior behavior in e.NewItems)
                        {
                            behavior.AssociatedObject = associatedObject;
                        }
                        break;
                    }
                case NotifyCollectionChangedAction.Reset:
                case NotifyCollectionChangedAction.Remove:
                    {
                        foreach (Behavior behavior in e.OldItems)
                        {
                            behavior.AssociatedObject = null;
                        }
                        break;
                    }
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
Software Engineer based out in Noida.

Technology skillset – .NET, WPF, WCF, LINQ, XAML.

Started blogging on http://1wpf.wordpress.com/


Stackoverflow Profile -> http://stackoverflow.com/users/649524/tilak

Comments and Discussions