536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
986 lines
33 KiB
C#
986 lines
33 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: CustomattributesConverter.cs
|
||
//
|
||
// Namespace: DataVisualization.Charting.Design
|
||
//
|
||
// Interfaces: IDataPointCustomPropertiesProvider
|
||
//
|
||
// Classes: CustomPropertiesTypeConverter, DynamicPropertyDescriptor
|
||
//
|
||
// Purpose: AxisName converter of the design-time CustomProperties
|
||
// property object.
|
||
//
|
||
// Reviewed:
|
||
//
|
||
//===================================================================
|
||
|
||
#region Used Namespaces
|
||
|
||
using System;
|
||
using System.Collections;
|
||
using System.ComponentModel;
|
||
using System.Drawing;
|
||
using System.Globalization;
|
||
using System.Diagnostics.CodeAnalysis;
|
||
|
||
#if Microsoft_CONTROL
|
||
using System.Windows.Forms.DataVisualization.Charting.Utilities;
|
||
using System.Windows.Forms.DataVisualization.Charting;
|
||
#else
|
||
using System.Web.UI.DataVisualization.Charting.Utilities;
|
||
using System.Web.UI.DataVisualization.Charting;
|
||
#endif
|
||
|
||
#endregion
|
||
|
||
#if Microsoft_CONTROL
|
||
namespace System.Windows.Forms.DataVisualization.Charting
|
||
#else
|
||
namespace System.Web.UI.DataVisualization.Charting
|
||
#endif
|
||
{
|
||
/// <summary>
|
||
/// Custom properties object type converter.
|
||
/// </summary>
|
||
internal class CustomPropertiesTypeConverter : TypeConverter
|
||
{
|
||
#region String to/from convertion methods
|
||
|
||
/// <summary>
|
||
/// Overrides the CanConvertFrom method of TypeConverter.
|
||
/// </summary>
|
||
/// <param name="context">Descriptor context.</param>
|
||
/// <param name="sourceType">Convertion source type.</param>
|
||
/// <returns>Indicates if convertion is possible.</returns>
|
||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||
{
|
||
if(sourceType == typeof(string))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return base.CanConvertFrom(context, sourceType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Overrides the CanConvertTo method of TypeConverter.
|
||
/// </summary>
|
||
/// <param name="context">Descriptor context.</param>
|
||
/// <param name="destinationType">Destination type.</param>
|
||
/// <returns>Indicates if convertion is possible.</returns>
|
||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||
{
|
||
if(destinationType == typeof(CustomProperties))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return base.CanConvertTo(context, destinationType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Overrides the ConvertTo method of TypeConverter.
|
||
/// </summary>
|
||
/// <param name="context">Descriptor context.</param>
|
||
/// <param name="culture">Culture information.</param>
|
||
/// <param name="value">Value to convert.</param>
|
||
/// <param name="destinationType">Convertion destination type.</param>
|
||
/// <returns>Converted object.</returns>
|
||
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
|
||
{
|
||
if (destinationType == typeof(string))
|
||
{
|
||
return ((CustomProperties)value).DataPointCustomProperties.CustomProperties;
|
||
}
|
||
|
||
return base.ConvertTo(context, culture, value, destinationType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Overrides the ConvertFrom method of TypeConverter.
|
||
/// Converts from string with comma separated values.
|
||
/// </summary>
|
||
/// <param name="context">Descriptor context.</param>
|
||
/// <param name="culture">Culture information.</param>
|
||
/// <param name="value">Value to convert from.</param>
|
||
/// <returns>Indicates if convertion is possible.</returns>
|
||
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
|
||
Justification = "Too large of a code change to justify making this change")]
|
||
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
|
||
{
|
||
string stringValue = value as string;
|
||
if(stringValue != null && context != null && context.Instance != null)
|
||
{
|
||
// Create new custom attribute class with a reference to the DataPointCustomProperties
|
||
if(context.Instance is DataPointCustomProperties)
|
||
{
|
||
((DataPointCustomProperties)context.Instance).CustomProperties = stringValue;
|
||
CustomProperties newAttributes = new CustomProperties(((DataPointCustomProperties)context.Instance));
|
||
return newAttributes;
|
||
}
|
||
|
||
else if (context.Instance is CustomProperties)
|
||
{
|
||
CustomProperties newAttributes = new CustomProperties(((CustomProperties)context.Instance).DataPointCustomProperties);
|
||
return newAttributes;
|
||
}
|
||
else if (context.Instance is IDataPointCustomPropertiesProvider)
|
||
{
|
||
CustomProperties newAttributes = new CustomProperties(((IDataPointCustomPropertiesProvider)context.Instance).DataPointCustomProperties);
|
||
return newAttributes;
|
||
}
|
||
|
||
else if (context.Instance is Array)
|
||
{
|
||
DataPointCustomProperties attributes = null;
|
||
foreach (object obj in ((Array)context.Instance))
|
||
{
|
||
if (obj is DataPointCustomProperties)
|
||
{
|
||
attributes = (DataPointCustomProperties)obj;
|
||
attributes.CustomProperties = stringValue;
|
||
}
|
||
}
|
||
if (attributes != null)
|
||
{
|
||
CustomProperties newAttributes = new CustomProperties(attributes);
|
||
return newAttributes;
|
||
}
|
||
}
|
||
}
|
||
return base.ConvertFrom(context, culture, value);
|
||
}
|
||
|
||
#endregion // String to/from convertion methods
|
||
|
||
#region Property Descriptor Collection methods
|
||
|
||
/// <summary>
|
||
/// Returns whether this object supports properties.
|
||
/// </summary>
|
||
/// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
|
||
/// <returns>true if GetProperties should be called to find the properties of this object; otherwise, false.</returns>
|
||
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns a collection of properties for the type of array specified by the value parameter,
|
||
/// using the specified context and properties.
|
||
/// </summary>
|
||
/// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
|
||
/// <param name="obj">An Object that specifies the type of array for which to get properties.</param>
|
||
/// <param name="attributes">An array of type Attribute that is used as a filter.</param>
|
||
/// <returns>A PropertyDescriptorCollection with the properties that are exposed for this data type, or a null reference (Nothing in Visual Basic) if there are no properties.</returns>
|
||
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object obj, Attribute[] attributes)
|
||
{
|
||
PropertyDescriptorCollection propCollection = new PropertyDescriptorCollection(null);
|
||
CustomProperties attr = obj as CustomProperties;
|
||
if(attr != null && context != null)
|
||
{
|
||
// Get series associated with custom attribute
|
||
Series series = (attr.DataPointCustomProperties is Series) ? ( (Series) attr.DataPointCustomProperties) : attr.DataPointCustomProperties.series;
|
||
if(series != null &&
|
||
series.Common != null)
|
||
{
|
||
// Loop through all registered custom properties
|
||
CustomPropertyRegistry registry = (CustomPropertyRegistry)series.Common.container.GetService(typeof(CustomPropertyRegistry));
|
||
foreach(CustomPropertyInfo attrInfo in registry.registeredCustomProperties)
|
||
{
|
||
// Check if attribute description matches curent selection in property browser
|
||
if(IsApplicableCustomProperty(attrInfo, context.Instance))
|
||
{
|
||
// Get array of property properties
|
||
Attribute[] propAttributes = GetPropertyAttributes(attrInfo);
|
||
|
||
// Create property descriptor
|
||
CustomAttributesPropertyDescriptor propertyDescriptor = new CustomAttributesPropertyDescriptor(
|
||
typeof(CustomProperties),
|
||
attrInfo.Name,
|
||
attrInfo.ValueType,
|
||
propAttributes,
|
||
attrInfo);
|
||
|
||
// Add descriptor into the collection
|
||
propCollection.Add(propertyDescriptor);
|
||
}
|
||
}
|
||
|
||
// Always add "UserDefined" property for all user defined custom properties
|
||
Attribute[] propUserDefinedAttributes = new Attribute[] {
|
||
new NotifyParentPropertyAttribute(true),
|
||
new RefreshPropertiesAttribute(RefreshProperties.All),
|
||
new DescriptionAttribute(SR.DescriptionAttributeUserDefined)
|
||
};
|
||
|
||
// Create property descriptor
|
||
CustomAttributesPropertyDescriptor propertyUserDefinedDescriptor = new CustomAttributesPropertyDescriptor(
|
||
typeof(CustomProperties),
|
||
"UserDefined",
|
||
typeof(string),
|
||
propUserDefinedAttributes,
|
||
null);
|
||
|
||
// Add descriptor into the collection
|
||
propCollection.Add(propertyUserDefinedDescriptor);
|
||
}
|
||
}
|
||
|
||
return propCollection;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks if provided custom attribute appies to the selected points or series.
|
||
/// </summary>
|
||
/// <param name="attrInfo">Custom attribute information.</param>
|
||
/// <param name="obj">Selected series or points.</param>
|
||
/// <returns>True if custom attribute applies.</returns>
|
||
private bool IsApplicableCustomProperty(CustomPropertyInfo attrInfo, object obj)
|
||
{
|
||
|
||
CustomProperties customProperties = obj as CustomProperties;
|
||
if (customProperties != null)
|
||
{
|
||
obj = customProperties.DataPointCustomProperties;
|
||
}
|
||
|
||
// Check if custom attribute applies to the series or points
|
||
if( (IsDataPoint(obj) && attrInfo.AppliesToDataPoint) ||
|
||
(!IsDataPoint(obj) && attrInfo.AppliesToSeries) )
|
||
{
|
||
// Check if attribute do not apply to 3D or 2D chart types
|
||
if( (Is3DChartType(obj) && attrInfo.AppliesTo3D) ||
|
||
(!Is3DChartType(obj) && attrInfo.AppliesTo2D) )
|
||
{
|
||
|
||
// Check if custom attribute applies to the chart types selected
|
||
SeriesChartType[] chartTypes = GetSelectedChartTypes(obj);
|
||
foreach(SeriesChartType chartType in chartTypes)
|
||
{
|
||
foreach(SeriesChartType attrChartType in attrInfo.AppliesToChartType)
|
||
{
|
||
if(attrChartType == chartType)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks if specified object represent a single or array of data points.
|
||
/// </summary>
|
||
/// <param name="obj">Object to test.</param>
|
||
/// <returns>True if specified object contains one or more data points.</returns>
|
||
private bool IsDataPoint(object obj)
|
||
{
|
||
Series series = obj as Series;
|
||
if(series != null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
Array array = obj as Array;
|
||
if(array != null && array.Length > 0)
|
||
{
|
||
if (array.GetValue(0) is Series)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks if specified object represent a single or array of data points.
|
||
/// </summary>
|
||
/// <param name="obj">Object to test.</param>
|
||
/// <returns>True if specified object contains one or more data points.</returns>
|
||
private bool Is3DChartType(object obj)
|
||
{
|
||
// Get array of series
|
||
Series[] seriesArray = GetSelectedSeries(obj);
|
||
|
||
// Loop through all series and check if its plotted on 3D chart area
|
||
foreach(Series series in seriesArray)
|
||
{
|
||
ChartArea chartArea = series.Chart.ChartAreas[series.ChartArea];
|
||
if(chartArea.Area3DStyle.Enable3D)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get array of selected series.
|
||
/// </summary>
|
||
/// <param name="obj">Selected objects.</param>
|
||
/// <returns>Selected series array.</returns>
|
||
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
|
||
Justification = "Too large of a code change to justify making this change")]
|
||
private Series[] GetSelectedSeries(object obj)
|
||
{
|
||
// Get array of series
|
||
Series[] seriesArray = new Series[0];
|
||
if(obj is Array && ((Array)obj).Length > 0)
|
||
{
|
||
if(((Array)obj).GetValue(0) is Series)
|
||
{
|
||
seriesArray = new Series[((Array)obj).Length];
|
||
((Array)obj).CopyTo(seriesArray, 0);
|
||
}
|
||
else if(((Array)obj).GetValue(0) is DataPointCustomProperties)
|
||
{
|
||
seriesArray = new Series[] { ((DataPointCustomProperties)((Array)obj).GetValue(0)).series };
|
||
}
|
||
}
|
||
else if(obj is Series)
|
||
{
|
||
seriesArray = new Series[] { ((Series)obj) };
|
||
}
|
||
else if(obj is DataPointCustomProperties)
|
||
{
|
||
seriesArray = new Series[] { ((DataPointCustomProperties)obj).series };
|
||
}
|
||
|
||
return seriesArray;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get array of chart types from the selected series.
|
||
/// </summary>
|
||
/// <param name="obj">Selected series or data points.</param>
|
||
/// <returns>Array of selected chart types.</returns>
|
||
private SeriesChartType[] GetSelectedChartTypes(object obj)
|
||
{
|
||
// Get array of series
|
||
Series[] seriesArray = GetSelectedSeries(obj);
|
||
|
||
// Create array of chart types
|
||
int index = 0;
|
||
SeriesChartType[] chartTypes = new SeriesChartType[seriesArray.Length];
|
||
foreach(Series series in seriesArray)
|
||
{
|
||
chartTypes[index++] = series.ChartType;
|
||
}
|
||
|
||
return chartTypes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets array of properties for the dynamic property.
|
||
/// </summary>
|
||
/// <param name="attrInfo">Custom attribute information.</param>
|
||
/// <returns>Array of properties.</returns>
|
||
private Attribute[] GetPropertyAttributes(CustomPropertyInfo attrInfo)
|
||
{
|
||
// Create default value attribute
|
||
DefaultValueAttribute defaultValueAttribute = null;
|
||
if (attrInfo.DefaultValue.GetType() == attrInfo.ValueType)
|
||
{
|
||
defaultValueAttribute = new DefaultValueAttribute(attrInfo.DefaultValue);
|
||
}
|
||
else if (attrInfo.DefaultValue is string)
|
||
{
|
||
defaultValueAttribute = new DefaultValueAttribute(attrInfo.ValueType, (string)attrInfo.DefaultValue);
|
||
}
|
||
else
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionCustomAttributeDefaultValueTypeInvalid));
|
||
}
|
||
// Add all properties into the list
|
||
ArrayList propList = new ArrayList();
|
||
|
||
propList.Add(new NotifyParentPropertyAttribute(true));
|
||
propList.Add(new RefreshPropertiesAttribute(RefreshProperties.All));
|
||
propList.Add(new DescriptionAttribute(attrInfo.Description));
|
||
propList.Add(defaultValueAttribute);
|
||
|
||
if (attrInfo.Name.Equals(CustomPropertyName.ErrorBarType, StringComparison.Ordinal))
|
||
{
|
||
propList.Add(new TypeConverterAttribute(typeof(ErrorBarTypeConverter)));
|
||
}
|
||
|
||
// Convert list to array
|
||
int index = 0;
|
||
Attribute[] propAttributes = new Attribute[propList.Count];
|
||
foreach(Attribute attr in propList)
|
||
{
|
||
propAttributes[index++] = attr;
|
||
}
|
||
return propAttributes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Special convertor for ErrorBarType custom attribute
|
||
/// </summary>
|
||
internal class ErrorBarTypeConverter : StringConverter
|
||
{
|
||
/// <summary>
|
||
/// Returns whether this object supports a standard set of values that can be picked from a list, using the specified context.
|
||
/// </summary>
|
||
/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
|
||
/// <returns>
|
||
/// true if <see cref="M:System.ComponentModel.TypeConverter.GetStandardValues"/> should be called to find a common set of values the object supports; otherwise, false.
|
||
/// </returns>
|
||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns whether the collection of standard values returned from <see cref="M:System.ComponentModel.TypeConverter.GetStandardValues"/> is an exclusive list of possible values, using the specified context.
|
||
/// </summary>
|
||
/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
|
||
/// <returns>
|
||
/// true if the <see cref="T:System.ComponentModel.TypeConverter.StandardValuesCollection"/> returned from <see cref="M:System.ComponentModel.TypeConverter.GetStandardValues"/> is an exhaustive list of possible values; false if other values are possible.
|
||
/// </returns>
|
||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns a collection of standard values for the data type this type converter is designed for when provided with a format context.
|
||
/// </summary>
|
||
/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context that can be used to extract additional information about the environment from which this converter is invoked. This parameter or properties of this parameter can be null.</param>
|
||
/// <returns>
|
||
/// A <see cref="T:System.ComponentModel.TypeConverter.StandardValuesCollection"/> that holds a standard set of valid values, or null if the data type does not support a standard set of values.
|
||
/// </returns>
|
||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||
{
|
||
ArrayList result = new ArrayList();
|
||
foreach (ChartTypes.ErrorBarType item in Enum.GetValues(typeof(ChartTypes.ErrorBarType)))
|
||
{
|
||
string itemStr = String.Format(CultureInfo.InvariantCulture, "{0}({1:N0})", item, ChartTypes.ErrorBarChart.DefaultErrorBarTypeValue(item));
|
||
result.Add(itemStr);
|
||
}
|
||
return new StandardValuesCollection(result);
|
||
}
|
||
}
|
||
|
||
#endregion // Property Descriptor Collection methods
|
||
|
||
#region Custom Attributes Property Descriptor
|
||
|
||
/// <summary>
|
||
/// Custom properties inner property descriptor class.
|
||
/// </summary>
|
||
protected class CustomAttributesPropertyDescriptor : TypeConverter.SimplePropertyDescriptor
|
||
{
|
||
#region Fields
|
||
|
||
// Property name
|
||
private string _name = string.Empty;
|
||
|
||
// Custom attribute information
|
||
private CustomPropertyInfo _customAttributeInfo = null;
|
||
|
||
#endregion // Fields
|
||
|
||
#region Constructor
|
||
|
||
/// <summary>
|
||
/// Property descriptor constructor.
|
||
/// </summary>
|
||
/// <param name="componentType">Component type.</param>
|
||
/// <param name="name">Property name.</param>
|
||
/// <param name="propertyType">Property type.</param>
|
||
/// <param name="attributes">Property attributes.</param>
|
||
/// <param name="customAttributeInfo">Custom attribute information.</param>
|
||
internal CustomAttributesPropertyDescriptor(
|
||
Type componentType,
|
||
string name,
|
||
Type propertyType,
|
||
Attribute[] attributes,
|
||
CustomPropertyInfo customAttributeInfo)
|
||
: base(componentType, name, propertyType, attributes)
|
||
{
|
||
this._name = name;
|
||
this._customAttributeInfo = customAttributeInfo;
|
||
}
|
||
|
||
#endregion // Constructor
|
||
|
||
#region Methods
|
||
|
||
/// <summary>
|
||
/// Gets the current value of the property on a component.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property for which to retrieve the value.</param>
|
||
/// <returns>The value of a property for a given component.</returns>
|
||
public override object GetValue(object component)
|
||
{
|
||
// "UserDefined" property expose comma separated user defined properties
|
||
CustomProperties customAttr = component as CustomProperties;
|
||
if(this._name == "UserDefined")
|
||
{
|
||
return customAttr.GetUserDefinedCustomProperties();
|
||
}
|
||
else
|
||
{
|
||
object val = null;
|
||
|
||
// Check if custom attribute with this name is set
|
||
string stringValue = customAttr.DataPointCustomProperties[this._name];
|
||
if(this._customAttributeInfo != null)
|
||
{
|
||
if(stringValue == null || stringValue.Length == 0)
|
||
{
|
||
val = GetValueFromString(this._customAttributeInfo.DefaultValue);
|
||
}
|
||
else
|
||
{
|
||
val = GetValueFromString(stringValue);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
val = stringValue;
|
||
}
|
||
|
||
return val;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets the value of the component to a different value.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property value that is to be set.</param>
|
||
/// <param name="value">The new value.</param>
|
||
public override void SetValue(object component, object value)
|
||
{
|
||
// Validate new value
|
||
ValidateValue(this._name, value);
|
||
|
||
// Get new value as string
|
||
string stringValue = GetStringFromValue(value);
|
||
|
||
// "UserDefined" property expose comma separated user defined properties
|
||
CustomProperties customAttr = component as CustomProperties;
|
||
if( this._name == "UserDefined" )
|
||
{
|
||
customAttr.SetUserDefinedAttributes(stringValue);
|
||
}
|
||
else
|
||
{
|
||
// Check if the new value is the same as DefaultValue
|
||
bool setAttributeValue = true;
|
||
if( IsDefaultValue(stringValue) )
|
||
{
|
||
// Remove custom properties with default values from data point
|
||
// only when series do not have this attribute set.
|
||
if( !(customAttr.DataPointCustomProperties is DataPoint) ||
|
||
!((DataPoint)customAttr.DataPointCustomProperties).series.IsCustomPropertySet(this._name) )
|
||
{
|
||
// Delete attribute
|
||
if(customAttr.DataPointCustomProperties.IsCustomPropertySet(this._name))
|
||
{
|
||
customAttr.DataPointCustomProperties.DeleteCustomProperty(this._name);
|
||
setAttributeValue = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Set custom attribute value
|
||
if( setAttributeValue )
|
||
{
|
||
customAttr.DataPointCustomProperties[this._name] = stringValue;
|
||
}
|
||
}
|
||
customAttr.DataPointCustomProperties.CustomProperties = customAttr.DataPointCustomProperties.CustomProperties;
|
||
|
||
IChangeTracking changeTracking = component as IChangeTracking;
|
||
if (changeTracking != null)
|
||
{
|
||
changeTracking.AcceptChanges();
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks if specified value is the default value of the attribute.
|
||
/// </summary>
|
||
/// <param name="val">Value to check.</param>
|
||
/// <returns>True if specified value is the default attribute value.</returns>
|
||
public bool IsDefaultValue(string val)
|
||
{
|
||
// Get default value string
|
||
string defaultValue = GetStringFromValue(this._customAttributeInfo.DefaultValue);
|
||
return (String.Compare(val, defaultValue, StringComparison.Ordinal) == 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets value from string a native type of attribute.
|
||
/// </summary>
|
||
/// <param name="obj">Object to convert to string.</param>
|
||
/// <returns>String representation of the specified object.</returns>
|
||
public virtual object GetValueFromString(object obj)
|
||
{
|
||
object result = null;
|
||
if(obj != null)
|
||
{
|
||
if(this._customAttributeInfo.ValueType == obj.GetType() )
|
||
{
|
||
return obj;
|
||
}
|
||
|
||
string stringValue = obj as string;
|
||
if (stringValue != null)
|
||
{
|
||
if(this._customAttributeInfo.ValueType == typeof(string) )
|
||
{
|
||
result = stringValue;
|
||
}
|
||
else if(this._customAttributeInfo.ValueType == typeof(float) )
|
||
{
|
||
result = float.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(this._customAttributeInfo.ValueType == typeof(double) )
|
||
{
|
||
result = double.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(this._customAttributeInfo.ValueType == typeof(int) )
|
||
{
|
||
result = int.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(this._customAttributeInfo.ValueType == typeof(bool) )
|
||
{
|
||
result = bool.Parse(stringValue);
|
||
}
|
||
else if(this._customAttributeInfo.ValueType == typeof(Color) )
|
||
{
|
||
ColorConverter colorConverter = new ColorConverter();
|
||
result = (Color)colorConverter.ConvertFromString(null, System.Globalization.CultureInfo.InvariantCulture, stringValue);
|
||
}
|
||
else if(this._customAttributeInfo.ValueType.IsEnum)
|
||
{
|
||
result = Enum.Parse(this._customAttributeInfo.ValueType, stringValue, true);
|
||
}
|
||
else
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeUnsupported( this._customAttributeInfo.ValueType.ToString() )));
|
||
}
|
||
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Converts attribute value to string.
|
||
/// </summary>
|
||
/// <param name="value">Attribute value to convert.</param>
|
||
/// <returns>Return attribute value converted to string.</returns>
|
||
public string GetStringFromValue(object value)
|
||
{
|
||
if(value is Color)
|
||
{
|
||
ColorConverter colorConverter = new ColorConverter();
|
||
return colorConverter.ConvertToString(null, System.Globalization.CultureInfo.InvariantCulture, value);
|
||
}
|
||
else if(value is float)
|
||
{
|
||
return ((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(value is double)
|
||
{
|
||
return ((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(value is int)
|
||
{
|
||
return ((int)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
else if(value is bool)
|
||
{
|
||
return ((bool)value).ToString();
|
||
}
|
||
|
||
return value.ToString();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Validates attribute value. Method throws exception in case of any issues.
|
||
/// </summary>
|
||
/// <param name="attrName">Attribute name.</param>
|
||
/// <param name="value">Attribute value to validate.</param>
|
||
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
|
||
Justification = "Too large of a code change to justify making this change")]
|
||
public virtual void ValidateValue(string attrName, object value)
|
||
{
|
||
// Check for validation rules
|
||
if(this._customAttributeInfo == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Check if property Min/Max value is provided
|
||
bool outOfRange = false;
|
||
if(this._customAttributeInfo.MaxValue != null)
|
||
{
|
||
if(value.GetType() != this._customAttributeInfo.MaxValue.GetType())
|
||
{
|
||
throw(new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMaximumPossibleValueInvalid( attrName ) ) );
|
||
}
|
||
|
||
if(value is float)
|
||
{
|
||
if((float)value > (float)this._customAttributeInfo.MaxValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else if(value is double)
|
||
{
|
||
if((double)value > (double)this._customAttributeInfo.MaxValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else if(value is int)
|
||
{
|
||
if((int)value > (int)this._customAttributeInfo.MaxValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueUnsupported(attrName)));
|
||
}
|
||
|
||
}
|
||
|
||
// Check if property Min value is provided
|
||
if(this._customAttributeInfo.MinValue != null)
|
||
{
|
||
if(value.GetType() != this._customAttributeInfo.MinValue.GetType())
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueInvalid( attrName ) ) );
|
||
}
|
||
|
||
if(value is float)
|
||
{
|
||
if((float)value < (float)this._customAttributeInfo.MinValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else if(value is double)
|
||
{
|
||
if((double)value < (double)this._customAttributeInfo.MinValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else if(value is int)
|
||
{
|
||
if((int)value < (int)this._customAttributeInfo.MinValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw(new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueUnsupported(attrName)));
|
||
}
|
||
}
|
||
|
||
// Value out of range exception
|
||
if(outOfRange)
|
||
{
|
||
if(this._customAttributeInfo.MaxValue != null && this._customAttributeInfo.MinValue != null)
|
||
{
|
||
throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange(attrName, this._customAttributeInfo.MinValue.ToString(),this._customAttributeInfo.MaxValue.ToString() )));
|
||
}
|
||
else if(this._customAttributeInfo.MinValue != null)
|
||
{
|
||
throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeBiggerThenValue(attrName, this._customAttributeInfo.MinValue.ToString())));
|
||
}
|
||
else if(this._customAttributeInfo.MaxValue != null)
|
||
{
|
||
throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeMoreThenValue(attrName, this._customAttributeInfo.MaxValue.ToString())));
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion // Methods
|
||
}
|
||
|
||
#endregion // Custom Attributes Property Descriptor
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Property descriptor with ability to dynamically change properties
|
||
/// of the base property descriptor object.
|
||
/// </summary>
|
||
internal class DynamicPropertyDescriptor : PropertyDescriptor
|
||
{
|
||
#region Fields
|
||
|
||
// Reference to the base property descriptor
|
||
private PropertyDescriptor _basePropertyDescriptor = null;
|
||
|
||
// Dynamic display name of the property
|
||
private string _displayName = string.Empty;
|
||
|
||
#endregion // Fields
|
||
|
||
#region Constructor
|
||
|
||
/// <summary>
|
||
/// Constructor of the dynamic property descriptor.
|
||
/// </summary>
|
||
/// <param name="basePropertyDescriptor">Base property descriptor.</param>
|
||
/// <param name="displayName">New display name of the property.</param>
|
||
public DynamicPropertyDescriptor(
|
||
PropertyDescriptor basePropertyDescriptor,
|
||
string displayName)
|
||
: base(basePropertyDescriptor)
|
||
{
|
||
this._displayName = displayName;
|
||
this._basePropertyDescriptor = basePropertyDescriptor;
|
||
}
|
||
|
||
#endregion // Constructor
|
||
|
||
#region Properties
|
||
|
||
/// <summary>
|
||
/// Gets the type of the component this property is bound to.
|
||
/// </summary>
|
||
public override Type ComponentType
|
||
{
|
||
get
|
||
{
|
||
return _basePropertyDescriptor.ComponentType;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the name that can be displayed in a window, such as a Properties window.
|
||
/// </summary>
|
||
public override string DisplayName
|
||
{
|
||
get
|
||
{
|
||
if(this._displayName.Length > 0)
|
||
{
|
||
return this._displayName;
|
||
}
|
||
return this._basePropertyDescriptor.DisplayName;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets a value indicating whether this property is browsable.
|
||
/// </summary>
|
||
public override bool IsBrowsable
|
||
{
|
||
get
|
||
{
|
||
return this._basePropertyDescriptor.IsBrowsable;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets a value indicating whether this property is read-only.
|
||
/// </summary>
|
||
public override bool IsReadOnly
|
||
{
|
||
get
|
||
{
|
||
return this._basePropertyDescriptor.IsReadOnly;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the type of the property.
|
||
/// </summary>
|
||
public override Type PropertyType
|
||
{
|
||
get
|
||
{
|
||
return this._basePropertyDescriptor.PropertyType;
|
||
}
|
||
}
|
||
|
||
#endregion // Properties
|
||
|
||
#region Methods
|
||
|
||
/// <summary>
|
||
/// Returns whether resetting an object changes its value.
|
||
/// </summary>
|
||
/// <param name="component">The component to test for reset capability.</param>
|
||
/// <returns>true if resetting the component changes its value; otherwise, false.</returns>
|
||
public override bool CanResetValue(object component)
|
||
{
|
||
return _basePropertyDescriptor.CanResetValue(component);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the current value of the property on a component.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property for which to retrieve the value.</param>
|
||
/// <returns>The value of a property for a given component.</returns>
|
||
public override object GetValue(object component)
|
||
{
|
||
return this._basePropertyDescriptor.GetValue(component);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Resets the value for this property of the component to the default value.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property value that is to be reset to the default value.</param>
|
||
public override void ResetValue(object component)
|
||
{
|
||
this._basePropertyDescriptor.ResetValue(component);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Determines a value indicating whether the value of this property needs to be persisted.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property to be examined for persistence.</param>
|
||
/// <returns>True if the property should be persisted; otherwise, false.</returns>
|
||
public override bool ShouldSerializeValue(object component)
|
||
{
|
||
return this._basePropertyDescriptor.ShouldSerializeValue(component);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets the value of the component to a different value.
|
||
/// </summary>
|
||
/// <param name="component">The component with the property value that is to be set.</param>
|
||
/// <param name="value">The new value.</param>
|
||
public override void SetValue(object component, object value)
|
||
{
|
||
this._basePropertyDescriptor.SetValue(component, value);
|
||
}
|
||
|
||
#endregion // Methods
|
||
}
|
||
|
||
internal interface IDataPointCustomPropertiesProvider
|
||
{
|
||
DataPointCustomProperties DataPointCustomProperties { get; }
|
||
}
|
||
}
|