CustomAttributesConverters.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. //
  5. // Purpose: AxisName converter of the design-time CustomProperties
  6. // property object.
  7. //
  8. using System;
  9. using System.Collections;
  10. using System.ComponentModel;
  11. using System.Drawing;
  12. using System.Globalization;
  13. using System.Diagnostics.CodeAnalysis;
  14. using FastReport.DataVisualization.Charting.Utilities;
  15. using FastReport.DataVisualization.Charting;
  16. namespace FastReport.DataVisualization.Charting
  17. {
  18. /// <summary>
  19. /// Custom properties object type converter.
  20. /// </summary>
  21. internal class CustomPropertiesTypeConverter : TypeConverter
  22. {
  23. #region String to/from convertion methods
  24. /// <summary>
  25. /// Overrides the CanConvertFrom method of TypeConverter.
  26. /// </summary>
  27. /// <param name="context">Descriptor context.</param>
  28. /// <param name="sourceType">Convertion source type.</param>
  29. /// <returns>Indicates if convertion is possible.</returns>
  30. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  31. {
  32. if(sourceType == typeof(string))
  33. {
  34. return true;
  35. }
  36. return base.CanConvertFrom(context, sourceType);
  37. }
  38. /// <summary>
  39. /// Overrides the CanConvertTo method of TypeConverter.
  40. /// </summary>
  41. /// <param name="context">Descriptor context.</param>
  42. /// <param name="destinationType">Destination type.</param>
  43. /// <returns>Indicates if convertion is possible.</returns>
  44. public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  45. {
  46. if(destinationType == typeof(CustomProperties))
  47. {
  48. return true;
  49. }
  50. return base.CanConvertTo(context, destinationType);
  51. }
  52. /// <summary>
  53. /// Overrides the ConvertTo method of TypeConverter.
  54. /// </summary>
  55. /// <param name="context">Descriptor context.</param>
  56. /// <param name="culture">Culture information.</param>
  57. /// <param name="value">Value to convert.</param>
  58. /// <param name="destinationType">Convertion destination type.</param>
  59. /// <returns>Converted object.</returns>
  60. public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
  61. {
  62. if (destinationType == typeof(string))
  63. {
  64. return ((CustomProperties)value).DataPointCustomProperties.CustomProperties;
  65. }
  66. return base.ConvertTo(context, culture, value, destinationType);
  67. }
  68. /// <summary>
  69. /// Overrides the ConvertFrom method of TypeConverter.
  70. /// Converts from string with comma separated values.
  71. /// </summary>
  72. /// <param name="context">Descriptor context.</param>
  73. /// <param name="culture">Culture information.</param>
  74. /// <param name="value">Value to convert from.</param>
  75. /// <returns>Indicates if convertion is possible.</returns>
  76. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
  77. Justification = "Too large of a code change to justify making this change")]
  78. public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  79. {
  80. string stringValue = value as string;
  81. if(stringValue != null && context != null && context.Instance != null)
  82. {
  83. // Create new custom attribute class with a reference to the DataPointCustomProperties
  84. if(context.Instance is DataPointCustomProperties)
  85. {
  86. ((DataPointCustomProperties)context.Instance).CustomProperties = stringValue;
  87. CustomProperties newAttributes = new CustomProperties(((DataPointCustomProperties)context.Instance));
  88. return newAttributes;
  89. }
  90. else if (context.Instance is CustomProperties)
  91. {
  92. CustomProperties newAttributes = new CustomProperties(((CustomProperties)context.Instance).DataPointCustomProperties);
  93. return newAttributes;
  94. }
  95. else if (context.Instance is IDataPointCustomPropertiesProvider)
  96. {
  97. CustomProperties newAttributes = new CustomProperties(((IDataPointCustomPropertiesProvider)context.Instance).DataPointCustomProperties);
  98. return newAttributes;
  99. }
  100. else if (context.Instance is Array)
  101. {
  102. DataPointCustomProperties attributes = null;
  103. foreach (object obj in ((Array)context.Instance))
  104. {
  105. if (obj is DataPointCustomProperties)
  106. {
  107. attributes = (DataPointCustomProperties)obj;
  108. attributes.CustomProperties = stringValue;
  109. }
  110. }
  111. if (attributes != null)
  112. {
  113. CustomProperties newAttributes = new CustomProperties(attributes);
  114. return newAttributes;
  115. }
  116. }
  117. }
  118. return base.ConvertFrom(context, culture, value);
  119. }
  120. #endregion // String to/from convertion methods
  121. #region Property Descriptor Collection methods
  122. /// <summary>
  123. /// Returns whether this object supports properties.
  124. /// </summary>
  125. /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
  126. /// <returns>true if GetProperties should be called to find the properties of this object; otherwise, false.</returns>
  127. public override bool GetPropertiesSupported(ITypeDescriptorContext context)
  128. {
  129. return true;
  130. }
  131. /// <summary>
  132. /// Returns a collection of properties for the type of array specified by the value parameter,
  133. /// using the specified context and properties.
  134. /// </summary>
  135. /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
  136. /// <param name="obj">An Object that specifies the type of array for which to get properties.</param>
  137. /// <param name="attributes">An array of type Attribute that is used as a filter.</param>
  138. /// <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>
  139. public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object obj, Attribute[] attributes)
  140. {
  141. PropertyDescriptorCollection propCollection = new PropertyDescriptorCollection(null);
  142. CustomProperties attr = obj as CustomProperties;
  143. if(attr != null && context != null)
  144. {
  145. // Get series associated with custom attribute
  146. Series series = (attr.DataPointCustomProperties is Series) ? ( (Series) attr.DataPointCustomProperties) : attr.DataPointCustomProperties.series;
  147. if(series != null &&
  148. series.Common != null)
  149. {
  150. // Loop through all registered custom properties
  151. CustomPropertyRegistry registry = (CustomPropertyRegistry)series.Common.container.GetService(typeof(CustomPropertyRegistry));
  152. foreach(CustomPropertyInfo attrInfo in registry.registeredCustomProperties)
  153. {
  154. // Check if attribute description matches curent selection in property browser
  155. if(IsApplicableCustomProperty(attrInfo, context.Instance))
  156. {
  157. // Get array of property properties
  158. Attribute[] propAttributes = GetPropertyAttributes(attrInfo);
  159. // Create property descriptor
  160. CustomAttributesPropertyDescriptor propertyDescriptor = new CustomAttributesPropertyDescriptor(
  161. typeof(CustomProperties),
  162. attrInfo.Name,
  163. attrInfo.ValueType,
  164. propAttributes,
  165. attrInfo);
  166. // Add descriptor into the collection
  167. propCollection.Add(propertyDescriptor);
  168. }
  169. }
  170. // Always add "UserDefined" property for all user defined custom properties
  171. Attribute[] propUserDefinedAttributes = new Attribute[] {
  172. new NotifyParentPropertyAttribute(true),
  173. new RefreshPropertiesAttribute(RefreshProperties.All),
  174. new DescriptionAttribute(SR.DescriptionAttributeUserDefined)
  175. };
  176. // Create property descriptor
  177. CustomAttributesPropertyDescriptor propertyUserDefinedDescriptor = new CustomAttributesPropertyDescriptor(
  178. typeof(CustomProperties),
  179. "UserDefined",
  180. typeof(string),
  181. propUserDefinedAttributes,
  182. null);
  183. // Add descriptor into the collection
  184. propCollection.Add(propertyUserDefinedDescriptor);
  185. }
  186. }
  187. return propCollection;
  188. }
  189. /// <summary>
  190. /// Checks if provided custom attribute appies to the selected points or series.
  191. /// </summary>
  192. /// <param name="attrInfo">Custom attribute information.</param>
  193. /// <param name="obj">Selected series or points.</param>
  194. /// <returns>True if custom attribute applies.</returns>
  195. private bool IsApplicableCustomProperty(CustomPropertyInfo attrInfo, object obj)
  196. {
  197. CustomProperties customProperties = obj as CustomProperties;
  198. if (customProperties != null)
  199. {
  200. obj = customProperties.DataPointCustomProperties;
  201. }
  202. // Check if custom attribute applies to the series or points
  203. if( (IsDataPoint(obj) && attrInfo.AppliesToDataPoint) ||
  204. (!IsDataPoint(obj) && attrInfo.AppliesToSeries) )
  205. {
  206. // Check if attribute do not apply to 3D or 2D chart types
  207. if( (Is3DChartType(obj) && attrInfo.AppliesTo3D) ||
  208. (!Is3DChartType(obj) && attrInfo.AppliesTo2D) )
  209. {
  210. // Check if custom attribute applies to the chart types selected
  211. SeriesChartType[] chartTypes = GetSelectedChartTypes(obj);
  212. foreach(SeriesChartType chartType in chartTypes)
  213. {
  214. foreach(SeriesChartType attrChartType in attrInfo.AppliesToChartType)
  215. {
  216. if(attrChartType == chartType)
  217. {
  218. return true;
  219. }
  220. }
  221. }
  222. }
  223. }
  224. return false;
  225. }
  226. /// <summary>
  227. /// Checks if specified object represent a single or array of data points.
  228. /// </summary>
  229. /// <param name="obj">Object to test.</param>
  230. /// <returns>True if specified object contains one or more data points.</returns>
  231. private bool IsDataPoint(object obj)
  232. {
  233. Series series = obj as Series;
  234. if(series != null)
  235. {
  236. return false;
  237. }
  238. Array array = obj as Array;
  239. if(array != null && array.Length > 0)
  240. {
  241. if (array.GetValue(0) is Series)
  242. {
  243. return false;
  244. }
  245. }
  246. return true;
  247. }
  248. /// <summary>
  249. /// Checks if specified object represent a single or array of data points.
  250. /// </summary>
  251. /// <param name="obj">Object to test.</param>
  252. /// <returns>True if specified object contains one or more data points.</returns>
  253. private bool Is3DChartType(object obj)
  254. {
  255. // Get array of series
  256. Series[] seriesArray = GetSelectedSeries(obj);
  257. // Loop through all series and check if its plotted on 3D chart area
  258. foreach(Series series in seriesArray)
  259. {
  260. ChartArea chartArea = series.Chart.ChartAreas[series.ChartArea];
  261. if(chartArea.Area3DStyle.Enable3D)
  262. {
  263. return true;
  264. }
  265. }
  266. return false;
  267. }
  268. /// <summary>
  269. /// Get array of selected series.
  270. /// </summary>
  271. /// <param name="obj">Selected objects.</param>
  272. /// <returns>Selected series array.</returns>
  273. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
  274. Justification = "Too large of a code change to justify making this change")]
  275. private Series[] GetSelectedSeries(object obj)
  276. {
  277. // Get array of series
  278. Series[] seriesArray = new Series[0];
  279. if(obj is Array && ((Array)obj).Length > 0)
  280. {
  281. if(((Array)obj).GetValue(0) is Series)
  282. {
  283. seriesArray = new Series[((Array)obj).Length];
  284. ((Array)obj).CopyTo(seriesArray, 0);
  285. }
  286. else if(((Array)obj).GetValue(0) is DataPointCustomProperties)
  287. {
  288. seriesArray = new Series[] { ((DataPointCustomProperties)((Array)obj).GetValue(0)).series };
  289. }
  290. }
  291. else if(obj is Series)
  292. {
  293. seriesArray = new Series[] { ((Series)obj) };
  294. }
  295. else if(obj is DataPointCustomProperties)
  296. {
  297. seriesArray = new Series[] { ((DataPointCustomProperties)obj).series };
  298. }
  299. return seriesArray;
  300. }
  301. /// <summary>
  302. /// Get array of chart types from the selected series.
  303. /// </summary>
  304. /// <param name="obj">Selected series or data points.</param>
  305. /// <returns>Array of selected chart types.</returns>
  306. private SeriesChartType[] GetSelectedChartTypes(object obj)
  307. {
  308. // Get array of series
  309. Series[] seriesArray = GetSelectedSeries(obj);
  310. // Create array of chart types
  311. int index = 0;
  312. SeriesChartType[] chartTypes = new SeriesChartType[seriesArray.Length];
  313. foreach(Series series in seriesArray)
  314. {
  315. chartTypes[index++] = series.ChartType;
  316. }
  317. return chartTypes;
  318. }
  319. /// <summary>
  320. /// Gets array of properties for the dynamic property.
  321. /// </summary>
  322. /// <param name="attrInfo">Custom attribute information.</param>
  323. /// <returns>Array of properties.</returns>
  324. private Attribute[] GetPropertyAttributes(CustomPropertyInfo attrInfo)
  325. {
  326. // Create default value attribute
  327. DefaultValueAttribute defaultValueAttribute = null;
  328. if (attrInfo.DefaultValue.GetType() == attrInfo.ValueType)
  329. {
  330. defaultValueAttribute = new DefaultValueAttribute(attrInfo.DefaultValue);
  331. }
  332. else if (attrInfo.DefaultValue is string)
  333. {
  334. defaultValueAttribute = new DefaultValueAttribute(attrInfo.ValueType, (string)attrInfo.DefaultValue);
  335. }
  336. else
  337. {
  338. throw (new InvalidOperationException(SR.ExceptionCustomAttributeDefaultValueTypeInvalid));
  339. }
  340. // Add all properties into the list
  341. ArrayList propList = new ArrayList();
  342. propList.Add(new NotifyParentPropertyAttribute(true));
  343. propList.Add(new RefreshPropertiesAttribute(RefreshProperties.All));
  344. propList.Add(new DescriptionAttribute(attrInfo.Description));
  345. propList.Add(defaultValueAttribute);
  346. if (attrInfo.Name.Equals(CustomPropertyName.ErrorBarType, StringComparison.Ordinal))
  347. {
  348. propList.Add(new TypeConverterAttribute(typeof(ErrorBarTypeConverter)));
  349. }
  350. // Convert list to array
  351. int index = 0;
  352. Attribute[] propAttributes = new Attribute[propList.Count];
  353. foreach(Attribute attr in propList)
  354. {
  355. propAttributes[index++] = attr;
  356. }
  357. return propAttributes;
  358. }
  359. /// <summary>
  360. /// Special convertor for ErrorBarType custom attribute
  361. /// </summary>
  362. internal class ErrorBarTypeConverter : StringConverter
  363. {
  364. /// <summary>
  365. /// Returns whether this object supports a standard set of values that can be picked from a list, using the specified context.
  366. /// </summary>
  367. /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
  368. /// <returns>
  369. /// true if <see cref="M:System.ComponentModel.TypeConverter.GetStandardValues"/> should be called to find a common set of values the object supports; otherwise, false.
  370. /// </returns>
  371. public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  372. {
  373. return true;
  374. }
  375. /// <summary>
  376. /// 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.
  377. /// </summary>
  378. /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
  379. /// <returns>
  380. /// 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.
  381. /// </returns>
  382. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  383. {
  384. return false;
  385. }
  386. /// <summary>
  387. /// Returns a collection of standard values for the data type this type converter is designed for when provided with a format context.
  388. /// </summary>
  389. /// <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>
  390. /// <returns>
  391. /// 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.
  392. /// </returns>
  393. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  394. {
  395. ArrayList result = new ArrayList();
  396. foreach (ChartTypes.ErrorBarType item in Enum.GetValues(typeof(ChartTypes.ErrorBarType)))
  397. {
  398. string itemStr = String.Format(CultureInfo.InvariantCulture, "{0}({1:N0})", item, ChartTypes.ErrorBarChart.DefaultErrorBarTypeValue(item));
  399. result.Add(itemStr);
  400. }
  401. return new StandardValuesCollection(result);
  402. }
  403. }
  404. #endregion // Property Descriptor Collection methods
  405. #region Custom Attributes Property Descriptor
  406. /// <summary>
  407. /// Custom properties inner property descriptor class.
  408. /// </summary>
  409. protected class CustomAttributesPropertyDescriptor : TypeConverter.SimplePropertyDescriptor
  410. {
  411. #region Fields
  412. // Property name
  413. private string _name = string.Empty;
  414. // Custom attribute information
  415. private CustomPropertyInfo _customAttributeInfo = null;
  416. #endregion // Fields
  417. #region Constructor
  418. /// <summary>
  419. /// Property descriptor constructor.
  420. /// </summary>
  421. /// <param name="componentType">Component type.</param>
  422. /// <param name="name">Property name.</param>
  423. /// <param name="propertyType">Property type.</param>
  424. /// <param name="attributes">Property attributes.</param>
  425. /// <param name="customAttributeInfo">Custom attribute information.</param>
  426. internal CustomAttributesPropertyDescriptor(
  427. Type componentType,
  428. string name,
  429. Type propertyType,
  430. Attribute[] attributes,
  431. CustomPropertyInfo customAttributeInfo)
  432. : base(componentType, name, propertyType, attributes)
  433. {
  434. this._name = name;
  435. this._customAttributeInfo = customAttributeInfo;
  436. }
  437. #endregion // Constructor
  438. #region Methods
  439. /// <summary>
  440. /// Gets the current value of the property on a component.
  441. /// </summary>
  442. /// <param name="component">The component with the property for which to retrieve the value.</param>
  443. /// <returns>The value of a property for a given component.</returns>
  444. public override object GetValue(object component)
  445. {
  446. // "UserDefined" property expose comma separated user defined properties
  447. CustomProperties customAttr = component as CustomProperties;
  448. if(this._name == "UserDefined")
  449. {
  450. return customAttr.GetUserDefinedCustomProperties();
  451. }
  452. else
  453. {
  454. object val = null;
  455. // Check if custom attribute with this name is set
  456. string stringValue = customAttr.DataPointCustomProperties[this._name];
  457. if(this._customAttributeInfo != null)
  458. {
  459. if(stringValue == null || stringValue.Length == 0)
  460. {
  461. val = GetValueFromString(this._customAttributeInfo.DefaultValue);
  462. }
  463. else
  464. {
  465. val = GetValueFromString(stringValue);
  466. }
  467. }
  468. else
  469. {
  470. val = stringValue;
  471. }
  472. return val;
  473. }
  474. }
  475. /// <summary>
  476. /// Sets the value of the component to a different value.
  477. /// </summary>
  478. /// <param name="component">The component with the property value that is to be set.</param>
  479. /// <param name="value">The new value.</param>
  480. public override void SetValue(object component, object value)
  481. {
  482. // Validate new value
  483. ValidateValue(this._name, value);
  484. // Get new value as string
  485. string stringValue = GetStringFromValue(value);
  486. // "UserDefined" property expose comma separated user defined properties
  487. CustomProperties customAttr = component as CustomProperties;
  488. if( this._name == "UserDefined" )
  489. {
  490. customAttr.SetUserDefinedAttributes(stringValue);
  491. }
  492. else
  493. {
  494. // Check if the new value is the same as DefaultValue
  495. bool setAttributeValue = true;
  496. if( IsDefaultValue(stringValue) )
  497. {
  498. // Remove custom properties with default values from data point
  499. // only when series do not have this attribute set.
  500. if( !(customAttr.DataPointCustomProperties is DataPoint) ||
  501. !((DataPoint)customAttr.DataPointCustomProperties).series.IsCustomPropertySet(this._name) )
  502. {
  503. // Delete attribute
  504. if(customAttr.DataPointCustomProperties.IsCustomPropertySet(this._name))
  505. {
  506. customAttr.DataPointCustomProperties.DeleteCustomProperty(this._name);
  507. setAttributeValue = false;
  508. }
  509. }
  510. }
  511. // Set custom attribute value
  512. if( setAttributeValue )
  513. {
  514. customAttr.DataPointCustomProperties[this._name] = stringValue;
  515. }
  516. }
  517. customAttr.DataPointCustomProperties.CustomProperties = customAttr.DataPointCustomProperties.CustomProperties;
  518. IChangeTracking changeTracking = component as IChangeTracking;
  519. if (changeTracking != null)
  520. {
  521. changeTracking.AcceptChanges();
  522. }
  523. }
  524. /// <summary>
  525. /// Checks if specified value is the default value of the attribute.
  526. /// </summary>
  527. /// <param name="val">Value to check.</param>
  528. /// <returns>True if specified value is the default attribute value.</returns>
  529. public bool IsDefaultValue(string val)
  530. {
  531. // Get default value string
  532. string defaultValue = GetStringFromValue(this._customAttributeInfo.DefaultValue);
  533. return (String.Compare(val, defaultValue, StringComparison.Ordinal) == 0);
  534. }
  535. /// <summary>
  536. /// Gets value from string a native type of attribute.
  537. /// </summary>
  538. /// <param name="obj">Object to convert to string.</param>
  539. /// <returns>String representation of the specified object.</returns>
  540. public virtual object GetValueFromString(object obj)
  541. {
  542. object result = null;
  543. if(obj != null)
  544. {
  545. if(this._customAttributeInfo.ValueType == obj.GetType() )
  546. {
  547. return obj;
  548. }
  549. string stringValue = obj as string;
  550. if (stringValue != null)
  551. {
  552. if(this._customAttributeInfo.ValueType == typeof(string) )
  553. {
  554. result = stringValue;
  555. }
  556. else if(this._customAttributeInfo.ValueType == typeof(float) )
  557. {
  558. result = float.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
  559. }
  560. else if(this._customAttributeInfo.ValueType == typeof(double) )
  561. {
  562. result = double.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
  563. }
  564. else if(this._customAttributeInfo.ValueType == typeof(int) )
  565. {
  566. result = int.Parse(stringValue, System.Globalization.CultureInfo.InvariantCulture);
  567. }
  568. else if(this._customAttributeInfo.ValueType == typeof(bool) )
  569. {
  570. result = bool.Parse(stringValue);
  571. }
  572. else if(this._customAttributeInfo.ValueType == typeof(Color) )
  573. {
  574. ColorConverter colorConverter = new ColorConverter();
  575. result = (Color)colorConverter.ConvertFromString(null, System.Globalization.CultureInfo.InvariantCulture, stringValue);
  576. }
  577. else if(this._customAttributeInfo.ValueType.IsEnum)
  578. {
  579. result = Enum.Parse(this._customAttributeInfo.ValueType, stringValue, true);
  580. }
  581. else
  582. {
  583. throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeUnsupported( this._customAttributeInfo.ValueType.ToString() )));
  584. }
  585. }
  586. }
  587. return result;
  588. }
  589. /// <summary>
  590. /// Converts attribute value to string.
  591. /// </summary>
  592. /// <param name="value">Attribute value to convert.</param>
  593. /// <returns>Return attribute value converted to string.</returns>
  594. public string GetStringFromValue(object value)
  595. {
  596. if(value is Color)
  597. {
  598. ColorConverter colorConverter = new ColorConverter();
  599. return colorConverter.ConvertToString(null, System.Globalization.CultureInfo.InvariantCulture, value);
  600. }
  601. else if(value is float)
  602. {
  603. return ((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
  604. }
  605. else if(value is double)
  606. {
  607. return ((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
  608. }
  609. else if(value is int)
  610. {
  611. return ((int)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
  612. }
  613. else if(value is bool)
  614. {
  615. return ((bool)value).ToString();
  616. }
  617. return value.ToString();
  618. }
  619. /// <summary>
  620. /// Validates attribute value. Method throws exception in case of any issues.
  621. /// </summary>
  622. /// <param name="attrName">Attribute name.</param>
  623. /// <param name="value">Attribute value to validate.</param>
  624. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
  625. Justification = "Too large of a code change to justify making this change")]
  626. public virtual void ValidateValue(string attrName, object value)
  627. {
  628. // Check for validation rules
  629. if(this._customAttributeInfo == null)
  630. {
  631. return;
  632. }
  633. // Check if property Min/Max value is provided
  634. bool outOfRange = false;
  635. if(this._customAttributeInfo.MaxValue != null)
  636. {
  637. if(value.GetType() != this._customAttributeInfo.MaxValue.GetType())
  638. {
  639. throw(new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMaximumPossibleValueInvalid( attrName ) ) );
  640. }
  641. if(value is float)
  642. {
  643. if((float)value > (float)this._customAttributeInfo.MaxValue)
  644. {
  645. outOfRange = true;
  646. }
  647. }
  648. else if(value is double)
  649. {
  650. if((double)value > (double)this._customAttributeInfo.MaxValue)
  651. {
  652. outOfRange = true;
  653. }
  654. }
  655. else if(value is int)
  656. {
  657. if((int)value > (int)this._customAttributeInfo.MaxValue)
  658. {
  659. outOfRange = true;
  660. }
  661. }
  662. else
  663. {
  664. throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueUnsupported(attrName)));
  665. }
  666. }
  667. // Check if property Min value is provided
  668. if(this._customAttributeInfo.MinValue != null)
  669. {
  670. if(value.GetType() != this._customAttributeInfo.MinValue.GetType())
  671. {
  672. throw (new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueInvalid( attrName ) ) );
  673. }
  674. if(value is float)
  675. {
  676. if((float)value < (float)this._customAttributeInfo.MinValue)
  677. {
  678. outOfRange = true;
  679. }
  680. }
  681. else if(value is double)
  682. {
  683. if((double)value < (double)this._customAttributeInfo.MinValue)
  684. {
  685. outOfRange = true;
  686. }
  687. }
  688. else if(value is int)
  689. {
  690. if((int)value < (int)this._customAttributeInfo.MinValue)
  691. {
  692. outOfRange = true;
  693. }
  694. }
  695. else
  696. {
  697. throw(new InvalidOperationException(SR.ExceptionCustomAttributeTypeOrMinimumPossibleValueUnsupported(attrName)));
  698. }
  699. }
  700. // Value out of range exception
  701. if(outOfRange)
  702. {
  703. if(this._customAttributeInfo.MaxValue != null && this._customAttributeInfo.MinValue != null)
  704. {
  705. throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange(attrName, this._customAttributeInfo.MinValue.ToString(),this._customAttributeInfo.MaxValue.ToString() )));
  706. }
  707. else if(this._customAttributeInfo.MinValue != null)
  708. {
  709. throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeBiggerThenValue(attrName, this._customAttributeInfo.MinValue.ToString())));
  710. }
  711. else if(this._customAttributeInfo.MaxValue != null)
  712. {
  713. throw(new InvalidOperationException(SR.ExceptionCustomAttributeMustBeMoreThenValue(attrName, this._customAttributeInfo.MaxValue.ToString())));
  714. }
  715. }
  716. }
  717. #endregion // Methods
  718. }
  719. #endregion // Custom Attributes Property Descriptor
  720. }
  721. /// <summary>
  722. /// Property descriptor with ability to dynamically change properties
  723. /// of the base property descriptor object.
  724. /// </summary>
  725. internal class DynamicPropertyDescriptor : PropertyDescriptor
  726. {
  727. #region Fields
  728. // Reference to the base property descriptor
  729. private PropertyDescriptor _basePropertyDescriptor = null;
  730. // Dynamic display name of the property
  731. private string _displayName = string.Empty;
  732. #endregion // Fields
  733. #region Constructor
  734. /// <summary>
  735. /// Constructor of the dynamic property descriptor.
  736. /// </summary>
  737. /// <param name="basePropertyDescriptor">Base property descriptor.</param>
  738. /// <param name="displayName">New display name of the property.</param>
  739. public DynamicPropertyDescriptor(
  740. PropertyDescriptor basePropertyDescriptor,
  741. string displayName)
  742. : base(basePropertyDescriptor)
  743. {
  744. this._displayName = displayName;
  745. this._basePropertyDescriptor = basePropertyDescriptor;
  746. }
  747. #endregion // Constructor
  748. #region Properties
  749. /// <summary>
  750. /// Gets the type of the component this property is bound to.
  751. /// </summary>
  752. public override Type ComponentType
  753. {
  754. get
  755. {
  756. return _basePropertyDescriptor.ComponentType;
  757. }
  758. }
  759. /// <summary>
  760. /// Gets the name that can be displayed in a window, such as a Properties window.
  761. /// </summary>
  762. public override string DisplayName
  763. {
  764. get
  765. {
  766. if(this._displayName.Length > 0)
  767. {
  768. return this._displayName;
  769. }
  770. return this._basePropertyDescriptor.DisplayName;
  771. }
  772. }
  773. /// <summary>
  774. /// Gets a value indicating whether this property is browsable.
  775. /// </summary>
  776. public override bool IsBrowsable
  777. {
  778. get
  779. {
  780. return this._basePropertyDescriptor.IsBrowsable;
  781. }
  782. }
  783. /// <summary>
  784. /// Gets a value indicating whether this property is read-only.
  785. /// </summary>
  786. public override bool IsReadOnly
  787. {
  788. get
  789. {
  790. return this._basePropertyDescriptor.IsReadOnly;
  791. }
  792. }
  793. /// <summary>
  794. /// Gets the type of the property.
  795. /// </summary>
  796. public override Type PropertyType
  797. {
  798. get
  799. {
  800. return this._basePropertyDescriptor.PropertyType;
  801. }
  802. }
  803. #endregion // Properties
  804. #region Methods
  805. /// <summary>
  806. /// Returns whether resetting an object changes its value.
  807. /// </summary>
  808. /// <param name="component">The component to test for reset capability.</param>
  809. /// <returns>true if resetting the component changes its value; otherwise, false.</returns>
  810. public override bool CanResetValue(object component)
  811. {
  812. return _basePropertyDescriptor.CanResetValue(component);
  813. }
  814. /// <summary>
  815. /// Gets the current value of the property on a component.
  816. /// </summary>
  817. /// <param name="component">The component with the property for which to retrieve the value.</param>
  818. /// <returns>The value of a property for a given component.</returns>
  819. public override object GetValue(object component)
  820. {
  821. return this._basePropertyDescriptor.GetValue(component);
  822. }
  823. /// <summary>
  824. /// Resets the value for this property of the component to the default value.
  825. /// </summary>
  826. /// <param name="component">The component with the property value that is to be reset to the default value.</param>
  827. public override void ResetValue(object component)
  828. {
  829. this._basePropertyDescriptor.ResetValue(component);
  830. }
  831. /// <summary>
  832. /// Determines a value indicating whether the value of this property needs to be persisted.
  833. /// </summary>
  834. /// <param name="component">The component with the property to be examined for persistence.</param>
  835. /// <returns>True if the property should be persisted; otherwise, false.</returns>
  836. public override bool ShouldSerializeValue(object component)
  837. {
  838. return this._basePropertyDescriptor.ShouldSerializeValue(component);
  839. }
  840. /// <summary>
  841. /// Sets the value of the component to a different value.
  842. /// </summary>
  843. /// <param name="component">The component with the property value that is to be set.</param>
  844. /// <param name="value">The new value.</param>
  845. public override void SetValue(object component, object value)
  846. {
  847. this._basePropertyDescriptor.SetValue(component, value);
  848. }
  849. #endregion // Methods
  850. }
  851. internal interface IDataPointCustomPropertiesProvider
  852. {
  853. DataPointCustomProperties DataPointCustomProperties { get; }
  854. }
  855. }