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

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

#
C# | 247 lines | 129 code | 26 blank | 92 comment | 18 complexity | f8997fcaaf35870d2134b9c8e14b4058 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.Generic;
 20using System.Globalization;
 21using System.Windows;
 22using Microsoft.Practices.Composite.Regions;
 23using Microsoft.Practices.Composite.Wpf.Properties;
 24
 25namespace Microsoft.Practices.Composite.Wpf.Regions
 26{
 27    /// <summary>
 28    /// This class is responsible for maintaining a collection of regions and attaching regions to controls. 
 29    /// </summary>
 30    /// <remarks>
 31    /// This class supplies the attached properties that can be used for simple region creation from XAML.
 32    /// It finds an adapter mapped to a WPF control and associates a new region to that control by calling
 33    /// <see cref="AttachNewRegion"/> automatically.
 34    /// </remarks>
 35    public class RegionManager : IRegionManager
 36    {
 37        #region Static properties (for XAML support)
 38
 39        /// <summary>
 40        /// Identifies the RegionName attached property.
 41        /// </summary>
 42        /// <remarks>
 43        /// When a control has both the <see cref="RegionNameProperty"/> and
 44        /// <see cref="RegionManagerProperty"/> attached properties set to
 45        /// a value different than <see langword="null" /> and there is a
 46        /// <see cref="IRegionAdapter"/> mapping registered for the control, it
 47        /// will create and adapt a new region for that control, and register it
 48        /// in the <see cref="IRegionManager"/> with the specified region name.
 49        /// </remarks>
 50        public static readonly DependencyProperty RegionNameProperty = DependencyProperty.RegisterAttached(
 51            "RegionName",
 52            typeof(string),
 53            typeof(RegionManager),
 54            new PropertyMetadata(OnSetRegionNameCallback));
 55
 56        /// <summary>
 57        /// Sets the <see cref="RegionNameProperty"/> attached property.
 58        /// </summary>
 59        /// <param name="regionTarget">The object to adapt. This is typically a container (i.e a control).</param>
 60        /// <param name="regionName">The name of the region to register.</param>
 61        public static void SetRegionName(DependencyObject regionTarget, string regionName)
 62        {
 63            regionTarget.SetValue(RegionNameProperty, regionName);
 64        }
 65
 66        /// <summary>
 67        /// Gets the value for the <see cref="RegionNameProperty"/> attached property.
 68        /// </summary>
 69        /// <param name="regionTarget">The object to adapt. This is typically a container (i.e a control).</param>
 70        /// <returns>The name of the region that should be created when 
 71        /// <see cref="RegionManagerProperty"/> is also set in this element.</returns>
 72        public static string GetRegionName(DependencyObject regionTarget)
 73        {
 74            return regionTarget.GetValue(RegionNameProperty) as string;
 75        }
 76
 77        private static void OnSetRegionNameCallback(DependencyObject element, DependencyPropertyChangedEventArgs args)
 78        {
 79            if (element != null)
 80            {
 81                IRegionManager regionManager = element.GetValue(RegionManagerProperty) as IRegionManager;
 82                if (regionManager != null)
 83                {
 84                    string oldRegionName = args.OldValue as string;
 85                    if (oldRegionName != null)
 86                    {
 87                        regionManager.Regions.Remove(oldRegionName);
 88                    }
 89
 90                    string newRegionName = args.NewValue as string;
 91                    if (newRegionName != null)
 92                    {
 93                        regionManager.AttachNewRegion(element, newRegionName);
 94                    }
 95                }
 96            }
 97        }
 98
 99        /// <summary>
100        /// Identifies the RegionManager attached property.
101        /// </summary>
102        /// <remarks>
103        /// When a control has both the <see cref="RegionNameProperty"/> and
104        /// <see cref="RegionManagerProperty"/> attached properties set to
105        /// a value different than <see langword="null" /> and there is a
106        /// <see cref="IRegionAdapter"/> mapping registered for the control, it
107        /// will create and adapt a new region for that control, and register it
108        /// in the <see cref="IRegionManager"/> with the specified region name.
109        /// </remarks>
110        public static readonly DependencyProperty RegionManagerProperty =
111            DependencyProperty.RegisterAttached("RegionManager", typeof(IRegionManager), typeof(RegionManager),
112                                                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnSetRegionManagerCallback));
113
114        /// <summary>
115        /// Gets the value of the <see cref="RegionNameProperty"/> attached property.
116        /// </summary>
117        /// <param name="target">The target element.</param>
118        /// <returns>The <see cref="IRegionManager"/> attached to the <paramref name="target"/> element.</returns>
119        public static IRegionManager GetRegionManager(DependencyObject target)
120        {
121            return (IRegionManager)target.GetValue(RegionManagerProperty);
122        }
123
124        /// <summary>
125        /// Sets the <see cref="RegionManagerProperty"/> attached property.
126        /// </summary>
127        /// <param name="target">The target element.</param>
128        /// <param name="value">The value.</param>
129        public static void SetRegionManager(DependencyObject target, IRegionManager value)
130        {
131            target.SetValue(RegionManagerProperty, value);
132        }
133
134        private static void OnSetRegionManagerCallback(DependencyObject element, DependencyPropertyChangedEventArgs args)
135        {
136            if (element != null)
137            {
138                string regionName = element.GetValue(RegionNameProperty) as string;
139                if (regionName != null)
140                {
141                    IRegionManager oldRegionManager = args.OldValue as IRegionManager;
142                    if (oldRegionManager != null)
143                    {
144                        oldRegionManager.Regions.Remove(regionName);
145                    }
146
147                    IRegionManager newRegionManager = args.NewValue as IRegionManager;
148                    if (newRegionManager != null)
149                    {
150                        newRegionManager.AttachNewRegion(element, regionName);
151                    }
152                }
153            }
154        }
155
156        #endregion
157
158        private readonly RegionAdapterMappings regionAdapterMappings;
159        private readonly IDictionary<string, IRegion> _regions;
160
161        /// <summary>
162        /// Initializes a new instance of <see cref="RegionManager"/>.
163        /// </summary>
164        public RegionManager()
165        {
166            _regions = new RegionsDictionary(this);
167        }
168
169        /// <summary>
170        /// Initializes a new instance of <see cref="RegionManager"/>.
171        /// </summary>
172        /// <param name="mappings">The <see cref="RegionAdapterMappings"/> that
173        /// will be used when calling <see cref="AttachNewRegion"/> explicitly
174        /// or by creating regions by using attached properties through XAML.
175        /// </param>
176        public RegionManager(RegionAdapterMappings mappings)
177            : this()
178        {
179            this.regionAdapterMappings = mappings;
180        }
181
182        /// <summary>
183        /// Gets a dictionary of <see cref="IRegion"/> that identify each region by name. 
184        /// You can use this dictionary to add or remove regions to the current region manager.
185        /// </summary>
186        /// <value>An <see cref="IDictionary{TKey,TValue}"/> with all the registered regions.</value>
187        public IDictionary<string, IRegion> Regions
188        {
189            get { return _regions; }
190        }
191
192        /// <summary>
193        /// Attaches a region to an object and adds it to the region manager.
194        /// </summary>
195        /// <param name="regionTarget">The object to adapt. This is typically a container (i.e a control).</param>
196        /// <param name="regionName">The name of the region to register.</param>
197        /// <exception cref="ArgumentException">When regions collection already has a region registered using <paramref name="regionName"/>.</exception>
198        public void AttachNewRegion(object regionTarget, string regionName)
199        {
200            if (Regions.ContainsKey(regionName))
201                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.RegionNameExistsException, regionName));
202
203            IRegionAdapter regionAdapter = regionAdapterMappings.GetMapping(regionTarget.GetType());
204            IRegion region = regionAdapter.Initialize(regionTarget);
205
206            Regions.Add(regionName, region);
207        }
208
209        /// <summary>
210        /// Creates a new region manager.
211        /// </summary>
212        /// <returns>A new region manager that can be used as a different scope from the current region manager.</returns>
213        public IRegionManager CreateRegionManager()
214        {
215            return new RegionManager(this.regionAdapterMappings);
216        }
217
218        class RegionsDictionary : Dictionary<string, IRegion>, IDictionary<string, IRegion>
219        {
220            private readonly IRegionManager regionManager;
221
222            internal RegionsDictionary(IRegionManager regionManager)
223            {
224                this.regionManager = regionManager;
225            }
226
227            void IDictionary<string, IRegion>.Add(string key, IRegion value)
228            {
229                base.Add(key, value);
230                value.RegionManager = regionManager;
231            }
232
233            bool IDictionary<string, IRegion>.Remove(string key)
234            {
235                bool removed = false;
236                if (this.ContainsKey(key))
237                {
238                    IRegion region = this[key];
239                    removed = base.Remove(key);
240                    region.RegionManager = null;
241                }
242
243                return removed;
244            }
245        }
246    }
247}