GridEntry.cs 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2004-2008 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jonathan Chambers (jonathan.chambers@ansys.com)
  24. // Ivan N. Zlatev (contact@i-nz.net)
  25. //
  26. // NOT COMPLETE
  27. using System.Collections;
  28. using System.Collections.ObjectModel;
  29. using System.ComponentModel;
  30. using System.ComponentModel.Design;
  31. using System.Drawing;
  32. using System.Drawing.Design;
  33. using System.Globalization;
  34. using System.Windows.Forms.Design;
  35. namespace System.Windows.Forms.PropertyGridInternal
  36. {
  37. internal class GridEntry : GridItem, ITypeDescriptorContext
  38. {
  39. #region Local Variables
  40. private PropertyGrid property_grid;
  41. private bool expanded;
  42. private GridItemCollection grid_items;
  43. private GridItem parent;
  44. private PropertyDescriptor[] property_descriptors;
  45. private int top;
  46. private Rectangle plus_minus_bounds;
  47. private GridItemCollection child_griditems_cache;
  48. #endregion // Local Variables
  49. #region Contructors
  50. protected GridEntry(PropertyGrid propertyGrid, GridEntry parent)
  51. {
  52. if (propertyGrid == null)
  53. throw new ArgumentNullException("propertyGrid");
  54. property_grid = propertyGrid;
  55. plus_minus_bounds = new Rectangle(0, 0, 0, 0);
  56. top = -1;
  57. grid_items = new GridItemCollection();
  58. expanded = false;
  59. this.parent = parent;
  60. child_griditems_cache = null;
  61. }
  62. // Cannot use one PropertyDescriptor for all owners, because the
  63. // propertydescriptors might have different Invokees. Check
  64. // ReflectionPropertyDescriptor.GetInvokee and how it's used.
  65. //
  66. public GridEntry(PropertyGrid propertyGrid, PropertyDescriptor[] properties,
  67. GridEntry parent) : this(propertyGrid, parent)
  68. {
  69. if (properties == null || properties.Length == 0)
  70. throw new ArgumentNullException("prop_desc");
  71. property_descriptors = properties;
  72. }
  73. #endregion // Constructors
  74. public override bool Expandable
  75. {
  76. get
  77. {
  78. TypeConverter converter = GetConverter();
  79. if (converter != null)
  80. return converter.GetPropertiesSupported((ITypeDescriptorContext)this);
  81. if (GetChildGridItemsCached().Count > 0)
  82. return true;
  83. return false;
  84. }
  85. }
  86. public override bool Expanded
  87. {
  88. get { return expanded; }
  89. set
  90. {
  91. if (expanded != value)
  92. {
  93. expanded = value;
  94. PopulateChildGridItems();
  95. if (value)
  96. property_grid.OnExpandItem(this);
  97. else
  98. property_grid.OnCollapseItem(this);
  99. }
  100. }
  101. }
  102. public override GridItemCollection GridItems
  103. {
  104. get
  105. {
  106. PopulateChildGridItems();
  107. return grid_items;
  108. }
  109. }
  110. public override GridItemType GridItemType
  111. {
  112. get { return GridItemType.Property; }
  113. }
  114. public override string Label
  115. {
  116. get
  117. {
  118. PropertyDescriptor property = this.PropertyDescriptor;
  119. if (property != null)
  120. {
  121. string label = property.DisplayName;
  122. ParenthesizePropertyNameAttribute parensAttr =
  123. property.Attributes[typeof(ParenthesizePropertyNameAttribute)] as ParenthesizePropertyNameAttribute;
  124. if (parensAttr != null && parensAttr.NeedParenthesis)
  125. label = "(" + label + ")";
  126. return label;
  127. }
  128. return String.Empty;
  129. }
  130. }
  131. public override GridItem Parent
  132. {
  133. get { return parent; }
  134. }
  135. public GridEntry ParentEntry
  136. {
  137. get
  138. {
  139. if (parent != null && parent.GridItemType == GridItemType.Category)
  140. return parent.Parent as GridEntry;
  141. return parent as GridEntry;
  142. }
  143. }
  144. public override PropertyDescriptor PropertyDescriptor
  145. {
  146. get { return property_descriptors != null ? property_descriptors[0] : null; }
  147. }
  148. public PropertyDescriptor[] PropertyDescriptors
  149. {
  150. get { return property_descriptors; }
  151. }
  152. public object PropertyOwner
  153. {
  154. get
  155. {
  156. object[] owners = PropertyOwners;
  157. if (owners != null)
  158. return owners[0];
  159. return null;
  160. }
  161. }
  162. public object[] PropertyOwners
  163. {
  164. get
  165. {
  166. if (ParentEntry == null)
  167. return null;
  168. object[] owners = ParentEntry.Values;
  169. PropertyDescriptor[] properties = PropertyDescriptors;
  170. object newOwner = null;
  171. for (int i = 0; i < owners.Length; i++)
  172. {
  173. if (owners[i] is ICustomTypeDescriptor)
  174. {
  175. newOwner = ((ICustomTypeDescriptor)owners[i]).GetPropertyOwner(properties[i]);
  176. if (newOwner != null)
  177. owners[i] = newOwner;
  178. }
  179. }
  180. return owners;
  181. }
  182. }
  183. // true if the value is the same among all properties
  184. public bool HasMergedValue
  185. {
  186. get
  187. {
  188. if (!IsMerged)
  189. return false;
  190. object[] values = this.Values;
  191. for (int i = 0; i + 1 < values.Length; i++)
  192. {
  193. if (!Object.Equals(values[i], values[i + 1]))
  194. return false;
  195. }
  196. return true;
  197. }
  198. }
  199. public virtual bool IsMerged
  200. {
  201. get { return (PropertyDescriptors != null && PropertyDescriptors.Length > 1); }
  202. }
  203. // If IsMerged this will return all values for all properties in all owners
  204. public virtual object[] Values
  205. {
  206. get
  207. {
  208. if (PropertyDescriptor == null || this.PropertyOwners == null)
  209. return null;
  210. if (IsMerged)
  211. {
  212. object[] owners = this.PropertyOwners;
  213. PropertyDescriptor[] properties = PropertyDescriptors;
  214. object[] values = new object[owners.Length];
  215. for (int i = 0; i < owners.Length; i++)
  216. values[i] = properties[i].GetValue(owners[i]);
  217. return values;
  218. }
  219. else
  220. {
  221. return new object[] { this.Value };
  222. }
  223. }
  224. }
  225. // Returns the first value for the first propertyowner and propertydescriptor
  226. //
  227. public override object Value
  228. {
  229. get
  230. {
  231. if (PropertyDescriptor == null || PropertyOwner == null)
  232. return null;
  233. return PropertyDescriptor.GetValue(PropertyOwner);
  234. }
  235. }
  236. public string ValueText
  237. {
  238. get
  239. {
  240. var text = ConvertToString(this.Value);
  241. return text ?? String.Empty;
  242. }
  243. }
  244. public override bool Select()
  245. {
  246. property_grid.SelectedGridItem = this;
  247. return true;
  248. }
  249. #region ITypeDescriptorContext
  250. void ITypeDescriptorContext.OnComponentChanged()
  251. {
  252. }
  253. bool ITypeDescriptorContext.OnComponentChanging()
  254. {
  255. return false;
  256. }
  257. IContainer ITypeDescriptorContext.Container
  258. {
  259. get
  260. {
  261. if (PropertyOwner == null)
  262. return null;
  263. IComponent component = property_grid.SelectedObject as IComponent;
  264. if (component != null && component.Site != null)
  265. return component.Site.Container;
  266. return null;
  267. }
  268. }
  269. object ITypeDescriptorContext.Instance
  270. {
  271. get { return PropertyOwner; }
  272. }
  273. PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor
  274. {
  275. get { return PropertyDescriptor; }
  276. }
  277. #endregion
  278. #region IServiceProvider Members
  279. object IServiceProvider.GetService(Type serviceType)
  280. {
  281. IComponent selectedComponent = property_grid.SelectedObject as IComponent;
  282. if (selectedComponent != null && selectedComponent.Site != null)
  283. return selectedComponent.Site.GetService(serviceType);
  284. return null;
  285. }
  286. #endregion
  287. internal int Top
  288. {
  289. get { return top; }
  290. set
  291. {
  292. if (top != value)
  293. top = value;
  294. }
  295. }
  296. internal Rectangle PlusMinusBounds
  297. {
  298. get { return plus_minus_bounds; }
  299. set { plus_minus_bounds = value; }
  300. }
  301. public void SetParent(GridItem parent)
  302. {
  303. this.parent = parent;
  304. }
  305. public ICollection AcceptedValues
  306. {
  307. get
  308. {
  309. TypeConverter converter = GetConverter();
  310. if (PropertyDescriptor != null && converter != null &&
  311. converter.GetStandardValuesSupported((ITypeDescriptorContext)this))
  312. {
  313. ArrayList values = new ArrayList();
  314. string stringVal = null;
  315. ICollection standardValues = converter.GetStandardValues((ITypeDescriptorContext)this);
  316. if (standardValues != null)
  317. {
  318. foreach (object value in standardValues)
  319. {
  320. stringVal = ConvertToString(value);
  321. if (stringVal != null)
  322. values.Add(stringVal);
  323. }
  324. }
  325. return values.Count > 0 ? values : null;
  326. }
  327. return null;
  328. }
  329. }
  330. private string ConvertToString(object value)
  331. {
  332. var converter = GetConverter();
  333. var convertContext = (ITypeDescriptorContext)this;
  334. var convertedValue = (string)null;
  335. if (converter != null && converter.CanConvertTo(convertContext, typeof(string)))
  336. {
  337. try
  338. {
  339. convertedValue = converter.ConvertToString(convertContext, value);
  340. }
  341. catch
  342. {
  343. // XXX: Happens too often...
  344. // property_grid.ShowError ("Property value of '" + property_descriptor.Name + "' is not convertible to string.");
  345. }
  346. }
  347. return (convertedValue != null) ? convertedValue : (value as string);
  348. }
  349. public bool HasCustomEditor
  350. {
  351. get { return EditorStyle != UITypeEditorEditStyle.None; }
  352. }
  353. public UITypeEditorEditStyle EditorStyle
  354. {
  355. get
  356. {
  357. UITypeEditor editor = GetEditor();
  358. if (editor != null)
  359. {
  360. try
  361. {
  362. return editor.GetEditStyle((ITypeDescriptorContext)this);
  363. }
  364. catch
  365. {
  366. // Some of our Editors throw NotImplementedException
  367. }
  368. }
  369. return UITypeEditorEditStyle.None;
  370. }
  371. }
  372. public bool EditorResizeable
  373. {
  374. get
  375. {
  376. if (this.EditorStyle == UITypeEditorEditStyle.DropDown)
  377. {
  378. UITypeEditor editor = GetEditor();
  379. if (editor != null && editor.IsDropDownResizable)
  380. return true;
  381. }
  382. return false;
  383. }
  384. }
  385. public bool EditValue(IWindowsFormsEditorService service)
  386. {
  387. if (service == null)
  388. throw new ArgumentNullException("service");
  389. IServiceContainer parent = ((ITypeDescriptorContext)this).GetService(typeof(IServiceContainer)) as IServiceContainer;
  390. ServiceContainer container = null;
  391. if (parent != null)
  392. container = new ServiceContainer(parent);
  393. else
  394. container = new ServiceContainer();
  395. container.AddService(typeof(IWindowsFormsEditorService), service);
  396. UITypeEditor editor = GetEditor();
  397. if (editor != null)
  398. {
  399. try
  400. {
  401. object value = editor.EditValue((ITypeDescriptorContext)this,
  402. container,
  403. this.Value);
  404. string error = null;
  405. return SetValue(value, out error);
  406. }
  407. catch
  408. { //(Exception e) {
  409. // property_grid.ShowError (e.Message + Environment.NewLine + e.StackTrace);
  410. }
  411. }
  412. return false;
  413. }
  414. private bool uiEditorIsSet;
  415. private UITypeEditor uiEditor;
  416. private UITypeEditor GetEditor()
  417. {
  418. if (!uiEditorIsSet)
  419. {
  420. if (PropertyDescriptor != null)
  421. {
  422. try
  423. {
  424. var rawEditor = PropertyDescriptor.GetEditor(typeof(UITypeEditor));
  425. uiEditor = rawEditor as UITypeEditor;
  426. var propertyType = PropertyDescriptor.PropertyType;
  427. var editorType = rawEditor?.GetType();
  428. var editorName = editorType?.FullName;
  429. var editorAsm = editorType?.Assembly;
  430. var thisAsm = this.GetType().Assembly;
  431. // here we provide built-in type editors (replacing type editors located in system assemblies because they are not functional here)
  432. if (typeof(ICollection).IsAssignableFrom(propertyType))
  433. {
  434. if ((uiEditor == null && typeof(string[]).IsAssignableFrom(propertyType)) ||
  435. (editorName == "System.ComponentModel.Design.StringArrayEditor" && editorAsm != thisAsm))
  436. uiEditor = new StringArrayEditor(propertyType);
  437. if ((uiEditor == null && typeof(Collection<string>).IsAssignableFrom(propertyType)) ||
  438. (editorName == "System.ComponentModel.Design.StringCollectionEditor" && editorAsm != thisAsm))
  439. uiEditor = new StringCollectionEditor(propertyType);
  440. if ((uiEditor == null && typeof(Array).IsAssignableFrom(propertyType)) ||
  441. (editorName == "System.ComponentModel.Design.ArrayEditor" && editorAsm != thisAsm))
  442. uiEditor = new ArrayEditor(propertyType);
  443. if (uiEditor == null ||
  444. (editorName == "System.ComponentModel.Design.CollectionEditor" && editorAsm != thisAsm))
  445. uiEditor = new CollectionEditor(propertyType);
  446. }
  447. if (propertyType == typeof(string))
  448. {
  449. if (uiEditor == null && (editorName == "System.ComponentModel.Design.MultilineStringEditor" && editorAsm != thisAsm))
  450. uiEditor = new MultilineStringEditor();
  451. }
  452. if (propertyType == typeof(DateTime))
  453. {
  454. if (uiEditor == null || (editorName == "System.ComponentModel.Design.DateTimeEditor" && editorAsm != thisAsm))
  455. uiEditor = new DateTimeEditor();
  456. }
  457. if (propertyType == typeof(AnchorStyles))
  458. {
  459. if (uiEditor == null || (editorName == "System.Windows.Forms.Design.AnchorEditor" && editorAsm != thisAsm))
  460. uiEditor = new AnchorEditor();
  461. }
  462. if (propertyType == typeof(DockStyle))
  463. {
  464. if (uiEditor == null || (editorName == "System.Windows.Forms.Design.DockEditor" && editorAsm != thisAsm))
  465. uiEditor = new DockEditor();
  466. }
  467. if (propertyType == typeof(Font))
  468. {
  469. if (uiEditor == null || (editorName == "System.Drawing.Design.FontEditor" && editorAsm != thisAsm))
  470. uiEditor = new FontEditor();
  471. }
  472. if (propertyType == typeof(Image))
  473. {
  474. if (uiEditor == null || (editorName == "System.Drawing.Design.ImageEditor" && editorAsm != thisAsm))
  475. uiEditor = new ImageEditor();
  476. }
  477. if (propertyType == typeof(Color))
  478. {
  479. if (uiEditor == null || (editorName == "System.Drawing.Design.ColorEditor" && editorAsm != thisAsm))
  480. uiEditor = new ColorEditor();
  481. }
  482. if (propertyType == typeof(Cursor))
  483. {
  484. if (uiEditor == null || (editorName == "System.Drawing.Design.CursorEditor" && editorAsm != thisAsm))
  485. uiEditor = new CursorEditor();
  486. }
  487. if (propertyType == typeof(ContentAlignment))
  488. {
  489. // fallback to standard enum editor
  490. if (editorName == "System.Drawing.Design.ContentAlignmentEditor" && editorAsm != thisAsm)
  491. uiEditor = null;
  492. }
  493. }
  494. catch
  495. {
  496. // can happen, because we are missing some editors
  497. }
  498. }
  499. uiEditorIsSet = true;
  500. }
  501. return uiEditor;
  502. }
  503. private TypeConverter GetConverter()
  504. {
  505. if (PropertyDescriptor != null)
  506. return PropertyDescriptor.Converter;
  507. return null;
  508. }
  509. public bool ToggleValue()
  510. {
  511. if (IsReadOnly || (IsMerged && !HasMergedValue))
  512. return false;
  513. bool success = false;
  514. string error = null;
  515. object value = this.Value;
  516. if (PropertyDescriptor.PropertyType == typeof(bool))
  517. success = SetValue(!(bool)value, out error);
  518. else
  519. {
  520. TypeConverter converter = GetConverter();
  521. if (converter != null &&
  522. converter.GetStandardValuesSupported((ITypeDescriptorContext)this))
  523. {
  524. TypeConverter.StandardValuesCollection values =
  525. (TypeConverter.StandardValuesCollection)converter.GetStandardValues((ITypeDescriptorContext)this);
  526. if (values != null)
  527. {
  528. for (int i = 0; i < values.Count; i++)
  529. {
  530. if (value != null && value.Equals(values[i]))
  531. {
  532. if (i < values.Count - 1)
  533. success = SetValue(values[i + 1], out error);
  534. else
  535. success = SetValue(values[0], out error);
  536. break;
  537. }
  538. }
  539. }
  540. }
  541. }
  542. if (!success && error != null)
  543. property_grid.ShowError(error);
  544. return success;
  545. }
  546. public bool SetValue(object value, out string error)
  547. {
  548. error = null;
  549. if (this.IsReadOnly)
  550. return false;
  551. object oldValue = Value;
  552. if (SetValueCore(value, out error))
  553. {
  554. InvalidateChildGridItemsCache();
  555. property_grid.OnPropertyValueChangedInternal(this, oldValue);
  556. return true;
  557. }
  558. return false;
  559. }
  560. protected virtual bool SetValueCore(object value, out string error)
  561. {
  562. error = null;
  563. TypeConverter converter = GetConverter();
  564. Type valueType = value != null ? value.GetType() : null;
  565. // if the new value is not of the same type try to convert it
  566. if (valueType != null && this.PropertyDescriptor.PropertyType != null &&
  567. !this.PropertyDescriptor.PropertyType.IsAssignableFrom(valueType))
  568. {
  569. bool conversionError = false;
  570. try
  571. {
  572. if (converter != null &&
  573. converter.CanConvertFrom((ITypeDescriptorContext)this, valueType))
  574. value = converter.ConvertFrom((ITypeDescriptorContext)this,
  575. CultureInfo.CurrentCulture, value);
  576. }
  577. catch (Exception e)
  578. {
  579. error = e.Message;
  580. conversionError = true;
  581. }
  582. if (conversionError)
  583. {
  584. string valueText = ConvertToString(value);
  585. string errorShortDescription = null;
  586. if (valueText != null)
  587. {
  588. errorShortDescription = "Property value '" + valueText + "' of '" +
  589. PropertyDescriptor.Name + "' is not convertible to type '" +
  590. this.PropertyDescriptor.PropertyType.Name + "'";
  591. }
  592. else
  593. {
  594. errorShortDescription = "Property value of '" +
  595. PropertyDescriptor.Name + "' is not convertible to type '" +
  596. this.PropertyDescriptor.PropertyType.Name + "'";
  597. }
  598. error = errorShortDescription + Environment.NewLine + Environment.NewLine + error;
  599. return false;
  600. }
  601. }
  602. bool changed = false;
  603. bool current_changed = false;
  604. object[] propertyOwners = this.PropertyOwners;
  605. PropertyDescriptor[] properties = PropertyDescriptors;
  606. for (int i = 0; i < propertyOwners.Length; i++)
  607. {
  608. object currentVal = properties[i].GetValue(propertyOwners[i]);
  609. current_changed = false;
  610. if (!Object.Equals(currentVal, value))
  611. {
  612. if (this.ShouldCreateParentInstance)
  613. {
  614. Hashtable updatedParentProperties = new Hashtable();
  615. PropertyDescriptorCollection parentProperties = TypeDescriptor.GetProperties(propertyOwners[i]);
  616. foreach (PropertyDescriptor property in parentProperties)
  617. {
  618. if (property.Name == properties[i].Name)
  619. updatedParentProperties[property.Name] = value;
  620. else
  621. updatedParentProperties[property.Name] = property.GetValue(propertyOwners[i]);
  622. }
  623. object updatedParentValue = this.ParentEntry.PropertyDescriptor.Converter.CreateInstance(
  624. (ITypeDescriptorContext)this.ParentEntry, updatedParentProperties);
  625. if (updatedParentValue != null)
  626. current_changed = this.ParentEntry.SetValueCore(updatedParentValue, out error);
  627. }
  628. else
  629. {
  630. try
  631. {
  632. properties[i].SetValue(propertyOwners[i], value);
  633. }
  634. catch
  635. {
  636. // MS seems to swallow this
  637. //
  638. // string valueText = ConvertToString (value);
  639. // if (valueText != null)
  640. // error = "Property value '" + valueText + "' of '" + properties[i].Name + "' is invalid.";
  641. // else
  642. // error = "Property value of '" + properties[i].Name + "' is invalid.";
  643. return false;
  644. }
  645. if (IsValueType(this.ParentEntry))
  646. current_changed = ParentEntry.SetValueCore(propertyOwners[i], out error);
  647. else
  648. current_changed = true;
  649. }
  650. }
  651. if (current_changed)
  652. changed = true;
  653. }
  654. return changed;
  655. }
  656. private bool IsValueType(GridEntry item)
  657. {
  658. if (item != null && item.PropertyDescriptor != null &&
  659. (item.PropertyDescriptor.PropertyType.IsValueType ||
  660. item.PropertyDescriptor.PropertyType.IsPrimitive))
  661. return true;
  662. return false;
  663. }
  664. public bool ResetValue()
  665. {
  666. if (IsResetable)
  667. {
  668. object[] owners = this.PropertyOwners;
  669. PropertyDescriptor[] properties = PropertyDescriptors;
  670. for (int i = 0; i < owners.Length; i++)
  671. {
  672. properties[i].ResetValue(owners[i]);
  673. if (IsValueType(this.ParentEntry))
  674. {
  675. string error = null;
  676. if (!ParentEntry.SetValueCore(owners[i], out error) && error != null)
  677. property_grid.ShowError(error);
  678. }
  679. }
  680. property_grid.OnPropertyValueChangedInternal(this, this.Value);
  681. return true;
  682. }
  683. return false;
  684. }
  685. public bool HasDefaultValue
  686. {
  687. get
  688. {
  689. if (PropertyDescriptor != null)
  690. return !PropertyDescriptor.ShouldSerializeValue(PropertyOwner);
  691. return false;
  692. }
  693. }
  694. // Determines if the current value can be reset
  695. //
  696. public virtual bool IsResetable
  697. {
  698. get { return (!IsReadOnly && PropertyDescriptor.CanResetValue(PropertyOwner)); }
  699. }
  700. // If false the entry can be modified only by the means of a predefined values
  701. // and not such inputed by the user.
  702. //
  703. public virtual bool IsEditable
  704. {
  705. get
  706. {
  707. TypeConverter converter = GetConverter();
  708. if (PropertyDescriptor == null)
  709. return false;
  710. else if (PropertyDescriptor.PropertyType.IsArray)
  711. return false;
  712. else if (PropertyDescriptor.IsReadOnly && !this.ShouldCreateParentInstance)
  713. return false;
  714. else if (converter == null ||
  715. !converter.CanConvertFrom((ITypeDescriptorContext)this, typeof(string)))
  716. return false;
  717. else if (converter.GetStandardValuesSupported((ITypeDescriptorContext)this) &&
  718. converter.GetStandardValuesExclusive((ITypeDescriptorContext)this))
  719. return false;
  720. else
  721. return true;
  722. }
  723. }
  724. // If true the the entry cannot be modified at all
  725. //
  726. public virtual bool IsReadOnly
  727. {
  728. get
  729. {
  730. TypeConverter converter = GetConverter();
  731. if (PropertyDescriptor == null || PropertyOwner == null)
  732. return true;
  733. else if (PropertyDescriptor.IsReadOnly &&
  734. (EditorStyle != UITypeEditorEditStyle.Modal || PropertyDescriptor.PropertyType.IsValueType) &&
  735. !this.ShouldCreateParentInstance)
  736. return true;
  737. else if (PropertyDescriptor.IsReadOnly &&
  738. TypeDescriptor.GetAttributes(PropertyDescriptor.PropertyType)
  739. [typeof(ImmutableObjectAttribute)].Equals(ImmutableObjectAttribute.Yes))
  740. return true;
  741. else if (ShouldCreateParentInstance && ParentEntry.IsReadOnly)
  742. return true;
  743. else if (!HasCustomEditor && converter == null)
  744. return true;
  745. else if (converter != null &&
  746. !converter.GetStandardValuesSupported((ITypeDescriptorContext)this) &&
  747. !converter.CanConvertFrom((ITypeDescriptorContext)this,
  748. typeof(string)) &&
  749. !HasCustomEditor)
  750. {
  751. return true;
  752. }
  753. else if (PropertyDescriptor.PropertyType.IsArray && !HasCustomEditor)
  754. return true;
  755. else
  756. return false;
  757. }
  758. }
  759. public bool IsPassword
  760. {
  761. get
  762. {
  763. if (PropertyDescriptor != null)
  764. return PropertyDescriptor.Attributes.Contains(PasswordPropertyTextAttribute.Yes);
  765. return false;
  766. }
  767. }
  768. public bool IsBool
  769. {
  770. get
  771. {
  772. if (PropertyDescriptor != null)
  773. return PropertyDescriptor.PropertyType == typeof(bool);
  774. return false;
  775. }
  776. }
  777. // This is a way to set readonly properties (e.g properties without a setter).
  778. // The way it works is that if CreateInstance is supported by the parent's converter
  779. // it gets passed a list of properties and their values which it uses to create an
  780. // instance (e.g by passing them to the ctor of that object type).
  781. //
  782. // This is used for e.g Font
  783. //
  784. public virtual bool ShouldCreateParentInstance
  785. {
  786. get
  787. {
  788. if (this.ParentEntry != null && ParentEntry.PropertyDescriptor != null)
  789. {
  790. TypeConverter parentConverter = ParentEntry.GetConverter();
  791. if (parentConverter != null && parentConverter.GetCreateInstanceSupported((ITypeDescriptorContext)this))
  792. return true;
  793. }
  794. return false;
  795. }
  796. }
  797. public virtual bool PaintValueSupported
  798. {
  799. get
  800. {
  801. UITypeEditor editor = GetEditor();
  802. if (editor != null)
  803. {
  804. try
  805. {
  806. return editor.GetPaintValueSupported();
  807. }
  808. catch
  809. {
  810. // Some of our Editors throw NotImplementedException
  811. }
  812. }
  813. return false;
  814. }
  815. }
  816. public virtual void PaintValue(Graphics gfx, Rectangle rect)
  817. {
  818. UITypeEditor editor = GetEditor();
  819. if (editor != null)
  820. {
  821. try
  822. {
  823. editor.PaintValue(this.Value, gfx, rect);
  824. }
  825. catch
  826. {
  827. // Some of our Editors throw NotImplementedException
  828. }
  829. }
  830. }
  831. #region Population
  832. protected void PopulateChildGridItems()
  833. {
  834. grid_items = GetChildGridItemsCached();
  835. }
  836. private void InvalidateChildGridItemsCache()
  837. {
  838. if (child_griditems_cache != null)
  839. {
  840. child_griditems_cache = null;
  841. PopulateChildGridItems();
  842. }
  843. }
  844. private GridItemCollection GetChildGridItemsCached()
  845. {
  846. if (child_griditems_cache == null)
  847. {
  848. child_griditems_cache = GetChildGridItems();
  849. }
  850. return child_griditems_cache;
  851. }
  852. private GridItemCollection GetChildGridItems()
  853. {
  854. object[] propertyOwners = this.Values;
  855. string[] propertyNames = GetMergedPropertyNames(propertyOwners);
  856. GridItemCollection items = new GridItemCollection();
  857. if (propertyOwners != null)
  858. {
  859. PropertyDescriptorCollection[] allProperties = new PropertyDescriptorCollection[propertyOwners.Length];
  860. for (int i = 0; i < propertyOwners.Length; i++)
  861. allProperties[i] = GetProperties(propertyOwners[i], property_grid.BrowsableAttributes);
  862. foreach (string propertyName in propertyNames)
  863. {
  864. PropertyDescriptor[] properties = new PropertyDescriptor[propertyOwners.Length];
  865. for (int i = 0; i < propertyOwners.Length; i++)
  866. properties[i] = allProperties[i][propertyName];
  867. items.Add(new GridEntry(property_grid, properties, this));
  868. }
  869. }
  870. return items;
  871. }
  872. private bool IsPropertyMergeable(PropertyDescriptor property)
  873. {
  874. if (property == null)
  875. return false;
  876. MergablePropertyAttribute attrib = property.Attributes[typeof(MergablePropertyAttribute)] as MergablePropertyAttribute;
  877. if (attrib != null && !attrib.AllowMerge)
  878. return false;
  879. return true;
  880. }
  881. private string[] GetMergedPropertyNames(object[] objects)
  882. {
  883. if (objects == null || objects.Length == 0)
  884. return new string[0];
  885. ArrayList intersection = new ArrayList();
  886. for (int i = 0; i < objects.Length; i++)
  887. {
  888. if (objects[i] == null)
  889. continue;
  890. PropertyDescriptorCollection properties = GetProperties(objects[i], property_grid.BrowsableAttributes);
  891. ArrayList new_intersection = new ArrayList();
  892. foreach (PropertyDescriptor currentProperty in (i == 0 ? (ICollection)properties : (ICollection)intersection))
  893. {
  894. PropertyDescriptor matchingProperty = (i == 0 ? currentProperty : properties[currentProperty.Name]);
  895. if (objects.Length > 1 && !IsPropertyMergeable(matchingProperty))
  896. continue;
  897. if (matchingProperty.PropertyType == currentProperty.PropertyType)
  898. new_intersection.Add(matchingProperty);
  899. }
  900. intersection = new_intersection;
  901. }
  902. string[] propertyNames = new string[intersection.Count];
  903. for (int i = 0; i < intersection.Count; i++)
  904. propertyNames[i] = ((PropertyDescriptor)intersection[i]).Name;
  905. return propertyNames;
  906. }
  907. private PropertyDescriptorCollection GetProperties(object propertyOwner, AttributeCollection attributes)
  908. {
  909. if (propertyOwner == null || property_grid.SelectedTab == null)
  910. return new PropertyDescriptorCollection(null);
  911. Attribute[] atts = new Attribute[attributes.Count];
  912. attributes.CopyTo(atts, 0);
  913. TypeConverter converter = GetConverter();
  914. if (converter != null)
  915. {
  916. PropertyDescriptorCollection properties = converter.GetProperties((ITypeDescriptorContext)this, propertyOwner, atts);
  917. return properties ?? new PropertyDescriptorCollection(null);
  918. }
  919. return property_grid.SelectedTab.GetProperties((ITypeDescriptorContext)this, propertyOwner, atts);
  920. }
  921. #endregion // Population
  922. }
  923. }