public MyPropertyDescriptor(
				PropertyManager enclosingInstance,
				string name,
				string value,
				bool readOnly,
				Attribute[] attrs) :
				base(name, attrs)
			{
				_enclosingInstance = enclosingInstance;
				_readOnly = readOnly;
				_value = value;			
			}
        private void PropertyGridSelectObject(object obj)
        {
            // show properties of selected object (if any)
            if (obj != null)
            {
                // first look into cache if propertyManager wasn't already constructed for this object,
                // if not, construct new one
                if (_propertyManagerCache.Contains(obj))
                {
                    propertyGrid.SelectedObject = _propertyManagerCache[obj];
                }
                else
                {
                    HydroNumerics.OpenMI.Gui.Controls.PropertyManager manager = HydroNumerics.OpenMI.Gui.Controls.PropertyManager.ConstructPropertyManager(obj, false);
                    propertyGrid.SelectedObject = manager;

                    // store propertyManager of actually showing properties into cache,
                    // so next time user selects same object the properties won't be newly constructed.
                    // It's most useful for making changes of DataOperation arguments persistent
                    // between selection of other items
                    _propertyManagerCache.Add(obj, manager);
                }

                // Modify text in properties group-box
                if (obj is IQuantity)
                {
                    this.groupBoxProperties.Text = " Quantity properties";
                }
                else if (obj is IElementSet)
                {
                    groupBoxProperties.Text = " ElementSet properties";
                }
                else if (obj is IDataOperation)
                {
                    groupBoxProperties.Text = " DataOperation properties";
                }
                else
                {
                    Debug.Assert(false);
                    groupBoxProperties.Text = " Properties";
                }
            }
            else
            {
                // no object is selected, show no properties
                propertyGrid.SelectedObject = null;
                groupBoxProperties.Text     = " Properties";
            }
        }
		/// <summary>
		/// Constructs a new <see cref="PropertyManager">PropertyManager</see> from <c>object</c>
		/// of known type.
		/// </summary>
		/// <param name="obj">Object of known type.</param>
		/// <param name="allReadOnly">If true, all properties are readonly.</param>
		/// <returns>Returns new <see cref="PropertyManager">PropertyManager</see>
		/// or <c>null</c> if object's type isn't known.</returns>
		/// <remarks>A this time this method knowns following types:
		/// <list>
		/// <item><see cref="IQuantity">IQuantity</see></item>
		/// <item><see cref="IElementSet">IElementSet</see></item>
		/// <item><see cref="IDataOperation">IDataOperation</see></item>
		/// <item><see cref="ILinkableComponent">ILinkableComponent</see></item>
		/// </list>
		/// Method saves <c>obj</c> parameter to <see cref="Tag">Tag</see> property, but you can
		/// use it for any purpose.
		/// </remarks>
		public static PropertyManager ConstructPropertyManager( object obj, bool allReadOnly )
		{
			PropertyManager prop = null;

			if( obj is IQuantity )
			{
				IQuantity quantity = (IQuantity)obj; 
				prop = new PropertyManager();

				// General
				prop.SetProperty("Description", quantity.Description,          true, "Description of this Quantity.",  "General");
				prop.SetProperty("ID",          quantity.ID,                   true, "ID of this Quantity.",           "General");
				prop.SetProperty("ValueType",   quantity.ValueType.ToString(), true, "Type of this Quantity's value.", "General" );

				// Dimensions
				prop.SetProperty("AmountOfSubstance", quantity.Dimension.GetPower(DimensionBase.AmountOfSubstance).ToString(), true, "The amount of substance in mole.",   "Dimensions");
				prop.SetProperty("Currency",          quantity.Dimension.GetPower(DimensionBase.Currency).ToString(),          true, "Currency in Euro.",              "Dimensions");
				prop.SetProperty("ElectricCurrent",   quantity.Dimension.GetPower(DimensionBase.ElectricCurrent).ToString(),   true, "Electric current in ampere.",    "Dimensions");
				prop.SetProperty("Length",            quantity.Dimension.GetPower(DimensionBase.Length).ToString(),            true, "Length in meter.",               "Dimensions");
				prop.SetProperty("LuminousIntensity", quantity.Dimension.GetPower(DimensionBase.LuminousIntensity).ToString(), true, "Luminous intensity in candela.", "Dimensions");
				prop.SetProperty("Mass",              quantity.Dimension.GetPower(DimensionBase.Mass).ToString(),              true, "Mass in kilogram.",              "Dimensions");
				prop.SetProperty("Temperature",       quantity.Dimension.GetPower(DimensionBase.Temperature).ToString(),       true, "Temperature in kelvin.",         "Dimensions");
				prop.SetProperty("Time",              quantity.Dimension.GetPower(DimensionBase.Time).ToString(),              true, "Time in second.",                "Dimensions");

				// Unit
				prop.SetProperty("ConversionFactorToSI", quantity.Unit.ConversionFactorToSI.ToString(), true, "Multiplicative coefficient used to convert this quantity to SI (SiUnit = Unit*ConversionFactorToSI + OffSetToSI).", "Unit");
				prop.SetProperty("OffSetToSI",           quantity.Unit.OffSetToSI.ToString(),           true, "Additive coefficient used to convert this quantity to SI (SiUnit = Unit*ConversionFactorToSI + OffSetToSI).",       "Unit");
				prop.SetProperty("UnitDescription",      quantity.Unit.Description,                     true, "Description of this unit.",                                                                                         "Unit");
				prop.SetProperty("UnitID",               quantity.Unit.ID,                              true, "ID of this unit.",                                                                                                  "Unit");
			}
			else if( obj is IElementSet )
			{
				IElementSet elementSet = (IElementSet)obj;
				prop = new PropertyManager();

				// General
				prop.SetProperty("ID",                 elementSet.ID,                      true, "ID of this ElementSet",                    "General" );
				prop.SetProperty("Version",            elementSet.Version.ToString(),      true, "Version of this ElementSet.",              "General" );
			  string spatialReference = string.Empty;
        if (elementSet.SpatialReference != null)
          spatialReference = elementSet.SpatialReference.ID;
        prop.SetProperty("SpatialReferenceID", spatialReference, true, "ID of this ElementSet's SpatialReference", "General");
				prop.SetProperty("Description",        elementSet.Description,             true, "Description of this ElementSet.",          "General" );
				prop.SetProperty("ElementCount",       elementSet.ElementCount.ToString(), true, "Count of elements of this ElementSet.",    "General" );
				prop.SetProperty("ElementType",        elementSet.ElementType.ToString(),  true, "Type of elements in this ElementSet.",     "General" );
			}
			else if( obj is IDataOperation )
			{
				IDataOperation dataOperation = (IDataOperation)obj;
				prop = new PropertyManager();

				string DataOperationID = "DataOperationID";

				// small trick to avoid that some argument's name is same as DataOperationID.
				// it's not quite pure, but it works:-)				
				bool conflict;
				do
				{
					conflict = false;
					for( int i=0; i<dataOperation.ArgumentCount; i++ )
						if( dataOperation.GetArgument(i).Key == DataOperationID )
						{
							DataOperationID += " ";
							conflict = true;
							break;
						}
				}
				while( conflict );	

				// General
				prop.SetProperty(DataOperationID, dataOperation.ID, true, "ID of this DataOperation", "General");
					
				// Arguments
				for( int i=0; i<dataOperation.ArgumentCount; i++ )
				{
					IArgument arg = dataOperation.GetArgument(i);
					prop.SetProperty(arg.Key, arg.Value, arg.ReadOnly || allReadOnly, arg.Description, "Arguments");
				}		
			}
			else if( obj is ILinkableComponent )
			{
				ILinkableComponent linkableComponent = (ILinkableComponent)obj;
				prop = new PropertyManager();

			  DateTime timeHorizonStart = DateTime.MinValue;
			  DateTime timeHorizonEnd = DateTime.MaxValue;
        if (linkableComponent.TimeHorizon != null)
        {
          timeHorizonStart = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.TimeHorizon.Start.ModifiedJulianDay);
          timeHorizonEnd = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.TimeHorizon.End.ModifiedJulianDay);
        }

			  DateTime earliestInputTime = DateTime.MinValue;
        if (linkableComponent.EarliestInputTime != null)
			    earliestInputTime = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.EarliestInputTime.ModifiedJulianDay);
				
				// General
				prop.SetProperty("ComponentID",             linkableComponent.ComponentID,                        true, "ID the component.",                                                        "General" );
				prop.SetProperty("ComponentDescription",    linkableComponent.ComponentDescription,               true, "Description of this component.",                                           "General" );
				prop.SetProperty("InputExchangeItemCount",  linkableComponent.InputExchangeItemCount.ToString(),  true, "Number of input exchange items.",                                          "General" );
				prop.SetProperty("OutputExchangeItemCount", linkableComponent.OutputExchangeItemCount.ToString(), true, "Number of output exchange items.",                                         "General" );
				prop.SetProperty("ModelID",                 linkableComponent.ModelID,                            true, "ID of the model (model=component+data).",                                  "General" );
				prop.SetProperty("ModelDescription",        linkableComponent.ModelDescription,                   true, "Description of the model.",                                                "General" );
				prop.SetProperty("TimeHorizonStart",        timeHorizonStart.ToString(),                          true, "Start of component's timehorizon.",                                        "General" );
				prop.SetProperty("TimeHorizonEnd",          timeHorizonEnd.ToString(),                            true, "End of component's timehorizon.",                                          "General" );
				prop.SetProperty("ValidationMessage",       linkableComponent.Validate(),                         true, "Validation string generated by component. No error ocured if it's empty.", "General" );
				prop.SetProperty("EarliestInputTime",       earliestInputTime.ToString(),                         true, "Earliest time for which component needs next input.",                      "General" );

				string implementsIManageState = obj is IManageState ? "yes" : "no";
				prop.SetProperty("ImplementsIManageState",  implementsIManageState,                               true, "Describes whether model implements IManageState interface.",               "General" );
			}

			if( prop!=null )
				prop.Tag = obj;

			return( prop );
		}
        /// <summary>
        /// Constructs a new <see cref="PropertyManager">PropertyManager</see> from <c>object</c>
        /// of known type.
        /// </summary>
        /// <param name="obj">Object of known type.</param>
        /// <param name="allReadOnly">If true, all properties are readonly.</param>
        /// <returns>Returns new <see cref="PropertyManager">PropertyManager</see>
        /// or <c>null</c> if object's type isn't known.</returns>
        /// <remarks>A this time this method knowns following types:
        /// <list>
        /// <item><see cref="IQuantity">IQuantity</see></item>
        /// <item><see cref="IElementSet">IElementSet</see></item>
        /// <item><see cref="IDataOperation">IDataOperation</see></item>
        /// <item><see cref="ILinkableComponent">ILinkableComponent</see></item>
        /// </list>
        /// Method saves <c>obj</c> parameter to <see cref="Tag">Tag</see> property, but you can
        /// use it for any purpose.
        /// </remarks>
        public static PropertyManager ConstructPropertyManager(object obj, bool allReadOnly)
        {
            PropertyManager prop = null;

            if (obj is IQuantity)
            {
                IQuantity quantity = (IQuantity)obj;
                prop = new PropertyManager();

                // General
                prop.SetProperty("Description", quantity.Description, true, "Description of this Quantity.", "General");
                prop.SetProperty("ID", quantity.ID, true, "ID of this Quantity.", "General");
                prop.SetProperty("ValueType", quantity.ValueType.ToString(), true, "Type of this Quantity's value.", "General");

                // Dimensions
                prop.SetProperty("AmountOfSubstance", quantity.Dimension.GetPower(DimensionBase.AmountOfSubstance).ToString(), true, "The amount of substance in mole.", "Dimensions");
                prop.SetProperty("Currency", quantity.Dimension.GetPower(DimensionBase.Currency).ToString(), true, "Currency in Euro.", "Dimensions");
                prop.SetProperty("ElectricCurrent", quantity.Dimension.GetPower(DimensionBase.ElectricCurrent).ToString(), true, "Electric current in ampere.", "Dimensions");
                prop.SetProperty("Length", quantity.Dimension.GetPower(DimensionBase.Length).ToString(), true, "Length in meter.", "Dimensions");
                prop.SetProperty("LuminousIntensity", quantity.Dimension.GetPower(DimensionBase.LuminousIntensity).ToString(), true, "Luminous intensity in candela.", "Dimensions");
                prop.SetProperty("Mass", quantity.Dimension.GetPower(DimensionBase.Mass).ToString(), true, "Mass in kilogram.", "Dimensions");
                prop.SetProperty("Temperature", quantity.Dimension.GetPower(DimensionBase.Temperature).ToString(), true, "Temperature in kelvin.", "Dimensions");
                prop.SetProperty("Time", quantity.Dimension.GetPower(DimensionBase.Time).ToString(), true, "Time in second.", "Dimensions");

                // Unit
                prop.SetProperty("ConversionFactorToSI", quantity.Unit.ConversionFactorToSI.ToString(), true, "Multiplicative coefficient used to convert this quantity to SI (SiUnit = Unit*ConversionFactorToSI + OffSetToSI).", "Unit");
                prop.SetProperty("OffSetToSI", quantity.Unit.OffSetToSI.ToString(), true, "Additive coefficient used to convert this quantity to SI (SiUnit = Unit*ConversionFactorToSI + OffSetToSI).", "Unit");
                prop.SetProperty("UnitDescription", quantity.Unit.Description, true, "Description of this unit.", "Unit");
                prop.SetProperty("UnitID", quantity.Unit.ID, true, "ID of this unit.", "Unit");
            }
            else if (obj is IElementSet)
            {
                IElementSet elementSet = (IElementSet)obj;
                prop = new PropertyManager();

                // General
                prop.SetProperty("ID", elementSet.ID, true, "ID of this ElementSet", "General");
                prop.SetProperty("Version", elementSet.Version.ToString(), true, "Version of this ElementSet.", "General");
                string spatialReference = string.Empty;
                if (elementSet.SpatialReference != null)
                {
                    spatialReference = elementSet.SpatialReference.ID;
                }
                prop.SetProperty("SpatialReferenceID", spatialReference, true, "ID of this ElementSet's SpatialReference", "General");
                prop.SetProperty("Description", elementSet.Description, true, "Description of this ElementSet.", "General");
                prop.SetProperty("ElementCount", elementSet.ElementCount.ToString(), true, "Count of elements of this ElementSet.", "General");
                prop.SetProperty("ElementType", elementSet.ElementType.ToString(), true, "Type of elements in this ElementSet.", "General");
            }
            else if (obj is IDataOperation)
            {
                IDataOperation dataOperation = (IDataOperation)obj;
                prop = new PropertyManager();

                string DataOperationID = "DataOperationID";

                // small trick to avoid that some argument's name is same as DataOperationID.
                // it's not quite pure, but it works:-)
                bool conflict;
                do
                {
                    conflict = false;
                    for (int i = 0; i < dataOperation.ArgumentCount; i++)
                    {
                        if (dataOperation.GetArgument(i).Key == DataOperationID)
                        {
                            DataOperationID += " ";
                            conflict         = true;
                            break;
                        }
                    }
                }while(conflict);

                // General
                prop.SetProperty(DataOperationID, dataOperation.ID, true, "ID of this DataOperation", "General");

                // Arguments
                for (int i = 0; i < dataOperation.ArgumentCount; i++)
                {
                    IArgument arg = dataOperation.GetArgument(i);
                    prop.SetProperty(arg.Key, arg.Value, arg.ReadOnly || allReadOnly, arg.Description, "Arguments");
                }
            }
            else if (obj is ILinkableComponent)
            {
                ILinkableComponent linkableComponent = (ILinkableComponent)obj;
                prop = new PropertyManager();

                DateTime timeHorizonStart = DateTime.MinValue;
                DateTime timeHorizonEnd   = DateTime.MaxValue;
                if (linkableComponent.TimeHorizon != null)
                {
                    timeHorizonStart = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.TimeHorizon.Start.ModifiedJulianDay);
                    timeHorizonEnd   = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.TimeHorizon.End.ModifiedJulianDay);
                }

                DateTime earliestInputTime = DateTime.MinValue;
                if (linkableComponent.EarliestInputTime != null)
                {
                    earliestInputTime = CalendarConverter.ModifiedJulian2Gregorian(linkableComponent.EarliestInputTime.ModifiedJulianDay);
                }

                // General
                prop.SetProperty("ComponentID", linkableComponent.ComponentID, true, "ID the component.", "General");
                prop.SetProperty("ComponentDescription", linkableComponent.ComponentDescription, true, "Description of this component.", "General");
                prop.SetProperty("InputExchangeItemCount", linkableComponent.InputExchangeItemCount.ToString(), true, "Number of input exchange items.", "General");
                prop.SetProperty("OutputExchangeItemCount", linkableComponent.OutputExchangeItemCount.ToString(), true, "Number of output exchange items.", "General");
                prop.SetProperty("ModelID", linkableComponent.ModelID, true, "ID of the model (model=component+data).", "General");
                prop.SetProperty("ModelDescription", linkableComponent.ModelDescription, true, "Description of the model.", "General");
                prop.SetProperty("TimeHorizonStart", timeHorizonStart.ToString(), true, "Start of component's timehorizon.", "General");
                prop.SetProperty("TimeHorizonEnd", timeHorizonEnd.ToString(), true, "End of component's timehorizon.", "General");
                prop.SetProperty("ValidationMessage", linkableComponent.Validate(), true, "Validation string generated by component. No error ocured if it's empty.", "General");
                prop.SetProperty("EarliestInputTime", earliestInputTime.ToString(), true, "Earliest time for which component needs next input.", "General");

                string implementsIManageState = obj is IManageState ? "yes" : "no";
                prop.SetProperty("ImplementsIManageState", implementsIManageState, true, "Describes whether model implements IManageState interface.", "General");
            }

            if (prop != null)
            {
                prop.Tag = obj;
            }

            return(prop);
        }