The Labs \ Source Viewer \ SSCLI \ System.ComponentModel.Design \ WrappedPropertyDescriptor

  1. //------------------------------------------------------------------------------
  2. // <copyright file="DesignerOptionService.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.ComponentModel.Design
  16. {
  17.    
  18.     using System;
  19.     using System.Collections;
  20.     using System.ComponentModel;
  21.     using System.Diagnostics;
  22.     using System.Diagnostics.CodeAnalysis;
  23.     using System.Globalization;
  24.     using System.Security.Permissions;
  25.    
  26.     /// <devdoc>
  27.     /// Provides access to get and set option values for a designer.
  28.     /// </devdoc>
  29.     [HostProtection(SharedState = true)]
  30.     public abstract class DesignerOptionService : IDesignerOptionService
  31.     {
  32.        
  33.         private DesignerOptionCollection _options;
  34.        
  35.         /// <devdoc>
  36.         /// Returns the options collection for this service. There is
  37.         /// always a global options collection that contains child collections.
  38.         /// </devdoc>
  39.         public DesignerOptionCollection Options {
  40.             get {
  41.                 if (_options == null) {
  42.                     _options = new DesignerOptionCollection(this, null, string.Empty, null);
  43.                 }
  44.                 return _options;
  45.             }
  46.         }
  47.        
  48.         /// <devdoc>
  49.         /// Creates a new DesignerOptionCollection with the given name, and adds it to
  50.         /// the given parent. The "value" parameter specifies an object whose public
  51.         /// properties will be used in the Propeties collection of the option collection.
  52.         /// The value parameter can be null if this options collection does not offer
  53.         /// any properties. Properties will be wrapped in such a way that passing
  54.         /// anything into the component parameter of the property descriptor will be
  55.         /// ignored and the value object will be substituted.
  56.         /// </devdoc>
  57.         protected DesignerOptionCollection CreateOptionCollection(DesignerOptionCollection parent, string name, object value)
  58.         {
  59.             if (parent == null) {
  60.                 throw new ArgumentNullException("parent");
  61.             }
  62.            
  63.             if (name == null) {
  64.                 throw new ArgumentNullException("name");
  65.             }
  66.            
  67.             if (name.Length == 0) {
  68.                 throw new ArgumentException(SR.GetString(SR.InvalidArgument, name.Length.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)), "name.Length");
  69.             }
  70.            
  71.             return new DesignerOptionCollection(this, parent, name, value);
  72.         }
  73.        
  74.         /// <devdoc>
  75.         /// Retrieves the property descriptor for the given page / value name. Returns
  76.         /// null if the property couldn't be found.
  77.         /// </devdoc>
  78.         private PropertyDescriptor GetOptionProperty(string pageName, string valueName)
  79.         {
  80.             if (pageName == null) {
  81.                 throw new ArgumentNullException("pageName");
  82.             }
  83.            
  84.             if (valueName == null) {
  85.                 throw new ArgumentNullException("valueName");
  86.             }
  87.            
  88.             string[] optionNames = pageName.Split(new char[] {'\\'});
  89.            
  90.             DesignerOptionCollection options = Options;
  91.             foreach (string optionName in optionNames) {
  92.                 options = options[optionName];
  93.                 if (options == null) {
  94.                     return null;
  95.                 }
  96.             }
  97.            
  98.             return options.Properties[valueName];
  99.         }
  100.        
  101.         /// <devdoc>
  102.         /// This method is called on demand the first time a user asks for child
  103.         /// options or properties of an options collection.
  104.         /// </devdoc>
  105.         protected virtual void PopulateOptionCollection(DesignerOptionCollection options)
  106.         {
  107.         }
  108.        
  109.         /// <devdoc>
  110.         /// This method must be implemented to show the options dialog UI for the given object.
  111.         /// </devdoc>
  112.         protected virtual bool ShowDialog(DesignerOptionCollection options, object optionObject)
  113.         {
  114.             return false;
  115.         }
  116.        
  117.        
  118.         /// <internalonly/>
  119.         /// <devdoc>
  120.         /// Gets the value of an option defined in this package.
  121.         /// </devdoc>
  122.         object IDesignerOptionService.GetOptionValue(string pageName, string valueName)
  123.         {
  124.             PropertyDescriptor optionProp = GetOptionProperty(pageName, valueName);
  125.             if (optionProp != null) {
  126.                 return optionProp.GetValue(null);
  127.             }
  128.             return null;
  129.         }
  130.        
  131.         /// <internalonly/>
  132.         /// <devdoc>
  133.         /// Sets the value of an option defined in this package.
  134.         /// </devdoc>
  135.         void IDesignerOptionService.SetOptionValue(string pageName, string valueName, object value)
  136.         {
  137.             PropertyDescriptor optionProp = GetOptionProperty(pageName, valueName);
  138.             if (optionProp != null) {
  139.                 optionProp.SetValue(null, value);
  140.             }
  141.         }
  142.        
  143.         /// <devdoc>
  144.         /// The DesignerOptionCollection class is a collection that contains
  145.         /// other DesignerOptionCollection objects. This forms a tree of options,
  146.         /// with each branch of the tree having a name and a possible collection of
  147.         /// properties. Each parent branch of the tree contains a union of the
  148.         /// properties if all the branch's children.
  149.         /// </devdoc>
  150.         [TypeConverter(typeof(DesignerOptionConverter))]
  151.         [Editor("", "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing)]
  152.         public sealed class DesignerOptionCollection : IList
  153.         {
  154.            
  155.             private DesignerOptionService _service;
  156.             private DesignerOptionCollection _parent;
  157.             private string _name;
  158.             private object _value;
  159.             private ArrayList _children;
  160.             private PropertyDescriptorCollection _properties;
  161.            
  162.             /// <devdoc>
  163.             /// Creates a new DesignerOptionCollection.
  164.             /// </devdoc>
  165.             internal DesignerOptionCollection(DesignerOptionService service, DesignerOptionCollection parent, string name, object value)
  166.             {
  167.                 _service = service;
  168.                 _parent = parent;
  169.                 _name = name;
  170.                 _value = value;
  171.                
  172.                 if (_parent != null) {
  173.                     if (_parent._children == null) {
  174.                         _parent._children = new ArrayList(1);
  175.                     }
  176.                     _parent._children.Add(this);
  177.                 }
  178.             }
  179.            
  180.             /// <devdoc>
  181.             /// The count of child options collections this collection contains.
  182.             /// </devdoc>
  183.             public int Count {
  184.                 get {
  185.                     EnsurePopulated();
  186.                     return _children.Count;
  187.                 }
  188.             }
  189.            
  190.             /// <devdoc>
  191.             /// The name of this collection. Names are programmatic names and are not
  192.             /// localized. A name search is case insensitive.
  193.             /// </devdoc>
  194.             public string Name {
  195.                 get { return _name; }
  196.             }
  197.            
  198.             /// <devdoc>
  199.             /// Returns the parent collection object, or null if there is no parent.
  200.             /// </devdoc>
  201.             public DesignerOptionCollection Parent {
  202.                 get { return _parent; }
  203.             }
  204.            
  205.             /// <devdoc>
  206.             /// The collection of properties that this OptionCollection, along with all of
  207.             /// its children, offers. PropertyDescriptors are taken directly from the
  208.             /// value passed to CreateObjectCollection and wrapped in an additional property
  209.             /// descriptor that hides the value object from the user. This means that any
  210.             /// value may be passed into the "component" parameter of the various
  211.             /// PropertyDescriptor methods. The value is ignored and is replaced with
  212.             /// the correct value internally.
  213.             /// </devdoc>
  214.             public PropertyDescriptorCollection Properties {
  215.                 get {
  216.                     if (_properties == null) {
  217.                         ArrayList propList;
  218.                        
  219.                         if (_value != null) {
  220.                             PropertyDescriptorCollection props = TypeDescriptor.GetProperties(_value);
  221.                             propList = new ArrayList(props.Count);
  222.                             foreach (PropertyDescriptor prop in props) {
  223.                                 propList.Add(new WrappedPropertyDescriptor(prop, _value));
  224.                             }
  225.                         }
  226.                         else {
  227.                             propList = new ArrayList(1);
  228.                         }
  229.                        
  230.                         EnsurePopulated();
  231.                         foreach (DesignerOptionCollection child in _children) {
  232.                             propList.AddRange(child.Properties);
  233.                         }
  234.                        
  235.                         PropertyDescriptor[] propArray = (PropertyDescriptor[])propList.ToArray(typeof(PropertyDescriptor));
  236.                         _properties = new PropertyDescriptorCollection(propArray, true);
  237.                     }
  238.                    
  239.                     return _properties;
  240.                 }
  241.             }
  242.            
  243.             /// <devdoc>
  244.             /// Retrieves the child collection at the given index.
  245.             /// </devdoc>
  246.             public DesignerOptionCollection this[int index]
  247.             {
  248.                 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
  249.                 get {
  250.                     EnsurePopulated();
  251.                     if (index < 0 || index >= _children.Count) {
  252.                         throw new IndexOutOfRangeException("index");
  253.                     }
  254.                     return (DesignerOptionCollection)_children[index];
  255.                 }
  256.             }
  257.            
  258.             /// <devdoc>
  259.             /// Retrieves the child collection at the given name. The name search is case
  260.             /// insensitive.
  261.             /// </devdoc>
  262.             public DesignerOptionCollection this[string name]
  263.             {
  264.                 get {
  265.                     EnsurePopulated();
  266.                     foreach (DesignerOptionCollection child in _children) {
  267.                         if (string.Compare(child.Name, name, true, CultureInfo.InvariantCulture) == 0) {
  268.                             return child;
  269.                         }
  270.                     }
  271.                     return null;
  272.                 }
  273.             }
  274.            
  275.             /// <devdoc>
  276.             /// Copies this collection to an array.
  277.             /// </devdoc>
  278.             public void CopyTo(Array array, int index)
  279.             {
  280.                 EnsurePopulated();
  281.                 _children.CopyTo(array, index);
  282.             }
  283.            
  284.             /// <devdoc>
  285.             /// Called before any access to our collection to force it to become populated.
  286.             /// </devdoc>
  287.             private void EnsurePopulated()
  288.             {
  289.                 if (_children == null) {
  290.                     _service.PopulateOptionCollection(this);
  291.                     if (_children == null) {
  292.                         _children = new ArrayList(1);
  293.                     }
  294.                 }
  295.             }
  296.            
  297.             /// <devdoc>
  298.             /// Returns an enumerator that can be used to iterate this collection.
  299.             /// </devdoc>
  300.             public IEnumerator GetEnumerator()
  301.             {
  302.                 EnsurePopulated();
  303.                 return _children.GetEnumerator();
  304.             }
  305.            
  306.             /// <devdoc>
  307.             /// Returns the numerical index of the given value.
  308.             /// </devdoc>
  309.             public int IndexOf(DesignerOptionCollection value)
  310.             {
  311.                 EnsurePopulated();
  312.                 return _children.IndexOf(value);
  313.             }
  314.            
  315.             /// <devdoc>
  316.             /// Locates the value object to use for getting or setting a property.
  317.             /// </devdoc>
  318.             private static object RecurseFindValue(DesignerOptionCollection options)
  319.             {
  320.                 if (options._value != null) {
  321.                     return options._value;
  322.                 }
  323.                
  324.                 foreach (DesignerOptionCollection child in options) {
  325.                     object value = RecurseFindValue(child);
  326.                     if (value != null) {
  327.                         return value;
  328.                     }
  329.                 }
  330.                
  331.                 return null;
  332.             }
  333.            
  334.             /// <devdoc>
  335.             /// Displays a dialog-based user interface that allows the user to
  336.             /// configure the various options.
  337.             /// </devdoc>
  338.             public bool ShowDialog()
  339.             {
  340.                 object value = RecurseFindValue(this);
  341.                
  342.                 if (value == null) {
  343.                     return false;
  344.                 }
  345.                
  346.                 return _service.ShowDialog(this, value);
  347.             }
  348.            
  349.             /// <internalonly/>
  350.             /// <devdoc>
  351.             /// Private ICollection implementation.
  352.             /// </devdoc>
  353.             bool ICollection.IsSynchronized {
  354.                 get { return false; }
  355.             }
  356.            
  357.             /// <internalonly/>
  358.             /// <devdoc>
  359.             /// Private ICollection implementation.
  360.             /// </devdoc>
  361.             object ICollection.SyncRoot {
  362.                 get { return this; }
  363.             }
  364.            
  365.             /// <internalonly/>
  366.             /// <devdoc>
  367.             /// Private IList implementation.
  368.             /// </devdoc>
  369.             bool IList.IsFixedSize {
  370.                 get { return true; }
  371.             }
  372.            
  373.             /// <internalonly/>
  374.             /// <devdoc>
  375.             /// Private IList implementation.
  376.             /// </devdoc>
  377.             bool IList.IsReadOnly {
  378.                 get { return true; }
  379.             }
  380.            
  381.             /// <internalonly/>
  382.             /// <devdoc>
  383.             /// Private IList implementation.
  384.             /// </devdoc>
  385.             object IList.this[int index]
  386.             {
  387.                 get { return this[index]; }
  388.                 set {
  389.                     throw new NotSupportedException();
  390.                 }
  391.             }
  392.            
  393.             /// <internalonly/>
  394.             /// <devdoc>
  395.             /// Private IList implementation.
  396.             /// </devdoc>
  397.             int IList.Add(object value)
  398.             {
  399.                 throw new NotSupportedException();
  400.             }
  401.            
  402.             /// <internalonly/>
  403.             /// <devdoc>
  404.             /// Private IList implementation.
  405.             /// </devdoc>
  406.             void IList.Clear()
  407.             {
  408.                 throw new NotSupportedException();
  409.             }
  410.            
  411.             /// <internalonly/>
  412.             /// <devdoc>
  413.             /// Private IList implementation.
  414.             /// </devdoc>
  415.             bool IList.Contains(object value)
  416.             {
  417.                 EnsurePopulated();
  418.                 return _children.Contains(value);
  419.             }
  420.            
  421.             /// <internalonly/>
  422.             /// <devdoc>
  423.             /// Private IList implementation.
  424.             /// </devdoc>
  425.             int IList.IndexOf(object value)
  426.             {
  427.                 EnsurePopulated();
  428.                 return _children.IndexOf(value);
  429.             }
  430.            
  431.             /// <internalonly/>
  432.             /// <devdoc>
  433.             /// Private IList implementation.
  434.             /// </devdoc>
  435.             void IList.Insert(int index, object value)
  436.             {
  437.                 throw new NotSupportedException();
  438.             }
  439.            
  440.             /// <internalonly/>
  441.             /// <devdoc>
  442.             /// Private IList implementation.
  443.             /// </devdoc>
  444.             void IList.Remove(object value)
  445.             {
  446.                 throw new NotSupportedException();
  447.             }
  448.            
  449.             /// <internalonly/>
  450.             /// <devdoc>
  451.             /// Private IList implementation.
  452.             /// </devdoc>
  453.             void IList.RemoveAt(int index)
  454.             {
  455.                 throw new NotSupportedException();
  456.             }
  457.            
  458.             /// <devdoc>
  459.             /// A special property descriptor that forwards onto a base
  460.             /// property descriptor but allows any value to be used for the
  461.             /// "component" parameter.
  462.             /// </devdoc>
  463.             private sealed class WrappedPropertyDescriptor : PropertyDescriptor
  464.             {
  465.                
  466.                 private object target;
  467.                 private PropertyDescriptor property;
  468.                
  469.                 internal WrappedPropertyDescriptor(PropertyDescriptor property, object target) : base(property.Name, null)
  470.                 {
  471.                     this.property = property;
  472.                     this.target = target;
  473.                 }
  474.                
  475.                 public override AttributeCollection Attributes {
  476.                     get { return property.Attributes; }
  477.                 }
  478.                
  479.                 public override Type ComponentType {
  480.                     get { return property.ComponentType; }
  481.                 }
  482.                
  483.                 public override bool IsReadOnly {
  484.                     get { return property.IsReadOnly; }
  485.                 }
  486.                
  487.                 public override Type PropertyType {
  488.                     get { return property.PropertyType; }
  489.                 }
  490.                
  491.                 public override bool CanResetValue(object component)
  492.                 {
  493.                     return property.CanResetValue(target);
  494.                 }
  495.                
  496.                 public override object GetValue(object component)
  497.                 {
  498.                     return property.GetValue(target);
  499.                 }
  500.                
  501.                 public override void ResetValue(object component)
  502.                 {
  503.                     property.ResetValue(target);
  504.                 }
  505.                
  506.                 public override void SetValue(object component, object value)
  507.                 {
  508.                     property.SetValue(target, value);
  509.                 }
  510.                
  511.                 public override bool ShouldSerializeValue(object component)
  512.                 {
  513.                     return property.ShouldSerializeValue(target);
  514.                 }
  515.             }
  516.         }
  517.        
  518.         /// <devdoc>
  519.         /// The type converter for the designer option collection.
  520.         /// </devdoc>
  521.         internal sealed class DesignerOptionConverter : TypeConverter
  522.         {
  523.            
  524.             public override bool GetPropertiesSupported(ITypeDescriptorContext cxt)
  525.             {
  526.                 return true;
  527.             }
  528.            
  529.             public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext cxt, object value, Attribute[] attributes)
  530.             {
  531.                 PropertyDescriptorCollection props = new PropertyDescriptorCollection(null);
  532.                 DesignerOptionCollection options = value as DesignerOptionCollection;
  533.                 if (options == null) {
  534.                     return props;
  535.                 }
  536.                
  537.                 foreach (DesignerOptionCollection option in options) {
  538.                     props.Add(new OptionPropertyDescriptor(option));
  539.                 }
  540.                
  541.                 foreach (PropertyDescriptor p in options.Properties) {
  542.                     props.Add(p);
  543.                 }
  544.                 return props;
  545.             }
  546.            
  547.             public override object ConvertTo(ITypeDescriptorContext cxt, CultureInfo culture, object value, Type destinationType)
  548.             {
  549.                 if (destinationType == typeof(string)) {
  550.                     return SR.GetString(SR.CollectionConverterText);
  551.                 }
  552.                 return base.ConvertTo(cxt, culture, value, destinationType);
  553.             }
  554.            
  555.             private class OptionPropertyDescriptor : PropertyDescriptor
  556.             {
  557.                
  558.                 private DesignerOptionCollection _option;
  559.                
  560.                 internal OptionPropertyDescriptor(DesignerOptionCollection option) : base(option.Name, null)
  561.                 {
  562.                     _option = option;
  563.                 }
  564.                
  565.                 public override Type ComponentType {
  566.                     get { return _option.GetType(); }
  567.                 }
  568.                
  569.                 public override bool IsReadOnly {
  570.                     get { return true; }
  571.                 }
  572.                
  573.                 public override Type PropertyType {
  574.                     get { return _option.GetType(); }
  575.                 }
  576.                
  577.                 public override bool CanResetValue(object component)
  578.                 {
  579.                     return false;
  580.                 }
  581.                
  582.                 public override object GetValue(object component)
  583.                 {
  584.                     return _option;
  585.                 }
  586.                
  587.                 public override void ResetValue(object component)
  588.                 {
  589.                 }
  590.                
  591.                 public override void SetValue(object component, object value)
  592.                 {
  593.                 }
  594.                
  595.                 public override bool ShouldSerializeValue(object component)
  596.                 {
  597.                     return false;
  598.                 }
  599.             }
  600.         }
  601.     }
  602. }

Developer Fusion