EditingContext.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 / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / Base / Core / EditingContext.cs / 1305376 / EditingContext.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Presentation
{ 

    using System.Activities.Presentation.Internal.Properties; 
    using System; 
    using System.Runtime;
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.Text; 
    using System.Activities.Presentation;
 
    //  
    // The EditingContext class contains contextual state about a designer.  This includes permanent
    // state such as list of services running in the designer. 
    // It also includes transient state consisting of context items.  Examples of transient
    // context item state include the set of currently selected objects as well as the editing tool
    // being used to manipulate objects on the design surface.
    // 
    // The editing context is designed to be a concrete class for ease of use.  It does have a protected
    // API that can be used to replace its implementation. 
    //  
    public class EditingContext : IDisposable
    { 

        private ContextItemManager _contextItems;
        private ServiceManager _services;
 
        // 
        // Creates a new editing context. 
        //  
        public EditingContext()
        { 
        }


        //  
        // The Disposing event gets fired just before the context gets disposed.
        //  
        public event EventHandler Disposing; 

        //  
        // Returns the local collection of context items offered by this editing context.
        // 
        // 
        public ContextItemManager Items 
        {
            get { 
                if (_contextItems == null) 
                {
                    _contextItems = CreateContextItemManager(); 
                    if (_contextItems == null)
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException(
                            string.Format(CultureInfo.CurrentCulture, Resources.Error_NullImplementation, "CreateContextItemManager"))); 
                    }
                } 
 
                return _contextItems;
            } 
        }

        // 
        // Returns the service manager for this editing context. 
        // 
        //  
        public ServiceManager Services 
        {
            get { 
                if (_services == null)
                {
                    _services = CreateServiceManager();
                    if (_services == null) 
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException( 
                            string.Format(CultureInfo.CurrentCulture, Resources.Error_NullImplementation, "CreateServiceManager"))); 
                    }
                } 

                return _services;
            }
        } 

        //  
        // Creates an instance of the context item manager to be returned from 
        // the ContextItems property.  The default implementation creates a
        // ContextItemManager that supports delayed activation of design editor 
        // managers through the declaration of a SubscribeContext attribute on
        // the design editor manager.
        // 
        // Returns an implementation of the ContextItemManager class. 
        protected virtual ContextItemManager CreateContextItemManager()
        { 
            return new DefaultContextItemManager(this); 
        }
 
        // 
        // Creates an instance of the service manager to be returned from the
        // Services property. The default implementation creates a ServiceManager
        // that supports delayed activation of design editor managers through the 
        // declaration of a SubscribeService attribute on the design editor manager.
        //  
        // Returns an implemetation of the ServiceManager class. 
        protected virtual ServiceManager CreateServiceManager()
        { 
            return new DefaultServiceManager();
        }

        //  
        // Disposes this editing context.
        //  
        public void Dispose() 
        {
            Dispose(true); 
            GC.SuppressFinalize(this);
        }

        //  
        // Disposes this editing context.
        // True if this object is being disposed, or false if it is finalizing. 
        //  
        protected virtual void Dispose(bool disposing)
        { 
            if (disposing)
            {
                // Let any interested parties know the context is being disposed
                if (Disposing != null) 
                {
                    Disposing(this, EventArgs.Empty); 
                } 

                IDisposable d = _services as IDisposable; 
                if (d != null)
                {
                    d.Dispose();
                } 

                d = _contextItems as IDisposable; 
                if (d != null) 
                {
                    d.Dispose(); 
                }
            }
        }
 
        // 
        // This is the default context item manager for our editing context. 
        //  
        private sealed class DefaultContextItemManager : ContextItemManager
        { 
            private EditingContext _context;
            private DefaultContextLayer _currentLayer;
            private Dictionary _subscriptions;
 
            internal DefaultContextItemManager(EditingContext context)
            { 
                _context = context; 
                _currentLayer = new DefaultContextLayer(null);
            } 

            // 
            // This changes a context item to the given value.  It is illegal to pass
            // null here.  If you want to set a context item to its empty value create 
            // an instance of the item using a default constructor.
            //  
            //  
            public override void SetValue(ContextItem value)
            { 
                if (value == null)
                {
                    throw FxTrace.Exception.ArgumentNull("value");
                } 

                // The rule for change is that we store the new value, 
                // raise a change on the item, and then raise a change 
                // to everyone else.  If changing the item fails, we recover
                // the previous item. 
                ContextItem existing, existingRawValue;
                existing = existingRawValue = GetValueNull(value.ItemType);

                if (existing == null) 
                {
                    existing = GetValue(value.ItemType); 
                } 

                bool success = false; 

                try
                {
                    _currentLayer.Items[value.ItemType] = value; 
                    NotifyItemChanged(_context, value, existing);
                    success = true; 
                } 
                finally
                { 
                    if (success)
                    {
                        OnItemChanged(value);
                    } 
                    else
                    { 
                        // The item threw during its transition to 
                        // becoming active.  Put the old one back.
                        // We must put the old one back by re-activating 
                        // it.  This could throw a second time, so we
                        // cover this case by removing the value first.
                        // Should it throw again, we won't recurse because
                        // the existing raw value would be null. 

                        _currentLayer.Items.Remove(value.ItemType); 
                        if (existingRawValue != null) 
                        {
                            SetValue(existingRawValue); 
                        }
                    }
                }
            } 

            //  
            // Returns true if the item manager contains an item of the given type. 
            // This only looks in the current layer.
            //  
            // 
            // 
            public override bool Contains(Type itemType)
            { 
                if (itemType == null)
                { 
                    throw FxTrace.Exception.ArgumentNull("itemType"); 
                }
                if (!typeof(ContextItem).IsAssignableFrom(itemType)) 
                {
                    throw FxTrace.Exception.AsError(new ArgumentException(
                        string.Format(CultureInfo.CurrentCulture,
                        Resources.Error_ArgIncorrectType, 
                        "itemType", typeof(ContextItem).FullName)));
                } 
 
                return _currentLayer.Items.ContainsKey(itemType);
            } 

            // 
            // Returns an instance of the requested item type.  If there is no context
            // item with the given type, an empty item will be created. 
            // 
            //  
            //  
            public override ContextItem GetValue(Type itemType)
            { 

                ContextItem item = GetValueNull(itemType);

                if (item == null) 
                {
 
                    // Check the default item table and add a new 
                    // instance there if we need to
                    if (!_currentLayer.DefaultItems.TryGetValue(itemType, out item)) 
                    {
                        item = (ContextItem)Activator.CreateInstance(itemType);

                        // Verify that the resulting item has the correct item type 
                        // If it doesn't, it means that the user provided a derived
                        // item type 
                        if (item.ItemType != itemType) 
                        {
                            throw FxTrace.Exception.AsError(new ArgumentException(string.Format( 
                                CultureInfo.CurrentCulture,
                                Resources.Error_DerivedContextItem,
                                itemType.FullName,
                                item.ItemType.FullName))); 
                        }
 
                        // Now push the item in the context so we have 
                        // a consistent reference
                        _currentLayer.DefaultItems.Add(item.ItemType, item); 
                    }
                }

                return item; 
            }
 
            //  
            // Similar to GetValue, but returns NULL if the item isn't found instead of
            // creating an empty item. 
            // 
            // 
            // 
            private ContextItem GetValueNull(Type itemType) 
            {
 
                if (itemType == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("itemType"); 
                }
                if (!typeof(ContextItem).IsAssignableFrom(itemType))
                {
                    throw FxTrace.Exception.AsError(new ArgumentException( 
                        string.Format(CultureInfo.CurrentCulture,
                        Resources.Error_ArgIncorrectType, 
                        "itemType", typeof(ContextItem).FullName))); 
                }
 
                ContextItem item = null;
                DefaultContextLayer layer = _currentLayer;
                while (layer != null && !layer.Items.TryGetValue(itemType, out item))
                { 
                    layer = layer.ParentLayer;
                } 
 
                return item;
            } 

            // 
            // Enumerates the context items in the editing context.  This enumeration
            // includes prior layers unless the enumerator hits an isolated layer. 
            // Enumeration is typically not useful in most scenarios but it is provided so
            // that developers can search in the context and learn what is placed in it. 
            //  
            // 
            public override IEnumerator GetEnumerator() 
            {
                return _currentLayer.Items.Values.GetEnumerator();
            }
 
            // 
            // Called when an item changes value.  This happens in one of two ways: 
            // either the user has called Change, or the user has removed a layer. 
            // 
            //  
            private void OnItemChanged(ContextItem item)
            {
                SubscribeContextCallback callback;
 
                Fx.Assert(item != null, "You cannot pass a null item here.");
 
                if (_subscriptions != null && _subscriptions.TryGetValue(item.ItemType, out callback)) 
                {
                    callback(item); 
                }
            }

            //  
            // Adds an event callback that will be invoked with a context item of the given item type changes.
            //  
            //  
            // 
            public override void Subscribe(Type contextItemType, SubscribeContextCallback callback) 
            {
                if (contextItemType == null)
                {
                    throw FxTrace.Exception.ArgumentNull("contextItemType"); 
                }
                if (callback == null) 
                { 
                    throw FxTrace.Exception.ArgumentNull("callback");
                } 
                if (!typeof(ContextItem).IsAssignableFrom(contextItemType))
                {
                    throw FxTrace.Exception.AsError(new ArgumentException(
                        string.Format(CultureInfo.CurrentCulture, 
                        Resources.Error_ArgIncorrectType,
                        "contextItemType", typeof(ContextItem).FullName))); 
                } 

                if (_subscriptions == null) 
                {
                    _subscriptions = new Dictionary();
                }
 
                SubscribeContextCallback existing = null;
 
                _subscriptions.TryGetValue(contextItemType, out existing); 

                existing = (SubscribeContextCallback)Delegate.Combine(existing, callback); 
                _subscriptions[contextItemType] = existing;

                // If the context is already present, invoke the callback.
                ContextItem item = GetValueNull(contextItemType); 

                if (item != null) 
                { 
                    callback(item);
                } 
            }

            // 
            //     Removes a subscription. 
            // 
            public override void Unsubscribe(Type contextItemType, SubscribeContextCallback callback) 
            { 

                if (contextItemType == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("contextItemType");
                }
                if (callback == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("callback"); 
                } 
                if (!typeof(ContextItem).IsAssignableFrom(contextItemType))
                { 
                    throw FxTrace.Exception.AsError(new ArgumentException(
                        string.Format(CultureInfo.CurrentCulture,
                        Resources.Error_ArgIncorrectType,
                        "contextItemType", typeof(ContextItem).FullName))); 
                }
                if (_subscriptions != null) 
                { 
                    SubscribeContextCallback existing;
                    if (_subscriptions.TryGetValue(contextItemType, out existing)) 
                    {
                        existing = (SubscribeContextCallback)RemoveCallback(existing, callback);
                        if (existing == null)
                        { 
                            _subscriptions.Remove(contextItemType);
                        } 
                        else 
                        {
                            _subscriptions[contextItemType] = existing; 
                        }
                    }
                }
            } 

            //  
            // This context layer contains our context items. 
            // 
            private class DefaultContextLayer 
            {
                private DefaultContextLayer _parentLayer;
                private Dictionary _items;
                private Dictionary _defaultItems; 

                internal DefaultContextLayer(DefaultContextLayer parentLayer) 
                { 
                    _parentLayer = parentLayer; // can be null
                } 

                internal Dictionary DefaultItems
                {
                    get { 
                        if (_defaultItems == null)
                        { 
                            _defaultItems = new Dictionary(); 
                        }
                        return _defaultItems; 
                    }
                }

                internal Dictionary Items 
                {
                    get { 
                        if (_items == null) 
                        {
                            _items = new Dictionary(); 
                        }
                        return _items;
                    }
                } 

                internal DefaultContextLayer ParentLayer 
                { 
                    get { return _parentLayer; }
                } 
            }
        }

        //  
        // This is the default service manager for our editing context.
        //  
        private sealed class DefaultServiceManager : ServiceManager, IDisposable 
        {
            private static readonly object _recursionSentinel = new object(); 

            private Dictionary _services;
            private Dictionary _subscriptions;
 
            internal DefaultServiceManager()
            { 
            } 

            //  
            // Returns true if the service manager contains a service of the given type.
            // 
            // 
            //  
            public override bool Contains(Type serviceType)
            { 
                if (serviceType == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("serviceType"); 
                }
                return (_services != null && _services.ContainsKey(serviceType));
            }
 
            // 
            // Retrieves the requested service.  This method returns null if the service could not be located. 
            //  
            // 
            //  
            public override object GetService(Type serviceType)
            {
                object service = null;
 
                if (serviceType == null)
                { 
                    throw FxTrace.Exception.ArgumentNull("serviceType"); 
                }
 
                if (_services != null && _services.TryGetValue(serviceType, out service))
                {

                    // If this service is our recursion sentinel, it means that someone is recursing 
                    // while resolving a service callback.  Throw to break out of the recursion
                    // cycle. 
                    if (service == _recursionSentinel) 
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.Error_RecursionResolvingService, serviceType.FullName))); 
                    }

                    // See if this service is a callback.  If it is, invoke it and store
                    // the resulting service back in the dictionary. 
                    PublishServiceCallback callback = service as PublishServiceCallback;
                    if (callback != null) 
                    { 

                        // Store a recursion sentinel in the dictionary so we can easily 
                        // tell if someone is recursing
                        _services[serviceType] = _recursionSentinel;
                        try
                        { 
                            service = callback(serviceType);
                            if (service == null) 
                            { 
                                throw FxTrace.Exception.AsError(new InvalidOperationException(
                                    string.Format(CultureInfo.CurrentCulture, 
                                    Resources.Error_NullService,
                                    callback.Method.DeclaringType.FullName,
                                    serviceType.FullName)));
                            } 

                            if (!serviceType.IsInstanceOfType(service)) 
                            { 
                                throw FxTrace.Exception.AsError(new InvalidOperationException(
                                    string.Format(CultureInfo.CurrentCulture, 
                                    Resources.Error_IncorrectServiceType,
                                    callback.Method.DeclaringType.FullName,
                                    serviceType.FullName,
                                    service.GetType().FullName))); 
                            }
                        } 
                        finally 
                        {
                            // Note, this puts the callback back in place if it threw. 
                            _services[serviceType] = service;
                        }
                    }
                } 

                // If the service is not found locally, do not walk up the parent chain. 
                // This was a major source of unreliability with the component model 
                // design.  For a service to be accessible from the editing context, it
                // must be added. 

                return service;
            }
 
            // 
            // Retrieves an enumerator that can be used to enumerate all of the services that this 
            // service manager publishes. 
            // 
            //  
            public override IEnumerator GetEnumerator()
            {
                if (_services == null)
                { 
                    _services = new Dictionary();
                } 
 
                return _services.Keys.GetEnumerator();
            } 

            // 
            // Calls back on the provided callback when someone has published the requested service.
            // If the service was already available, this method invokes the callback immediately. 
            //
            // A generic version of this method is provided for convience, and calls the non-generic 
            // method with appropriate casts. 
            // 
            //  
            // 
            public override void Subscribe(Type serviceType, SubscribeServiceCallback callback)
            {
                if (serviceType == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("serviceType"); 
                } 
                if (callback == null)
                { 
                    throw FxTrace.Exception.ArgumentNull("callback");
                }

                object service = GetService(serviceType); 
                if (service != null)
                { 
 
                    // If the service is already available, callback immediately
                    callback(serviceType, service); 
                }
                else
                {
 
                    // Otherwise, store this for later
                    if (_subscriptions == null) 
                    { 
                        _subscriptions = new Dictionary();
                    } 
                    SubscribeServiceCallback existing = null;
                    _subscriptions.TryGetValue(serviceType, out existing);
                    existing = (SubscribeServiceCallback)Delegate.Combine(existing, callback);
                    _subscriptions[serviceType] = existing; 
                }
            } 
 
            // 
            // Calls back on the provided callback when someone has published the requested service. 
            // If the service was already available, this method invokes the callback immediately.
            //
            // A generic version of this method is provided for convience, and calls the non-generic
            // method with appropriate casts. 
            // 
            //  
            //  
            public override void Publish(Type serviceType, PublishServiceCallback callback)
            { 
                if (serviceType == null)
                {
                    throw FxTrace.Exception.ArgumentNull("serviceType");
                } 
                if (callback == null)
                { 
                    throw FxTrace.Exception.ArgumentNull("callback"); 
                }
 
                Publish(serviceType, (object)callback);
            }

            //  
            //     If you already have an instance to a service, you can publish it here.
            //  
            //  
            // 
            public override void Publish(Type serviceType, object serviceInstance) 
            {
                if (serviceType == null)
                {
                    throw FxTrace.Exception.ArgumentNull("serviceType"); 
                }
                if (serviceInstance == null) 
                { 
                    throw FxTrace.Exception.ArgumentNull("serviceInstance");
                } 

                if (!(serviceInstance is PublishServiceCallback) && !serviceType.IsInstanceOfType(serviceInstance))
                {
                    throw FxTrace.Exception.AsError(new ArgumentException( 
                        string.Format(CultureInfo.CurrentCulture,
                        Resources.Error_IncorrectServiceType, 
                        typeof(ServiceManager).Name, 
                        serviceType.FullName,
                        serviceInstance.GetType().FullName))); 
                }

                if (_services == null)
                { 
                    _services = new Dictionary();
                } 
 
                try
                { 
                    _services.Add(serviceType, serviceInstance);
                }
                catch (ArgumentException e)
                { 
                    throw FxTrace.Exception.AsError(new ArgumentException(string.Format(
                        CultureInfo.CurrentCulture, 
                        Resources.Error_DuplicateService, serviceType.FullName), e)); 
                }
 
                // Now see if there were any subscriptions that required this service
                SubscribeServiceCallback subscribeCallback;
                if (_subscriptions != null && _subscriptions.TryGetValue(serviceType, out subscribeCallback))
                { 
                    subscribeCallback(serviceType, GetService(serviceType));
                    _subscriptions.Remove(serviceType); 
                } 
            }
 
            // 
            //     Removes a subscription.
            // 
            public override void Unsubscribe(Type serviceType, SubscribeServiceCallback callback) 
            {
 
                if (serviceType == null) 
                {
                    throw FxTrace.Exception.ArgumentNull("serviceType"); 
                }
                if (callback == null)
                {
                    throw FxTrace.Exception.ArgumentNull("callback"); 
                }
 
                if (_subscriptions != null) 
                {
                    SubscribeServiceCallback existing; 
                    if (_subscriptions.TryGetValue(serviceType, out existing))
                    {
                        existing = (SubscribeServiceCallback)RemoveCallback(existing, callback);
                        if (existing == null) 
                        {
                            _subscriptions.Remove(serviceType); 
                        } 
                        else
                        { 
                            _subscriptions[serviceType] = existing;
                        }
                    }
                } 
            }
 
            //  
            // We implement IDisposable so that the editing context can destroy us when it
            // shuts down. 
            // 
            void IDisposable.Dispose()
            {
                if (_services != null) 
                {
                    Dictionary services = _services; 
 
                    try
                    { 
                        foreach (object value in services.Values)
                        {
                            IDisposable d = value as IDisposable;
                            if (d != null) 
                            {
                                d.Dispose(); 
                            } 
                        }
                    } 
                    finally
                    {
                        _services = null;
                    } 
                }
            } 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

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