DialogPage.cs :  » Development » StyleCop » Microsoft » VisualStudio » Shell » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » StyleCop 
StyleCop » Microsoft » VisualStudio » Shell » DialogPage.cs
//------------------------------------------------------------------------------
// <copyright file="DialogPage.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace Microsoft.VisualStudio.Shell{

    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Shell.Interop;
    using System.Windows.Forms.Design;
    using Microsoft.Win32;
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
    using IServiceProvider = System.IServiceProvider;

    /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage"]' />
    /// <devdoc>
    ///     DialogPage encompasses a tools dialog page.  The default dialog page 
    ///     examines itself for public properties, and offers these properties 
    ///     to the user in a property grid.  You can customize this behavior, 
    ///     however by overriding various methods on the page.  The dialog 
    ///     page will automatically persist any changes made to it to the user's 
    ///     section of the registry, provided that those properties provide 
    ///     support for to/from string conversions on their type converter.
    /// </devdoc>
    [CLSCompliant(false),ComVisible(true)]
    public class DialogPage : Component,
        IWin32Window,
        IProfileManager {

        private IWin32Window     _window;
        private DialogSubclass   _subclass;
        private DialogContainer _container;
        private string           _settingsPath;
        private bool             _initializing = false;
        private bool             _uiActive = false;
        private bool             _propertyChangedHooked = false;
        private EventHandler     _onPropertyChanged;

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.DialogPage"]' />
        /// <devdoc>
        /// Constructs the Dialog Page.
        /// </devdoc>
        public DialogPage() {
            HookProperties(true);
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.AutomationObject"]' />
        /// <devdoc>
        ///     The object the dialog page is going to browse.  The
        ///     default returns "this", but you can change it to
        ///     browse any object you want.
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual object AutomationObject {
            get {
                return this;
            }
        }
        
        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage".Site]' />
        /// <devdoc>
        ///     Override for the site property.  This override is used so we can
        ///     load and save our settings at the appropriate time.
        /// </devdoc>
        public override ISite Site {
            get {
                return base.Site;
                
            }
            set {
                if (value == null && base.Site != null) {
                    // This is dangerous at shut down time and is causing
                    // bad ExecutionEngineExceptions. It's also entirely redundant.
                    //SaveSettingsToStorage();
                }

                base.Site = value;

                if (value != null) {
                    LoadSettingsFromStorage();
                }
            }
        }
        
        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage".Window]' />
        /// <devdoc>
        ///     The window this dialog page will use for its UI.
        ///     This window handle must be constant, so if you are
        ///     returning a Windows Forms control you must make sure
        ///     it does not recreate its handle.  If the window object
        ///     implements IComponent it will be sited by the 
        ///     dialog page so it can get access to global services.
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        protected virtual IWin32Window Window {
            get {
                PropertyGrid grid = new PropertyGrid();
                grid.Location = new Point(0,0);
                grid.ToolbarVisible = false;
                grid.CommandsVisibleIfAvailable = false;
                grid.SelectedObject = AutomationObject;
                return grid;
            }
        }
        
        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.Dispose"]' />
        /// <devdoc>
        ///     Disposes this object.
        /// </devdoc>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {

                if (_container != null)
                {
                    try
                    {
                        _container.Dispose();
                    }
                    catch (Exception)
                    {
                        Debug.Fail("Failed to dispose container");
                    }
                    _container = null;
                }

                if (_window != null && _window is IDisposable)
                {
                    try
                    {
                    ((IDisposable)_window).Dispose();
                    }
                    catch (Exception)
                    {
                        Debug.Fail("Failed to dispose window");
                    }
                    _window = null;
                }

                if (_subclass != null)
                {
                    _subclass = null;
                }

                HookProperties(false);
            }
            base.Dispose(disposing);
        }
        
        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.LoadSettingsFromStorage"]' />
        /// <devdoc>
        ///     This method is called when the dialog page should load
        ///     its default settings from the registry.  The default
        ///     implementation gets the Package service, gets the
        ///     user registry key, and reads in all properties for this
        ///     page that could be converted from strings.
        /// </devdoc>
        public virtual void LoadSettingsFromStorage() {
            _initializing = true;
            try {
                Package package = (Package)GetService(typeof(Package));
                Debug.Assert(package != null, "No package service; we cannot load settings");
                if (package != null) {
                    using (RegistryKey rootKey = package.UserRegistryRoot) {

                        string path = this.SettingsRegistryPath;
                        object automationObject = this.AutomationObject;

                        RegistryKey key = rootKey.OpenSubKey(path, false /* writable */);
                        if (key != null) {
                            using (key) {

                                string[] valueNames = key.GetValueNames();
                                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(automationObject);

                                foreach(string valueName in valueNames) {
                                    string value = key.GetValue(valueName).ToString();

                                    PropertyDescriptor prop = properties[valueName];
                                    if (prop != null && prop.Converter.CanConvertFrom(typeof(string))) {
                                        prop.SetValue(automationObject, prop.Converter.ConvertFromInvariantString(value));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            finally {
                _initializing = false;
            }
            HookProperties(true); //hook if this failed during construction.
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.LoadSettingsFromXml"]' />
        /// <devdoc>
        ///     This method is called when the dialog page should load
        ///     its default settings from the profile XML file.  
        /// </devdoc>
        public virtual void LoadSettingsFromXml(IVsSettingsReader reader) {
            _initializing = true;
            try {
                object automationObject = this.AutomationObject;
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(automationObject, new Attribute[] {DesignerSerializationVisibilityAttribute.Visible});

                foreach(PropertyDescriptor property in properties) {
                    TypeConverter converter = property.Converter;
                    if (converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(typeof(string))) {
                        // read from the xml feed
                        string value = null;
                        object cv = null;
                        try {
                            if ( NativeMethods.Succeeded(reader.ReadSettingString(property.Name, out value)) && (value != null) )
                            {
                                cv = property.Converter.ConvertFromInvariantString(value);
                            }
                        } catch (Exception) {
                            // ReadSettingString throws an exception if the property 
                            // is not found and we also catch ConvertFromInvariantString
                            // exceptions so that we gracefully handle bad vssettings.
                        }
                        //not all values have to be present
                        if (cv != null) { 
                            property.SetValue(automationObject, cv);
                        }
                    }
                }
            }
            finally {
                _initializing = false;    //we have loaded from storage
            }
            HookProperties(true); //hook if this failed during construction.
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.ResetSettings"]' />
        /// <devdoc>Override this method in order to reset your settings to your default values.</devdoc>
        public virtual void ResetSettings() {
        }

        /// <devdoc>
        /// This function hooks property change events so that we automatically serialize
        /// if the value changes outside of UI and loading
        /// </devdoc>
        private void HookProperties(bool hook) {
            if (_propertyChangedHooked != hook)  {
                
                if (_onPropertyChanged == null)
                    _onPropertyChanged = new EventHandler(OnPropertyChanged);

                object automationObject = null;
                try
                {
                    automationObject = this.AutomationObject;
                }
                catch (Exception e)
                {
                    Debug.Fail(e.ToString());  //assert this so we don't ship bad code.
                }

                if (automationObject!= null)  {
                    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(automationObject, new Attribute[] {DesignerSerializationVisibilityAttribute.Visible});

                    foreach(PropertyDescriptor property in properties) {
                        if (hook) 
                            property.AddValueChanged(automationObject, _onPropertyChanged);
                        else
                            property.RemoveValueChanged(automationObject, _onPropertyChanged);
                    }
                    _propertyChangedHooked = hook;
                }
            }
        }

        // Convert an item property value changed event into a list changed event
        private void OnPropertyChanged(object sender, EventArgs e)  {
            if (!_initializing && !_uiActive)
                SaveSettingsToStorage();
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.OnActivate"]' />
        /// <devdoc>
        ///     This method is called when VS wants to activate this
        ///     page.  If true is returned, the page is activated.
        /// </devdoc>
        protected virtual void OnActivate(CancelEventArgs e) {
            _uiActive = true;
        }
        
        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.OnClosed"]' />
        /// <devdoc>
        ///     This event is raised when the page is closed.   
        /// </devdoc>
        protected virtual void OnClosed(EventArgs e) {
            _uiActive = false;
            LoadSettingsFromStorage(); //reload whatever is saved in storage so if someone is accessing this object, it will have the correct values.
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.OnDeactivate"]' />
        /// <devdoc>
        ///     This method is called when VS wants to deatviate this
        ///     page.  If true is returned, the page is deactivated.
        /// </devdoc>
        protected virtual void OnDeactivate(CancelEventArgs e) {
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.OnApply"]' />
        /// <devdoc>
        ///     This method is called when VS wants to save the user's 
        ///     changes then the dialog is dismissed.
        /// </devdoc>
        protected virtual void OnApply(PageApplyEventArgs e) {
            SaveSettingsToStorage();
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.SaveSettingsToStorage"]' />
        /// <devdoc>
        ///     This method does the reverse of LoadSettingsFromStorage.
        /// </devdoc>
        public virtual void SaveSettingsToStorage() {
            Package package = (Package)GetService(typeof(Package));
            Debug.Assert(package != null, "No package service; we cannot load settings");
            if (package != null) {
                using (RegistryKey rootKey = package.UserRegistryRoot) {

                    string path = SettingsRegistryPath;
                    object automationObject = this.AutomationObject;
                    RegistryKey key = rootKey.OpenSubKey(path, true /* writable */);
                    if (key == null) {
                        key = rootKey.CreateSubKey(path);
                    }

                    using (key) {

                        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(automationObject, new Attribute[] { DesignerSerializationVisibilityAttribute.Visible });

                        foreach(PropertyDescriptor property in properties) {
                            TypeConverter converter = property.Converter;
                            if (converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(typeof(string))) {
                                key.SetValue(property.Name, converter.ConvertToInvariantString(property.GetValue(automationObject)));
                            }
                        }
                    }
                }
            }
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.SaveSettingsToXml"]' />
        /// <devdoc>
        ///     This method does the reverse of LoadSettingsFromXml.
        /// </devdoc>
        public virtual void SaveSettingsToXml(IVsSettingsWriter writer) {
            object automationObject = this.AutomationObject;
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(automationObject, new Attribute[] {DesignerSerializationVisibilityAttribute.Visible});
            // [clovett] Sort the names so that tests can depend on the order returned, otherwise the order changes
            // randomly based on some internal hashtable seed.  Besides it makes it easier for the user to
            // read the .vssettings files.
            ArrayList sortedNames = new ArrayList();
            foreach (PropertyDescriptor property in properties) {
                sortedNames.Add(property.Name);
            }
            sortedNames.Sort();
            foreach(string name in sortedNames) {
                PropertyDescriptor property = properties[name];
                TypeConverter converter = property.Converter;
                if (converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(typeof(string))) {
                    NativeMethods.ThrowOnFailure(
                        writer.WriteSettingString(property.Name, converter.ConvertToInvariantString(property.GetValue(automationObject)))
                    );
                }
            }
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.SettingsRegistryPath"]' />
        /// <devdoc>
        /// This is where the settings are stored under [UserRegistryRoot]\DialogPage, the default
        /// is the full type name of your AutomationObject.
        /// </devdoc>
        protected string SettingsRegistryPath {
            get {
                if (this._settingsPath == null) {
                    this._settingsPath = "DialogPage\\" + this.AutomationObject.GetType().FullName;
                }
                return this._settingsPath;
            }
            set {
                this._settingsPath = value;
            }
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.IWin32Window.Handle"]/*' />
        /// <internalonly/>
        /// <devdoc>
        /// IWin32Window implementation.  This just delegates to the Window property.
        /// </devdoc>
        IntPtr IWin32Window.Handle {
            get {

                if (_window == null) {
                    _window = Window;
                    if (_window is IComponent) {
                        if (_container == null) {
                            _container = new DialogContainer(Site);
                        }
                        _container.Add((IComponent)_window);
                    }
                    if (_subclass == null) {
                        _subclass = new DialogSubclass(this);
                    }
                }

                if (_subclass.Handle != _window.Handle) {
                    _subclass.AssignHandle(_window.Handle);
                }

                return _window.Handle;
            }
        }

        internal void ResetContainer() {
            if (_container != null && _window is IComponent) {
                // This resets the AmbientProperties.
                _container._ambientProperties = null;
                _container.Remove((IComponent)_window);                
                _container.Add((IComponent)_window);
            }
        }

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.ApplyKind"]/*' />
        /// <devdoc>
        /// Apply behavior.  Allows the OnApply event to be canceled with optional navigation instructions.
        /// </devdoc>
        public enum ApplyKind { 
            /// <summary>
            /// Apply - Allows the changes to be applied
            /// </summary>
            Apply = 0, 

            /// <summary>
            /// CancelNavigate - Cancels the apply event and navigates to the page cancelling the event.
            /// </summary>
            Cancel = 1, 
            
            /// <summary>
            /// CancelNoNavigate - Cancels the apply event and returns the active page, not the page cancelling the event.
            /// </summary>
            CancelNoNavigate = 2 
        };

        /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.PageApplyEventArgs"]/*' />
        /// <devdoc>
        /// Event arguments to allow the OnApply method to indicate how to handle the apply event.
        /// </devdoc>
        protected class PageApplyEventArgs : EventArgs
        {
            private ApplyKind _apply = ApplyKind.Apply;

            /// <include file='doc\DialogPage.uex' path='docs/doc[@for="DialogPage.AutomationObject.ApplyBehavior"]' />
            public ApplyKind ApplyBehavior
            {
                get
                {
                    return _apply;
                }
                set
                {
                    _apply = value;
                }
            }
        }

        /// <devdoc>
        ///     This class derives from container to provide a service provider
        ///     connection to the dialog page.
        /// </devdoc>
        private sealed class DialogContainer : Container {

            private IServiceProvider _provider;
            internal AmbientProperties _ambientProperties;

            /// <devdoc>
            ///     Creates a new container using the given service provider.
            /// </devdoc>
            public DialogContainer(IServiceProvider provider) {
                _provider = provider;
            }

            /// <devdoc>
            ///     Override to GetService so we can route requests
            ///     to the package's service provider.
            /// </devdoc>
            protected override object GetService(Type serviceType) {
                if (serviceType == null) {
                    throw new ArgumentNullException("serviceType");
                }
                if (serviceType == typeof(AmbientProperties)) {
                    if (_ambientProperties == null) {
                        IUIService uis = GetService(typeof(IUIService)) as IUIService;
                        _ambientProperties = new AmbientProperties();
                        _ambientProperties.Font = (Font)uis.Styles["DialogFont"];
                    }
                    return _ambientProperties;
                }
                if (_provider != null) {
                    object service = _provider.GetService(serviceType);
                    if (service != null) {
                        return service;
                    }
                }
                return base.GetService(serviceType);
            }
        }

        /// <devdoc>
        ///     This class derives from NativeWindow to provide a hook
        ///     into the window handle.  We use this hook so we can
        ///     respond to property sheet window messages that VS
        ///     will send us.
        /// </devdoc>
        private sealed class DialogSubclass : NativeWindow {

            private DialogPage _page;
            private bool       _closeCalled;

            /// <devdoc>
            ///     Create a new DialogSubclass
            /// </devdoc>
            internal DialogSubclass(DialogPage page) {
                _page = page;
                _closeCalled = false;
            }

            /// <devdoc>
            ///     Override for WndProc to handle our PSP messages
            /// </devdoc>
            protected override void WndProc(ref Message m) {

                CancelEventArgs ce;

                switch (m.Msg) { 
                    case NativeMethods.WM_NOTIFY:
                        NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.NMHDR));
                        switch (nmhdr.code) {
                            case NativeMethods.PSN_RESET:
                                _closeCalled = true;
                                _page.OnClosed(EventArgs.Empty);
                                return;
                            case NativeMethods.PSN_APPLY:
                                PageApplyEventArgs pae = new PageApplyEventArgs(); 
                                _page.OnApply(pae);
                                switch (pae.ApplyBehavior)
                                {    
                                    case ApplyKind.Cancel:
                                        m.Result = (IntPtr)NativeMethods.PSNRET_INVALID;
                                        break;

                                    case ApplyKind.CancelNoNavigate:
                                        m.Result = (IntPtr)NativeMethods.PSNRET_INVALID_NOCHANGEPAGE;
                                        break;

                                    case ApplyKind.Apply:
                                    default:
                                        m.Result = IntPtr.Zero;
                                        break;
                                }
                                UnsafeNativeMethods.SetWindowLong(m.HWnd, NativeMethods.DWL_MSGRESULT, m.Result);
                                return;
                            case NativeMethods.PSN_KILLACTIVE:
                                ce = new CancelEventArgs();
                                _page.OnDeactivate(ce);
                                m.Result = (IntPtr)(ce.Cancel ? 1 : 0);
                                UnsafeNativeMethods.SetWindowLong(m.HWnd, NativeMethods.DWL_MSGRESULT, m.Result);
                                return;
                            case NativeMethods.PSN_SETACTIVE:
                                _closeCalled = false;
                                ce = new CancelEventArgs();
                                _page.OnActivate(ce);
                                m.Result = (IntPtr)(ce.Cancel ? -1 : 0);
                                UnsafeNativeMethods.SetWindowLong(m.HWnd, NativeMethods.DWL_MSGRESULT, m.Result);
                                return;
                        }
                        break;
                    case NativeMethods.WM_DESTROY:

                        // we can't tell the difference between OK and Apply (see above), so
                        // if we get a destroy and close hasn't been called, make sure we call it
                        //
                        if (!_closeCalled && _page != null) {
                            _page.OnClosed(EventArgs.Empty);
                        }
                        break;
                }

                base.WndProc(ref m);
            }
        }
    }
}

www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.