#if FRAMEWORK20 using System; using System.Collections.Generic; using System.Text; using DevComponents.AdvTree; using System.ComponentModel; using System.Reflection; using DevComponents.DotNetBar.Controls; using System.Drawing; using System.Windows.Forms; using System.Drawing.Design; using System.Windows.Forms.Design; using System.Drawing.Imaging; using System.Collections; using System.Threading; namespace DevComponents.DotNetBar { /// /// Represents a property node in AdvPropertyGrid. /// public class PropertyNode : Node, ITypeDescriptorContext, IWindowsFormsEditorService { #region Private Variables private const string ID_UITypeEditorImage = "UITypeEditorImage"; #endregion #region Constructors private PropertyDescriptor _Property = null; /// /// Initializes a new instance of the PropertyNode class. /// /// public PropertyNode(PropertyDescriptor property) { _Property = property; this.CellNavigationEnabled = false; PasswordPropertyTextAttribute passwordAttribute = _Property.Attributes[typeof(PasswordPropertyTextAttribute)] as PasswordPropertyTextAttribute; if (passwordAttribute != null && passwordAttribute.Password) IsPassword = true; } #endregion #region Internal Implementation public virtual void UpdateDisplayedValue() { UpdateDisplayedValue(true); } public virtual void UpdateDisplayedValue(bool refreshSubProperties) { if (_IsDisposed || _IsDisposing) return; object propertyValue = PropertyValue; UpdateDisplayedValue(propertyValue, refreshSubProperties); } protected virtual void UpdateDisplayedValue(object propertyValue) { UpdateDisplayedValue(propertyValue, true); } protected virtual void UpdateDisplayedValue(object propertyValue, bool refreshSubProperties) { if (_IsDisposed || _IsDisposing) return; // Value cell Cell cell = this.EditCell; cell.Text = GetPropertyTextValue(propertyValue); if (GetIsDefaultValue(propertyValue)) { cell.StyleNormal = EditCellStyle; } else { cell.StyleNormal = ValueChangedStyle; } RevertEditorValue(); if (IsTypeEditorPaintValueSupported) { UITypeEditor typeEditor = GetTypeEditor(); if (typeEditor != null && typeEditor.GetPaintValueSupported(this)) { Rectangle r = new Rectangle(0, 0, 20, 13); Bitmap image = new Bitmap(r.Width, r.Height, PixelFormat.Format32bppArgb); image.Tag = ID_UITypeEditorImage; using (Graphics g = Graphics.FromImage(image)) { bool error = false; try { typeEditor.PaintValue(new PaintValueEventArgs(this, propertyValue, g, r)); //typeEditor.PaintValue(propertyValue, g, r); } catch { error = true; } if (error) DisplayHelp.FillRectangle(g, r, Color.White); DisplayHelp.DrawRectangle(g, SwatchBorderColor, r); } cell.Images.Image = image; } else { if (cell.Images.Image != null && cell.Images.Image.Tag is string && (string)cell.Images.Image.Tag == ID_UITypeEditorImage) { Image image = cell.Images.Image; cell.Images.Image = null; image.Dispose(); } } } if (refreshSubProperties) { UpdateChildProperties(); //if (this.HasChildNodes && this.Expanded) // LoadChildProperties(); } } private Color _SwatchBorderColor = Color.Black; private Color SwatchBorderColor { get { return _SwatchBorderColor; } } protected virtual bool IsTypeEditorPaintValueSupported { get { return true; } } private string GetPropertyTextValue() { return GetPropertyTextValue(this.PropertyValue); } protected string GetPropertyTextValue(object propertyValue) { if (_PropertySettings != null && _PropertySettings.HasConvertPropertyValueToStringHandler) { ConvertValueEventArgs e = new ConvertValueEventArgs(null, propertyValue, GetPropertyName(), GetTargetComponent(), PropertyDescriptor); _PropertySettings.InvokeConvertPropertyValueToString(e); if (e.IsConverted && e.StringValue != null) return e.StringValue; } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null && grid.HasConvertPropertyValueToStringHandler) { ConvertValueEventArgs e = new ConvertValueEventArgs(null, propertyValue, GetPropertyName(), GetTargetComponent(), PropertyDescriptor); grid.InvokeConvertPropertyValueToString(e); if (e.IsConverted && e.StringValue != null) return e.StringValue; } string textValue = null; TypeConverter typeConverter = this.TypeConverter; try { textValue = typeConverter.ConvertToString(this, propertyValue); } catch (Exception) { } if (textValue == null) { textValue = string.Empty; } if (IsPassword) { textValue = StringHelper.Repeat(AdvPropertyGrid.PasswordChar, textValue.Length); } return textValue; } private TypeConverter _TypeConverter = null; internal virtual TypeConverter TypeConverter { get { if (_PropertySettings != null && _PropertySettings.TypeConverter != null) return _PropertySettings.TypeConverter; if (_TypeConverter == null) { _TypeConverter = GetPropertyDescriptor().Converter; } return _TypeConverter; } } public virtual Type PropertyType { get { object propertyValue = this.PropertyValue; if (propertyValue != null) { return propertyValue.GetType(); } else return _Property.PropertyType; return null; } } public virtual object PropertyValue { get { try { object propertyValue = this.GetPropertyValue(this.GetTargetComponent()); return propertyValue; } catch (Exception exception) { return exception; } } set { ApplyValue(value, null); } } protected virtual bool GetIsDefaultValue() { return GetIsDefaultValue(PropertyValue); } private bool GetIsDefaultValue(object propertyValue) { DefaultValueAttribute defaultValueAttribute = GetPropertyDescriptor().Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute; if (defaultValueAttribute != null) { if (defaultValueAttribute.Value != null) return (defaultValueAttribute.Value.Equals(propertyValue)); return defaultValueAttribute.Value == propertyValue; } if (propertyValue != null) { string strfunct = "ShouldSerialize" + GetPropertyName(); PropertyDescriptor propDesc = GetPropertyDescriptor(); if (propDesc != null && propDesc.ComponentType != null && propDesc.ComponentType.GetMethod(strfunct, BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) != null) { MethodInfo mi = propDesc.ComponentType.GetMethod(strfunct, BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); object target = GetTargetComponent(); if (mi.DeclaringType.IsInstanceOfType(target)) // If method is injected by designer code we need to detect that to avoid Invalid Target Exception from RunTimeMethodInfo.CheckConsistency { object result = mi.Invoke(GetTargetComponent(), null); if (result is bool && ((bool)result)) return false; } } } return true; } protected virtual object GetTargetComponent() { if (_TargetComponent != null) return _TargetComponent; Node node = this.Parent as Node; while (node != null) { if (node is PropertyNode) return ((PropertyNode)node).GetTargetComponent(); node = node.Parent as Node; } return _TargetComponent; } private object _TargetComponent; internal object TargetComponent { get { return _TargetComponent; } set { object oldValue = _TargetComponent; _TargetComponent = value; OnTargetComponentChanged(oldValue, value); } } private bool _PropertyChangedEventHandled = false; protected virtual void OnTargetComponentChanged(object oldValue, object newValue) { string eventName = GetPropertyName() + "Changed"; if (oldValue != null && _PropertyChangedEventHandled) { try { if (oldValue is ICustomTypeDescriptor) { EventDescriptor item = GetEventDescriptor(oldValue, eventName); if (item != null) item.RemoveEventHandler(oldValue, this.PropertyValueChangedEventHandler); } else { EventInfo info = oldValue.GetType().GetEvent(eventName); if (info != null) info.RemoveEventHandler(oldValue, this.PropertyValueChangedEventHandler); } } finally { _PropertyChangedEventHandled = false; } } if (newValue != null && GetPropertyDescriptor() != null) { // Check whether object has PropertyNameChanged event handler... if (newValue is ICustomTypeDescriptor) { EventDescriptor item = GetEventDescriptor(newValue, eventName); if (item != null) { try { item.AddEventHandler(newValue, PropertyValueChangedEventHandler); _PropertyChangedEventHandled = true; } catch { _PropertyChangedEventHandled = false; } } } else { EventInfo info = newValue.GetType().GetEvent(eventName); if (info != null && info.EventHandlerType == typeof(EventHandler)) { try { info.AddEventHandler(newValue, PropertyValueChangedEventHandler); _PropertyChangedEventHandled = true; } catch { _PropertyChangedEventHandled = false; } } } } } private EventDescriptor GetEventDescriptor(object value, string eventName) { EventDescriptorCollection col = ((ICustomTypeDescriptor)value).GetEvents(); foreach (EventDescriptor item in col) { if (item.Name == eventName) { if (item.EventType == typeof(EventHandler)) { return item; } break; } } return null; } private void PropertyValueChanged(object sender, EventArgs e) { UpdateDisplayedValue(); } private EventHandler _PropertyValueChangedEventHandler = null; private EventHandler PropertyValueChangedEventHandler { get { if (_PropertyValueChangedEventHandler == null) _PropertyValueChangedEventHandler = new EventHandler(PropertyValueChanged); return _PropertyValueChangedEventHandler; } } protected virtual object GetPropertyValue(object target) { PropertyDescriptor propertyDescriptor = GetPropertyDescriptor(); if (propertyDescriptor == null) { return null; } if (_IsMultiObject) { object[] targets = (object[])target; object returnValue = GetPropertyValueCore(targets[0], propertyDescriptor); TypeConverter converter = this.TypeConverter; for (int i = 1; i < targets.Length; i++) { object value = null; if (propertyDescriptor.ComponentType.IsAssignableFrom(targets[i].GetType())) value = GetPropertyValueCore(targets[i], propertyDescriptor); else { //PropertyDescriptor desc2 = PropertyParser.GetProperty(propertyDescriptor.Name, targets[i], converter.GetPropertiesSupported(this) ? converter : null); PropertyDescriptor desc2 = PropertyParser.GetProperty(propertyDescriptor.Name, targets[i], null); value = GetPropertyValueCore(targets[i], desc2); } if (returnValue != null && !returnValue.Equals(value) || returnValue == null && value != null) { returnValue = null; break; } } return returnValue; } else { return GetPropertyValueCore(target, propertyDescriptor); } } protected virtual object GetPropertyValueCore(object target, PropertyDescriptor propertyDescriptor) { object propertyValue; if (target is ICustomTypeDescriptor) { target = ((ICustomTypeDescriptor)target).GetPropertyOwner(propertyDescriptor); } try { propertyValue = propertyDescriptor.GetValue(target); } catch { throw; } return propertyValue; } public PropertyDescriptor PropertyDescriptor { get { return _Property; } internal set { _Property = value; UpdateValueInlineEditor(); } } protected override void OnParentChanged() { UpdateValueInlineEditor(); base.OnParentChanged(); } private bool IsEditorReadOnly { get { PropertyDescriptor propDesc = PropertyDescriptor; if (propDesc != null) return propDesc.IsReadOnly; return false; } } /// /// Releases the inline editor used by the node. /// public virtual void ReleaseInlineEditor() { UpdateValueInlineEditor(); } private bool _IsUsingInlineEditor = false; private void UpdateValueInlineEditor() { if (_IsUsingInlineEditor) { Cell editCell = this.EditCell; Control editor = editCell.HostedControl; if (editor != null) { editCell.HostedControl = null; if (editor is IPropertyValueEditor) ((IPropertyValueEditor)editor).EditValueChanged -= ValueEditorEditValueChanged; editor.Dispose(); } else if (editCell.HostedItem != null) { BaseItem item = editCell.HostedItem; editCell.HostedItem = null; if (item is IPropertyValueEditor) ((IPropertyValueEditor)item).EditValueChanged -= ValueEditorEditValueChanged; item.Dispose(); } } _IsUsingInlineEditor = false; if (_Property == null || IsDisposing) return; PropertyValueEditor valueEditor; if (_PropertySettings != null && _PropertySettings.ValueEditor != null) valueEditor = _PropertySettings.ValueEditor; else valueEditor = _Property.Attributes[typeof(PropertyValueEditor)] as PropertyValueEditor; if (valueEditor != null) { IPropertyValueEditor editorCustom = valueEditor.CreateEditor(_Property, _TargetComponent); editorCustom.EditValueChanged += ValueEditorEditValueChanged; _Editor = editorCustom; if (editorCustom is Control) { this.EditCell.HostedControl = (Control)_Editor; if (this.IsReadOnly || this.IsEditorReadOnly) this.EditCell.HostedControl.Enabled = false; } else if (editorCustom is BaseItem) { this.EditCell.HostedItem = (BaseItem)_Editor; if (this.IsReadOnly || this.IsEditorReadOnly) this.EditCell.Enabled = false; } else throw new ArgumentException("PropertyValueEditor must inherit from Control or BaseItem."); _IsUsingInlineEditor = true; } } private ElementStyle _ValueChangedStyle = null; public ElementStyle ValueChangedStyle { get { if (_ValueChangedStyle == null) { IPropertyElementStyleProvider styleProvider = StyleProvider; if (styleProvider != null) return styleProvider.ValueChangedStyle; } return _ValueChangedStyle; } set { _ValueChangedStyle = value; } } private ElementStyle _EditCellStyle = null; public ElementStyle EditCellStyle { get { if (_EditCellStyle == null) { IPropertyElementStyleProvider styleProvider = StyleProvider; if (styleProvider != null) return styleProvider.DefaultEditCellStyle; } return _EditCellStyle; } set { if (_EditCellStyle != value) { _EditCellStyle = value; UpdateDisplayedValue(); } } } object _Editor = null; protected override void OnSelected(eTreeAction action) { if (_IsDisposed || _IsDisposing) return; UpdateDisplayedValue(); AdvTree.AdvTree tree = this.TreeControl; bool focusEditor = false; Point pos = Point.Empty; if (tree != null) { pos = tree.PointToClient(Control.MousePosition); if (this.EditCell.Bounds.Contains(pos)) focusEditor = true; } if (action == eTreeAction.Keyboard && WinApi.HIWORD(WinApi.GetKeyState(9)) != 0) focusEditor = true; if (this.Enabled && (!this.IsReadOnly && CanEditPropertyContent())) { EnterEditorMode(action, focusEditor); if (focusEditor && !pos.IsEmpty && _Editor is TextBoxDropDown) { ((TextBoxDropDown)_Editor).TextBox.SelectAll(); } } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { string description = GetDescriptionAttributeValue(); if (!string.IsNullOrEmpty(description)) { bool replaceNewLineCharacters = false; if (!TextMarkup.MarkupParser.IsMarkup(ref description)) replaceNewLineCharacters = true; description = description.Replace("<", "<"); description = description.Replace(">", ">"); description = "" + this.Text + "
" + description; if (replaceNewLineCharacters) description = description.Replace("\n", "
"); } grid.HelpPanel.Text = description; } base.OnSelected(action); } private string _Description = null; private string GetDescriptionAttributeValue() { if (_PropertySettings != null && _PropertySettings.Description != null) return _PropertySettings.Description; if (_Description == null) { _Description = _Property.Description; //DescriptionAttribute att = _Property.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute; //if (att != null) // _Description = att.Description; //else // _Description = ""; } return _Description; } internal TextBoxDropDown GetEditor() { return _Editor as TextBoxDropDown; } private bool IsUsingPropertyEditor() { if (_Property != null && !_Property.PropertyType.IsPrimitive && !_Property.PropertyType.IsEnum && !(_Property.PropertyType == typeof(string))) { UITypeEditor editor = GetTypeEditor(); if (editor != null) // && (editor.GetEditStyle(this) == UITypeEditorEditStyle.Modal || editor.GetEditStyle(this) == UITypeEditorEditStyle.None) return true; } return false; } private bool CanEditPropertyContent() { if (_Property != null && !_Property.PropertyType.IsPrimitive && !_Property.PropertyType.IsEnum && !(_Property.PropertyType == typeof(string))) { UITypeEditor editor = GetTypeEditor(); if (editor != null) // && (editor.GetEditStyle(this) == UITypeEditorEditStyle.Modal || editor.GetEditStyle(this) == UITypeEditorEditStyle.None) return true; else { if (this.TypeConverter != null && this.TypeConverter.CanConvertFrom(typeof(string))) return true; return false; } } return true; } private bool _IsReadOnly = false; /// /// Gets or sets whether property text box is read only. Default value is false. /// public bool IsReadOnly { get { return _IsReadOnly; } set { if (_IsReadOnly == value) return; _IsReadOnly = value; if (_IsReadOnly) this.Style = GetReadOnlyStyle(); else this.Style = GetDefaultStyle(); OnIsReadOnlyChanged(); } } protected virtual void OnIsReadOnlyChanged() { Cell editCell = this.EditCell; if (editCell == null) return; if (editCell.HostedControl is IPropertyValueEditor) editCell.HostedControl.Enabled = !_IsReadOnly; if (editCell.HostedItem is IPropertyValueEditor) editCell.HostedItem.Enabled = !_IsReadOnly; } private ElementStyle GetReadOnlyStyle() { if (_PropertySettings != null && _PropertySettings.ReadOnlyStyle != null) return _PropertySettings.ReadOnlyStyle; IPropertyElementStyleProvider styleProvider = this.StyleProvider; if (styleProvider != null) { return styleProvider.ReadOnlyStyle; } return null; } public IPropertyElementStyleProvider StyleProvider { get { return AdvPropertyGrid as IPropertyElementStyleProvider; } } private ElementStyle GetDefaultStyle() { if (_PropertySettings != null && _PropertySettings.Style != null) return _PropertySettings.Style; return null; } protected virtual Cell EditCell { get { return this.Cells[1]; } } protected override bool CanKeyboardNavigate(KeyEventArgs e) { return !IsEditing || IsEditing && (_Editor is TextBoxDropDown && !((TextBoxDropDown)_Editor).TextBox.Focused || _Editor is IPropertyValueEditor && ((IPropertyValueEditor)_Editor).IsEditorFocused); } /// /// Gets whether node is in editing mode. /// public bool IsEditing { get { return _IsEditing; } internal set { if (_IsEditing != value) { _IsEditing = value; AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) grid.OnPropertyIsEditingChanged(this); } } } private bool _IsEditing = false; /// /// Places the node into the editing mode if possible, raises the exception if node is read-only. /// /// Action that caused the edit mode. /// Indicates whether to focus the editor. public virtual void EnterEditorMode(eTreeAction action, bool focusEditor) { if (IsEditing) throw new InvalidOperationException("Node is already in edit mode."); if (!Enabled) throw new InvalidOperationException("Node is disabled. Cannot enter edit mode."); if (_IsUsingInlineEditor) { if (_Editor is IPropertyValueEditor) ((IPropertyValueEditor)_Editor).EditValue = PropertyValue; IsEditing = true; if (focusEditor) { if (_Editor is IPropertyValueEditor) ((IPropertyValueEditor)_Editor).FocusEditor(); } EditValueChanged = false; return; } if (_Editor == null) { _Editor = CreateNodeEditor(); TextBoxDropDown editor = _Editor as TextBoxDropDown; if (editor != null) { if (IsPassword) { editor.PasswordChar = AdvPropertyGrid.PasswordChar; editor.Text = GetPropertyTextValue(); } else { editor.PasswordChar = '\0'; editor.Text = this.EditCell.Text; } } else if (_Editor is IPropertyValueEditor) { ((IPropertyValueEditor)_Editor).EditValue = PropertyValue; if (!IsReadOnly) ((Control)_Editor).Enabled = false; } ElementStyle valueChangedStyle = this.ValueChangedStyle; if (this.EditCell.StyleNormal == valueChangedStyle && valueChangedStyle.Font != null) { if (editor != null) editor.TextBox.Font = valueChangedStyle.Font; else if (_Editor is IPropertyValueEditor) ((IPropertyValueEditor)_Editor).EditorFont = valueChangedStyle.Font; } this.EditCell.HostedControl = (Control)_Editor; IsEditing = true; if (focusEditor) { if (editor != null) editor.Focus(); else if (_Editor is IPropertyValueEditor) ((IPropertyValueEditor)_Editor).FocusEditor(); } EditValueChanged = false; } } protected virtual Control CreateNodeEditor() { bool isReadOnly = GetEffectiveReadOnly(); //PropertyValueEditor valueEditor = _Property.Attributes[typeof(PropertyValueEditor)] as PropertyValueEditor; //if (valueEditor != null) //{ // IPropertyValueEditor editorCustom = valueEditor.CreateEditor(_Property, _TargetComponent); // editorCustom.EditValueChanged += ValueEditorEditValueChanged; // return (Control)editorCustom; //} TextBoxDropDown editor = new TextBoxDropDown(); if (BarUtilities.UseTextRenderer) editor.BackgroundStyle.MarginLeft = 3; AdvPropertyGrid grid = this.AdvPropertyGrid; if (grid != null) editor.Font = grid.Font; editor.Size = new Size(32, editor.PreferredHeight); editor.Visible = true; editor.TextBox.KeyDown += new KeyEventHandler(EditorKeyDown); editor.TextBox.TextChanged += new EventHandler(EditorTextChanged); editor.TextBox.ReadOnly = isReadOnly; editor.TextBox.PreventEnterBeep = true; UITypeEditor typeEditor = GetTypeEditor(); UITypeEditorEditStyle editStyle = UITypeEditorEditStyle.None; if (typeEditor != null) { editStyle = typeEditor.GetEditStyle(this); if (editStyle == UITypeEditorEditStyle.Modal) { editor.ButtonCustom.Visible = true; editor.ButtonCustomClick += new EventHandler(EditorButtonCustomClick); } else if (editStyle == UITypeEditorEditStyle.DropDown) { editor.ButtonDropDown.Visible = true; editor.ButtonDropDownClick += new CancelEventHandler(EditorButtonDropDownClick); } if (!IsReadOnly) { PropertyDescriptor propertyDescriptor = GetPropertyDescriptor(); if (propertyDescriptor != null && !propertyDescriptor.PropertyType.IsAssignableFrom(typeof(string)) && propertyDescriptor.Converter != null && !propertyDescriptor.Converter.CanConvertFrom(typeof(string))) editor.TextBox.ReadOnly = true; } } if (typeEditor == null || editStyle == UITypeEditorEditStyle.None) { if (!isReadOnly) { SetupEditorAutoCompleteList(editor); if (!SetupEditorPopup(editor)) editor.ButtonDropDown.Visible = false; else { editor.ButtonDropDown.Visible = true; } } } if (AfterEditorCreated != null) AfterEditorCreated(this, editor); return editor; } /// /// Defines delegate that is called after property editor is created. /// /// PropertyNode sender. /// Reference to editor. public delegate void AfterEditorCreatedDelegate(object sender, object editor); /// /// Called after property editor is created. /// public AfterEditorCreatedDelegate AfterEditorCreated; void ValueEditorEditValueChanged(object sender, EventArgs e) { EditValueChanged = true; if (IsEditing) ApplyEdit(); } private bool ProcessEditorDropDownClick() { UITypeEditor typeEditor = GetTypeEditor(); if (typeEditor != null && typeEditor.GetEditStyle(this) == UITypeEditorEditStyle.DropDown) { object value = typeEditor.EditValue(this, this, this.PropertyValue); ApplyValue(value, null); return true; } return false; } private void EditorButtonDropDownClick(object sender, CancelEventArgs e) { ProcessEditorDropDownClick(); e.Cancel = true; } private bool GetEffectiveReadOnly() { return this.IsReadOnly; } private UITypeEditor GetTypeEditor() { PropertyDescriptor propertyDescriptor = GetPropertyDescriptor(); if (_PropertySettings != null && _PropertySettings.UITypeEditor != null) { return _PropertySettings.UITypeEditor; } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null && grid.HasProvideUITypeEditorHandler) { ProvideUITypeEditorEventArgs args = new ProvideUITypeEditorEventArgs(GetPropertyName(), propertyDescriptor); grid.InvokeProvideUITypeEditor(args); if (args.EditorSpecified) return args.UITypeEditor; } object value = PropertyValue; if (value is ICustomTypeDescriptor) { ICustomTypeDescriptor descriptor = (ICustomTypeDescriptor)value; UITypeEditor editor = (UITypeEditor)descriptor.GetEditor(typeof(UITypeEditor)); if (editor != null) return editor; } return (UITypeEditor)propertyDescriptor.GetEditor(typeof(UITypeEditor)); } internal string PropertyName { get { return GetPropertyName(); } } protected virtual string GetPropertyName() { return GetPropertyDescriptor().Name; } protected virtual PropertyDescriptor GetPropertyDescriptor() { return _Property; } private void EditorButtonCustomClick(object sender, EventArgs e) { // Invoke this delayed and out of loop since MFC dialogs did not get focus when shown directly from this event handler. BarUtilities.InvokeDelayed(new MethodInvoker(delegate { UITypeEditor typeEditor = GetTypeEditor(); if (typeEditor == null) return; object value = null; try { value = typeEditor.EditValue(this, this, this.PropertyValue); } catch (Exception ex) { MessageBoxEx.Show(ex.Message); return; } ApplyValue(value, null); })); } protected virtual bool SetupEditorPopup(TextBoxDropDown editor) { if (this.PropertyType == null) return false; string[] items = GetPopupListContent(); if (items == null || items.Length == 0) return false; TextBoxDropDown textBox = editor; ListBox list = new ListBox(); list.SelectedIndexChanged += new EventHandler(PopupListSelectedIndexChanged); list.BorderStyle = BorderStyle.None; list.Items.AddRange(items); if (!string.IsNullOrEmpty(editor.Text)) list.SelectedItem = editor.Text; textBox.DropDownControl = list; list.Size = GetPreferredListBoxSize(ref items); return true; } private void PopupListSelectedIndexChanged(object sender, EventArgs e) { ListBox list = (ListBox)sender; if (!list.Visible || list.SelectedItem == null) return; TextBoxDropDown editor = _Editor as TextBoxDropDown; editor.Text = (string)list.SelectedItem; editor.CloseDropDown(); EditValueChanged = true; if (ApplyEdit()) { AdvTree.AdvTree tree = this.TreeControl; if (tree != null) tree.Focus(); this.SelectedCell = this.Cells[0]; } } private Size _CachedPreferredListBoxSize = Size.Empty; private int _LastCacheListBoxItemCount = -1; protected virtual Size GetPreferredListBoxSize(ref string[] items) { if (items == null || items.Length == 0) return new Size(96, 32); AdvTree.AdvTree tree = this.TreeControl; if (tree == null) return new Size(96, 32); if (!_CachedPreferredListBoxSize.IsEmpty && _LastCacheListBoxItemCount == items.Length) return _CachedPreferredListBoxSize; Size totalSize = Size.Empty; using (Graphics g = tree.CreateGraphics()) { Font font = tree.Font; for (int i = 0; i < items.Length; i++) { Size itemSize = TextDrawing.MeasureString(g, items[i], font); if (itemSize.Width == 0) itemSize.Width = this.EditCell.Bounds.Width - 8; if (itemSize.Height == 0) itemSize.Height = font.Height; totalSize.Width = Math.Max(itemSize.Width, totalSize.Width); if (totalSize.Height < 320) totalSize.Height += itemSize.Height; else { if (totalSize.Width < 120) totalSize.Width = 128; break; } } } if (totalSize.Width < this.EditCell.Bounds.Width - 8) totalSize.Width = this.EditCell.Bounds.Width - 8; _CachedPreferredListBoxSize = totalSize; _LastCacheListBoxItemCount = items.Length; return totalSize; } protected virtual string[] GetPopupListContent() { if (_PropertySettings != null && _PropertySettings.HasProvidePropertyValueListHandler) { PropertyValueListEventArgs args = new PropertyValueListEventArgs(GetPropertyName(), GetTargetComponent(), PropertyDescriptor); _PropertySettings.InvokeProvidePropertyValueList(args); if (args.IsListValid) { if (args.ValueList == null) return null; return args.ValueList.ToArray(); } } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null && grid.HasProvidePropertyValueListHandler) { PropertyValueListEventArgs args = new PropertyValueListEventArgs(GetPropertyName(), GetTargetComponent(), PropertyDescriptor); grid.InvokeProvidePropertyValueList(args); if (args.IsListValid) { if (args.ValueList == null) return null; return args.ValueList.ToArray(); } } TypeConverter converter = this.TypeConverter; if (converter != null && converter.GetStandardValuesSupported(this)) { System.ComponentModel.TypeConverter.StandardValuesCollection stdValues = converter.GetStandardValues(this); if (stdValues != null && stdValues.Count > 0) { string[] values = new string[stdValues.Count]; for (int i = 0; i < stdValues.Count; i++) { object item = stdValues[i]; values[i] = converter.ConvertToString(item); } return values; } } if (this.PropertyType.IsEnum) { return Enum.GetNames(this.PropertyType); } else if (this.PropertyType == typeof(bool)) { string[] items = new string[2]; if (converter != null && converter.CanConvertTo(typeof(string))) { items[0] = (string)converter.ConvertTo(false, typeof(string)); items[1] = (string)converter.ConvertTo(true, typeof(string)); } else { items[0] = bool.FalseString; items[1] = bool.TrueString; } return items; } return null; } protected virtual void SetupEditorAutoCompleteList(TextBoxDropDown editor) { if (this.PropertyType == null) return; TextBox textBox = editor.TextBox; TypeConverter converter = this.TypeConverter; //if (converter != null && converter.GetStandardValuesExclusive(this)) // editor.InternalReadOnly = true; //else // editor.InternalReadOnly = false; string[] items = GetPopupListContent(); if (items != null && items.Length > 0) { textBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend; textBox.AutoCompleteSource = AutoCompleteSource.CustomSource; textBox.AutoCompleteCustomSource.Clear(); textBox.AutoCompleteCustomSource.AddRange(items); if (converter != null && converter.GetStandardValuesSupported() && converter.GetStandardValuesExclusive()) textBox.ReadOnly = true; else textBox.ReadOnly = false; } } protected override void OnNodeDoubleClick(EventArgs e) { base.OnNodeDoubleClick(e); if (GetEffectiveReadOnly()) return; if (!SelectNextValue()) { if (_Editor is TextBoxDropDown) { ((TextBoxDropDown)_Editor).TextBox.SelectAll(); ((TextBoxDropDown)_Editor).Focus(); } else if (_Editor is IPropertyValueEditor) ((IPropertyValueEditor)_Editor).FocusEditor(); } } public virtual bool SelectNextValue() { string[] listArray = GetPopupListContent(); if (listArray == null || listArray.Length == 0) return false; List list = new List(listArray); string currentValue = this.EditCell.Text; if (string.IsNullOrEmpty(currentValue) || !list.Contains(currentValue)) { currentValue = list[0]; } else { int index = list.IndexOf(currentValue) + 1; if (index >= list.Count) index = 0; currentValue = list[index]; } Exception valueException = null; object value = GetValueFromString(currentValue, out valueException); if (valueException != null) return false; SetPropertyValue(this.GetTargetComponent(), value); RefreshPropertyValuesCheck(); UpdateDisplayedValue(); bool reportSuccess = AdvPropertyGrid.HighlightPropertyOnUpdate && !_IsUsingInlineEditor; if (reportSuccess) { this.IsSelectionVisible = false; StartHighlight(SuccessHighlightColor); } return true; } void EditorTextChanged(object sender, EventArgs e) { this.EditValueChanged = true; } protected virtual void EditorKeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { CancelEdit(); AdvTree.AdvTree tree = this.TreeControl; if (tree != null) tree.Focus(); this.SetSelectedCell(this.Cells[0], eTreeAction.Keyboard); } else if (e.KeyCode == Keys.Enter) { if (ApplyEdit() && !(_IsDisposed || _IsDisposing)) { this.SetSelectedCell(this.Cells[0], eTreeAction.Keyboard); AdvTree.AdvTree tree = this.TreeControl; if (tree != null) tree.Focus(); } } else if (e.KeyCode == Keys.Delete && !this.IsReadOnly && this.IsPropertyValueNullable && this.PropertyValue != null) { bool reset = true; TextBox textBox = sender as TextBox; if (textBox != null && textBox.SelectionLength != textBox.TextLength) reset = false; if (reset) ApplyValue(null, null); } } protected override void OnKeyDown(KeyEventArgs e) { if (e.KeyCode == Keys.Down && e.Modifiers == Keys.Alt) { if (!ProcessEditorDropDownClick()) { TextBoxDropDown editor = _Editor as TextBoxDropDown; if (editor != null && editor.ButtonDropDown.Visible && editor.DropDownControl != null && !editor.IsPopupOpen) editor.IsPopupOpen = true; } } base.OnKeyDown(e); } protected virtual bool IsPropertyValueNullable { get { return !_Property.PropertyType.IsValueType; } } private bool _EditValueChanged = false; public bool EditValueChanged { get { return _EditValueChanged; } set { _EditValueChanged = value; } } protected override void OnDeselected(eTreeAction action) { if (this.IsEditing) { if (this.EditValueChanged && !IsReadOnly) ApplyEdit(); ExitEditorMode(action); } base.OnDeselected(action); } /// /// Exits the editor mode. /// /// Action that caused the editor mode exit. public virtual void ExitEditorMode(eTreeAction action) { if (!IsEditing) return; Control editor = _Editor as Control; if (!_IsUsingInlineEditor) { _Editor = null; this.EditCell.HostedControl = null; } if (editor is TextBoxDropDown && !_IsUsingInlineEditor) { TextBoxDropDown editorDropDown = (TextBoxDropDown)editor; if (editorDropDown.IsPopupOpen) editorDropDown.CloseDropDown(); if (editorDropDown.DropDownControl != null && !_UITypeEditorDropDownControl) { Control c = editorDropDown.DropDownControl; editorDropDown.DropDownControl = null; c.Dispose(); } editorDropDown.ButtonCustomClick -= EditorButtonCustomClick; editorDropDown.ButtonDropDownClick -= EditorButtonDropDownClick; editorDropDown.TextBox.KeyDown -= new KeyEventHandler(EditorKeyDown); editorDropDown.TextBox.TextChanged -= new EventHandler(EditorTextChanged); editorDropDown.Dispose(); } else if (editor != null && !_IsUsingInlineEditor) { if (editor is IPropertyValueEditor) ((IPropertyValueEditor)editor).EditValueChanged -= ValueEditorEditValueChanged; editor.Dispose(); } if (_HighlightWorker != null && _HighlightWorker.IsBusy) _HighlightWorker.CancelAsync(); IsEditing = false; } /// /// Called when visual part of the node has changed due to the changes of its properties or properties of the cells contained by node. /// internal override void OnDisplayChanged() { if (!IsDisposing && !IsDisposed) base.OnDisplayChanged(); } /// /// Cancel the edit changes and applies the old property value. /// public virtual void CancelEdit() { if (!IsEditing) return; UpdateDisplayedValue(); ClearErrorMarkings(); _EditValueChanged = false; if (_HighlightWorker != null && _HighlightWorker.IsBusy) _HighlightWorker.CancelAsync(); } protected virtual void RevertEditorValue() { Cell cell = this.EditCell; if (_Editor is TextBoxDropDown) { TextBoxDropDown editor = (TextBoxDropDown)_Editor; editor.Text = cell.Text; EditValueChanged = false; ElementStyle valueChangedStyle = this.ValueChangedStyle; if (valueChangedStyle != null && cell.StyleNormal == valueChangedStyle && valueChangedStyle.Font != null) editor.TextBox.Font = valueChangedStyle.Font; else editor.TextBox.Font = null; } else if (_Editor is IPropertyValueEditor) { IPropertyValueEditor editor = (IPropertyValueEditor)_Editor; if (!object.Equals(editor.EditValue, PropertyValue)) //if (editor.EditValue != PropertyValue) editor.EditValue = PropertyValue; EditValueChanged = false; ElementStyle valueChangedStyle = this.ValueChangedStyle; if (valueChangedStyle != null && cell.StyleNormal == valueChangedStyle && valueChangedStyle.Font != null) editor.EditorFont = valueChangedStyle.Font; else editor.EditorFont = null; } } /// /// Attempts to apply current edit value to the property. /// public virtual bool ApplyEdit() { if (!IsEditing) throw new InvalidOperationException("Node is not in edit mode."); if (!EditValueChanged) return true; if (_Editor is TextBoxDropDown) return ApplyEdit(((TextBoxDropDown)_Editor).Text); else return ApplyEdit(((IPropertyValueEditor)_Editor).EditValue); } protected virtual bool ApplyEdit(object text) { Exception valueException = null; object value = null; if (text is string) value = GetValueFromString((string)text, out valueException); else value = text; return ApplyValue(value, valueException); } /// /// Returns the full property path to the root of the selected object. /// /// Full property path. public string GetPropertyPath() { string path = GetPropertyName(); Node parent = this.Parent; while (parent != null) { PropertyNode propNode = parent as PropertyNode; if (propNode != null) { if (propNode.PropertyDescriptor != null) path = propNode.GetPropertyName() + "." + path; } parent = parent.Parent; } return path; } protected virtual bool ApplyValue(object value, Exception valueException) { bool valueApplied = false; if (GetPropertyValue(GetTargetComponent()) == value && valueException == null) return true; if (valueException == null) { AdvPropertyGrid grid = this.AdvPropertyGrid; if (grid != null) { valueApplied = grid.InvokePropertyValueChanging(GetPropertyName(), value, _Property, GetPropertyPath()); } if (!valueApplied) { try { SetPropertyValue(this.GetTargetComponent(), value); valueApplied = true; if (_IsDisposed || _IsDisposing) return true; } catch (Exception e) { valueException = e; } } } if (!valueApplied) { // Set error state... if (_PropertySettings == null || _PropertySettings.Image == null) this.Image = GetErrorImage(); this.IsSelectionVisible = false; // Get SuperTooltip to display error tip SuperTooltip tooltip = GetSuperTooltip(); if (tooltip != null) AttachErrorTooltip(tooltip, valueException, value); StartHighlight(ErrorHighlightColor); } else { // if for some reason property value was not set we'll return false if (value != null && !value.Equals(PropertyValue) && PropertyType.IsPrimitive) valueApplied = false; bool reportSuccess = AdvPropertyGrid.HighlightPropertyOnUpdate && !_IsUsingInlineEditor; if (_ErrorTooltipAttached) reportSuccess = true; ClearErrorMarkings(); UpdateDisplayedValue(); if (reportSuccess) this.IsSelectionVisible = false; if (reportSuccess && valueApplied) StartHighlight(SuccessHighlightColor); _EditValueChanged = false; if (_Property != null && valueApplied) { RefreshPropertyValuesCheck(); } } return valueApplied; } private void RefreshPropertyValuesCheck() { if (_Property == null) return; RefreshPropertiesAttribute refreshAttribute = GetRefreshPropertiesAttribute(); RefreshPropertiesAttribute parentRefresh = null; if (this.Parent is PropertyNode) parentRefresh = ((PropertyNode)this.Parent).GetRefreshPropertiesAttribute(); if (parentRefresh != null && parentRefresh.RefreshProperties == RefreshProperties.All) { AdvPropertyGrid.RefreshPropertyValues(this.Parent); } else if (refreshAttribute != null) { if (refreshAttribute.RefreshProperties == RefreshProperties.Repaint) { AdvPropertyGrid.RefreshPropertyValues(); } else if (refreshAttribute.RefreshProperties == RefreshProperties.All) { AdvPropertyGrid.RefreshProperties(); } } if (this.Parent is PropertyNode) ((PropertyNode)this.Parent).UpdateDisplayedValue(false); } internal RefreshPropertiesAttribute GetRefreshPropertiesAttribute() { RefreshPropertiesAttribute refreshAttribute = _Property.Attributes[typeof(RefreshPropertiesAttribute)] as RefreshPropertiesAttribute; return refreshAttribute; } private Color ErrorHighlightColor { get { AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { return grid.Appearance.ErrorHighlightColor; } return ColorScheme.GetColor(0xD99694); } } private Color SuccessHighlightColor { get { AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { return grid.Appearance.SuccessHighlightColor; } return ColorScheme.GetColor(0x9BBB59); } } private void ClearErrorMarkings() { SuperTooltip tooltip = GetSuperTooltip(); if (tooltip != null) EraseErrorTooltip(tooltip); if (_PropertySettings == null || _PropertySettings.Image == null) this.Image = null; if (_PropertySettings != null) UpdatePropertySettings(); } private bool _ErrorTooltipAttached = false; private void AttachErrorTooltip(SuperTooltip tooltip, Exception valueException, object value) { SuperTooltipInfo info = new SuperTooltipInfo(); info.HeaderText = this.Text; string s = GetErrorString(); bool showTooltip = false; if (valueException is InvalidPropertyValueException && !string.IsNullOrEmpty(valueException.Message)) { s = valueException.Message; showTooltip = true; } else if (valueException != null) { if (!s.EndsWith(" ")) s += " "; s += valueException.Message; } info.BodyText = s; AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { grid.InvokePrepareErrorSuperTooltip(info, GetPropertyName(), valueException, value); } tooltip.SetSuperTooltip(this, info); if (showTooltip) { // Show tooltip below the node Rectangle r = this.Cells[0].Bounds; AdvTree.AdvTree tree = this.TreeControl; if (tree != null) r.Location = tree.PointToScreen(r.Location); tooltip.ShowTooltip(this, new Point(r.Right - 18, r.Bottom)); } _ErrorTooltipAttached = true; } private string GetErrorString() { string s = "Error setting the value. "; AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) s = grid.SystemText.ErrorSettingPropertyValueTooltip; IPropertyGridLocalizer localizer = this.PropertyGridLocalizer; if (localizer != null) { return localizer.GetErrorTooltipMessage(s) ?? s; } return s ?? ""; } private void EraseErrorTooltip(SuperTooltip tooltip) { tooltip.HideTooltip(); tooltip.SetSuperTooltip(this, null); _ErrorTooltipAttached = false; } private Image _ErrorImage = null; private Image GetErrorImage() { AdvPropertyGrid propertyGrid = this.AdvPropertyGrid; if (propertyGrid != null && propertyGrid.Appearance.PropertyValueErrorImage != null) return propertyGrid.Appearance.PropertyValueErrorImage; if (_ErrorImage == null) _ErrorImage = BarFunctions.LoadBitmap("SystemImages.ErrorIcon.png"); return _ErrorImage; } private BackgroundWorker _HighlightWorker = null; private ElementStyle _HighlightStyle = null; /// /// Starts fade background color style highlight for the property node. /// /// Specifies the fade background color. public void StartHighlight(Color color) { if (_HighlightWorker == null) { _HighlightWorker = new BackgroundWorker(); _HighlightWorker.WorkerSupportsCancellation = true; _HighlightWorker.DoWork += new DoWorkEventHandler(HighlightWorkerDoWork); _HighlightWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(HighlightWorkerCompleted); if (this.Style != null) { _HighlightStyle = this.Style.Copy(); } else { AdvTree.AdvTree tree = this.TreeControl; if (tree != null && tree.NodeStyle != null) _HighlightStyle = tree.NodeStyle.Copy(); else _HighlightStyle = new ElementStyle(); } } else if (_HighlightWorker.IsBusy) { _HighlightWorker.CancelAsync(); return; } _HighlightStyle.BackColor = color; this.Style = _HighlightStyle; _HighlightWorker.RunWorkerAsync(this.TreeControl); } private SuperTooltip GetSuperTooltip() { AdvPropertyGrid grid = this.AdvPropertyGrid; if (grid != null) return grid.SuperTooltip; return null; } internal void SetHelpTooltip(SuperTooltip superTooltip) { string description = GetDescriptionAttributeValue(); if (string.IsNullOrEmpty(description)) superTooltip.SetSuperTooltip(this, null); else { SuperTooltipInfo info = new SuperTooltipInfo(this.Text, "", description, null, null, eTooltipColor.System, true, false, Size.Empty); superTooltip.SetSuperTooltip(this, info); } } private void HighlightWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { this.Style = GetDefaultStyle(); this.IsSelectionVisible = true; } private void HighlightWorkerDoWork(object sender, DoWorkEventArgs e) { for (int i = 255; i > 0; i -= 25) { if (e.Cancel) break; Control control = e.Argument as Control; if (control.IsHandleCreated && !control.IsDisposed) control.BeginInvoke(new ChangeHighlightStyleDelegate(ChangeHighlightStyle), new object[] { i }); try { using ( System.Threading.ManualResetEvent wait = new System.Threading.ManualResetEvent(false)) wait.WaitOne(80); //Thread.Sleep(80); } catch { break; } } } private void ChangeHighlightStyle(int alpha) { _HighlightStyle.BackColor = Color.FromArgb(alpha, _HighlightStyle.BackColor.R, _HighlightStyle.BackColor.G, _HighlightStyle.BackColor.B); } private delegate void ChangeHighlightStyleDelegate(int alpha); protected virtual object GetValueFromString(string text, out Exception exception) { object value = null; exception = null; if (_PropertySettings != null && _PropertySettings.HasConvertFromStringToPropertyValueHandler) { ConvertValueEventArgs args = new ConvertValueEventArgs(text, null, GetPropertyName(), GetTargetComponent(), PropertyDescriptor); try { _PropertySettings.InvokeConvertFromStringToPropertyValue(args); } catch (Exception e) { exception = e; } if (args.IsConverted) return args.TypedValue; } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null && grid.HasConvertFromStringToPropertyValueHandler) { ConvertValueEventArgs args = new ConvertValueEventArgs(text, null, GetPropertyName(), GetTargetComponent(), PropertyDescriptor); try { grid.InvokeConvertFromStringToPropertyValue(args); } catch (Exception e) { exception = e; } if (args.IsConverted) return args.TypedValue; } TypeConverter conv = this.TypeConverter; try { value = conv.ConvertFromString(this, text); } catch (Exception e) { exception = e; } return value; } protected virtual void SetPropertyValue(object target, object value) { PropertyDescriptor propertyDescriptor = GetPropertyDescriptor(); if (propertyDescriptor == null) { return; } if (_IsMultiObject) { TypeConverter converter = this.TypeConverter; object[] targets = (object[])target; foreach (object item in targets) { if (propertyDescriptor.PropertyType.IsAssignableFrom(item.GetType())) SetPropertyValueCore(item, value, propertyDescriptor); else { PropertyDescriptor desc2 = PropertyParser.GetProperty(propertyDescriptor.Name, item, converter.GetPropertiesSupported(this) ? converter : null); if (desc2 == null) desc2 = PropertyParser.GetProperty(propertyDescriptor.Name, item, null); SetPropertyValueCore(item, value, desc2); } } } else { SetPropertyValueCore(target, value, propertyDescriptor); } } private void ValidatePropertyValue(object target, object value, PropertyDescriptor propertyDescriptor) { AdvPropertyGrid pg = this.AdvPropertyGrid; if (pg == null) return; if (!pg.HasValidatePropertyValueHandlers) return; ValidatePropertyValueEventArgs args = new ValidatePropertyValueEventArgs(propertyDescriptor.Name, value, target); pg.InvokeValidatePropertyValue(args); if (args.Cancel) throw new InvalidPropertyValueException(args.Message); } protected virtual void SetPropertyValueCore(object target, object value, PropertyDescriptor propertyDescriptor) { ValidatePropertyValue(target, value, propertyDescriptor); bool useCreateInstance = false; PropertyNode parent = this.Parent as PropertyNode; if (parent != null) { TypeConverter parentConverter = parent.TypeConverter; if (parentConverter != null && parentConverter.GetCreateInstanceSupported(this)) useCreateInstance = true; } if (useCreateInstance) { if (target is ICustomTypeDescriptor) { target = ((ICustomTypeDescriptor)target).GetPropertyOwner(propertyDescriptor); } object valueOwner = parent.GetTargetComponent(); TypeConverter parentTypeConverter = parent.TypeConverter; PropertyDescriptorCollection properties = parentTypeConverter.GetProperties(parent, valueOwner); Dictionary propertyValues = new Dictionary(properties.Count); object newValueInstance = null; for (int i = 0; i < properties.Count; i++) { string propertyName = GetPropertyName(); if (propertyName != null && propertyName.Equals(properties[i].Name)) { propertyValues[properties[i].Name] = value; } else { propertyValues[properties[i].Name] = properties[i].GetValue(target); } } try { newValueInstance = parentTypeConverter.CreateInstance(parent, propertyValues); } catch (Exception exception) { if (string.IsNullOrEmpty(exception.Message)) { throw new TargetInvocationException("Exception Creating New Instance Of Object For Property " + this.Text + " " + parent.PropertyType.FullName + " " + exception.ToString(), exception); } throw; } if (newValueInstance != null) { parent.PropertyValue = newValueInstance; } } else { if (target is ICustomTypeDescriptor) { target = ((ICustomTypeDescriptor)target).GetPropertyOwner(propertyDescriptor); } try { propertyDescriptor.SetValue(target, value); } catch { throw; } } AdvPropertyGrid grid = this.AdvPropertyGrid; if (grid != null) grid.InvokePropertyValueChanged(GetPropertyName(), value, null); } private bool _IsDisposing; internal bool IsDisposing { get { return _IsDisposing; } set { _IsDisposing = value; } } internal bool IsDisposed { get { return _IsDisposed; } } private bool _IsDisposed = false; protected override void Dispose(bool disposing) { _IsDisposed = true; if (this.IsEditing) CancelEdit(); BackgroundWorker worker = _HighlightWorker; _HighlightWorker = null; if (worker != null) worker.Dispose(); if (_ErrorImage != null) _ErrorImage.Dispose(); base.Dispose(disposing); } protected virtual AdvPropertyGrid AdvPropertyGrid { get { AdvTree.AdvTree tree = this.TreeControl; if (tree == null) return null; Control parent = tree.Parent; while (parent != null) { if (parent is AdvPropertyGrid) return (AdvPropertyGrid)parent; parent = parent.Parent; } return null; } } internal virtual void OnLoaded() { UpdateChildProperties(); UpdatePropertySettings(); } private void UpdateChildProperties() { if (HasChildProperties) { this.ExpandVisibility = eNodeExpandVisibility.Visible; if (this.Expanded) LoadChildProperties(); } else { if (this.HasChildNodes) { AdvPropertyGrid propertyGrid = AdvPropertyGrid; foreach (Node child in this.Nodes) AdvPropertyGrid.ClearPropertyNode(child, propertyGrid); this.Nodes.Clear(); } this.Expanded = false; this.ExpandVisibility = eNodeExpandVisibility.Auto; } } public bool HasChildProperties { get { TypeConverter converter = this.TypeConverter; if (converter != null && converter.GetPropertiesSupported()) { PropertyDescriptorCollection childProps = PropertyParser.GetProperties(this, AttributeFilter, this.PropertyValue, converter.GetPropertiesSupported(this) ? converter : null); if (childProps != null && childProps.Count > 0) return true; } return false; } } protected virtual Attribute[] AttributeFilter { get { AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { Attribute[] attributes = new Attribute[grid.BrowsableAttributes.Count]; grid.BrowsableAttributes.CopyTo(attributes, 0); return attributes; } return null; } } protected virtual void LoadChildProperties() { string lastSelectedProperty = null; AdvTree.AdvTree tree = this.TreeControl; ePropertySort childPropertySort = ePropertySort.Alphabetical; if (tree != null) { tree.BeginUpdate(); if (tree.Parent is AdvPropertyGrid) childPropertySort = ((AdvPropertyGrid)tree.Parent).SubPropertiesDefaultSort; } try { if (this.HasChildNodes) { if (tree != null && tree.SelectedNode != null && this.Nodes.Contains(tree.SelectedNode)) lastSelectedProperty = tree.SelectedNode.Text; } ClearChildNodes(); TypeConverter converter = this.TypeConverter; if (converter != null && converter.GetPropertiesSupported()) { Attribute[] attributes = AttributeFilter; List ignoredProperties = this.IgnoredProperties; List ignoredCategories = this.IgnoredCategories; IPropertyGridLocalizer localizer = this.PropertyGridLocalizer; PropertyDescriptorCollection childProps = PropertyParser.GetProperties(this, attributes, this.PropertyValue, converter.GetPropertiesSupported(this) ? converter : null); PropertyNodeFactory factory = this.NodeFactory; if (childProps != null && childProps.Count > 0) { PropertyParser parser = new PropertyParser( this, this.PropertyValue, attributes, factory, ignoredProperties, ignoredCategories, localizer, this.PropertySettingsCollection); parser.HelpType = AdvPropertyGrid.HelpType; parser.TypeConverter = converter.GetPropertiesSupported(this) ? converter : null; parser.Parse(this.Nodes, childPropertySort, GetSuperTooltip()); } } if (!string.IsNullOrEmpty(lastSelectedProperty) && this.HasChildNodes && tree != null) { foreach (Node item in this.Nodes) { if (item.Text == lastSelectedProperty) { tree.SelectedNode = item; break; } } } } finally { if (tree != null) tree.EndUpdate(); } } private void ClearChildNodes() { if (!this.HasChildNodes) return; AdvPropertyGrid propertyGrid = AdvPropertyGrid; foreach (Node item in this.Nodes) { AdvPropertyGrid.ClearPropertyNode(item, propertyGrid); if (item.IsSelected && propertyGrid.PropertyTree != null) propertyGrid.PropertyTree.SelectedNode = null; } this.Nodes.Clear(); } internal PropertyNodeFactory NodeFactory { get { AdvPropertyGrid grid = this.AdvPropertyGrid; if (grid != null) return grid.GetPropertyNodeFactory(); else return new PropertyNodeFactory(null); } } public IPropertyGridLocalizer PropertyGridLocalizer { get { return AdvPropertyGrid; } } public PropertySettingsCollection PropertySettingsCollection { get { AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) return grid.PropertySettings; return null; } } private PropertySettings _PropertySettings = null; /// /// Gets or sets the property settings that are applied to this property node. /// public PropertySettings PropertySettings { get { return _PropertySettings; } set { if (_PropertySettings == value) return; if (_PropertySettings != null) _PropertySettings.PropertyChanged -= new PropertyChangedEventHandler(PropertySettingsChanged); _PropertySettings = value; if (_PropertySettings != null) _PropertySettings.PropertyChanged += new PropertyChangedEventHandler(PropertySettingsChanged); UpdateValueInlineEditor(); } } private void PropertySettingsChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != PropertySettings.NamePropertyName && e.PropertyName != PropertySettings.NamePropertyDescriptor) UpdatePropertySettings(); if (e.PropertyName == "ValueEditor") UpdateValueInlineEditor(); } private bool IsCollection { get { if (_Property == null) return false; if (_Property.PropertyType.GetInterface("IList") != null && !_Property.PropertyType.IsArray && _Property.IsReadOnly) return true; return false; } } /// /// Applies PropertySettings to this node. /// public virtual void UpdatePropertySettings() { bool parentCreateInstanceSupported = false; TypeConverter parentConverter = null; if (this.Parent is PropertyNode) { PropertyNode parent = (PropertyNode)this.Parent; parentConverter = parent.TypeConverter; if (parentConverter != null && parentConverter.GetCreateInstanceSupported(this)) parentCreateInstanceSupported = true; } if (_PropertySettings == null) { if (!this.Visible) this.Visible = true; bool readOnlyAtt = false; if (parentConverter == null | !parentCreateInstanceSupported) readOnlyAtt = PropertyParser.GetReadOnlyAttribute(_Property, this.GetTargetComponent()); if (readOnlyAtt && !IsCollection) this.IsReadOnly = readOnlyAtt; else if (parentCreateInstanceSupported || IsUsingPropertyEditor()) this.IsReadOnly = false; this.Text = GetDefaultPropertyName(); this.ImageAlignment = eCellPartAlignment.FarCenter; this.Image = null; if (!_ErrorTooltipAttached) { SuperTooltip tooltip = GetSuperTooltip(); if (tooltip != null) { tooltip.SetSuperTooltip(this, null); } } return; } if (this.Visible != _PropertySettings.Visible) this.Visible = _PropertySettings.Visible; if (this.IsReadOnly != _PropertySettings.ReadOnly) this.IsReadOnly = _PropertySettings.ReadOnly; else if (!_ErrorTooltipAttached && !this.IsReadOnly) this.Style = GetDefaultStyle(); if (!_ErrorTooltipAttached && this.IsReadOnly && _PropertySettings.ReadOnlyTooltip != null) { SuperTooltip tooltip = GetSuperTooltip(); if (tooltip != null) { tooltip.SetSuperTooltip(this, _PropertySettings.ReadOnlyTooltip); } } if (_PropertySettings.Image != null) { this.Image = _PropertySettings.Image; this.ImageAlignment = _PropertySettings.ImageAlignment; } else { this.ImageAlignment = eCellPartAlignment.FarCenter; this.Image = null; } if (!string.IsNullOrEmpty(_PropertySettings.DisplayName)) this.Text = _PropertySettings.DisplayName; else this.Text = GetDefaultPropertyName(); if (!_ErrorTooltipAttached && _PropertySettings.Tooltip != null && !(_PropertySettings.ReadOnly && _PropertySettings.ReadOnlyTooltip != null)) { SuperTooltip tooltip = GetSuperTooltip(); if (tooltip != null) { tooltip.SetSuperTooltip(this, _PropertySettings.Tooltip); } } } private string GetDefaultPropertyName() { string text = _Property.DisplayName; IPropertyGridLocalizer localizer = this.PropertyGridLocalizer; if (localizer != null) { string name = localizer.GetPropertyName(_Property.Name); if (!string.IsNullOrEmpty(name)) text = name; } return text; } public List IgnoredCategories { get { List categories = new List(); AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { categories.AddRange(grid.IgnoredCategories); } return categories; } } public List IgnoredProperties { get { List props = new List(); AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { props.AddRange(grid.IgnoredProperties); } return props; } } protected override void OnExpandChanging(bool expanded, eTreeAction action) { if (expanded) { LoadChildProperties(); } base.OnExpandChanging(expanded, action); } private bool _IsMultiObject = false; /// /// Gets or sets whether property node represents property for multiple objects. /// public bool IsMultiObject { get { return _IsMultiObject; } internal set { _IsMultiObject = value; } } protected override void OnKeyboardCopy(KeyEventArgs args) { Clipboard.SetText(this.EditCell.Text); base.OnKeyboardCopy(args); } protected override void OnKeyboardPaste(KeyEventArgs args) { if (Clipboard.ContainsText() && !this.IsReadOnly) { ApplyEdit(Clipboard.GetText()); } base.OnKeyboardPaste(args); } private bool _IsPassword = false; /// /// Gets or sets whether property is password property which value is not displayed as plain text. /// public bool IsPassword { get { return _IsPassword; } set { _IsPassword = value; } } #endregion #region ITypeDescriptorContext Members public virtual IComponent Component { get { object valueOwner = GetTargetComponent(); if (valueOwner is IComponent) { return (IComponent)valueOwner; } return null; } } IContainer ITypeDescriptorContext.Container { get { IComponent component = this.Component; if (component != null) { ISite site = component.Site; if (site != null) { return site.Container; } } return null; } } object ITypeDescriptorContext.Instance { get { return GetTargetComponent(); } } void ITypeDescriptorContext.OnComponentChanged() { } bool ITypeDescriptorContext.OnComponentChanging() { return true; } PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get { return GetPropertyDescriptor(); } } #endregion #region IServiceProvider Members object IServiceProvider.GetService(Type serviceType) { //Console.WriteLine(serviceType); if (serviceType == typeof(PropertyNode) || serviceType == typeof(IWindowsFormsEditorService)) { return this; } AdvPropertyGrid grid = AdvPropertyGrid; if (grid != null) { if (grid.Site != null) return grid.Site.GetService(serviceType); if (grid.Parent != null && grid.Parent.Site != null) return grid.Parent.Site.GetService(serviceType); } return null; } #endregion #region IWindowsFormsEditorService Members void IWindowsFormsEditorService.CloseDropDown() { TextBoxDropDown editor = _Editor as TextBoxDropDown; if (editor != null && editor.IsPopupOpen) editor.CloseDropDown(); } private bool _UITypeEditorDropDownControl = false; [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, ExactSpelling = true)] private static extern int MsgWaitForMultipleObjectsEx(int nCount, IntPtr pHandles, int dwMilliseconds, int dwWakeMask, int dwFlags); void IWindowsFormsEditorService.DropDownControl(Control control) { Type type = typeof(Application); TextBoxDropDown editor = _Editor as TextBoxDropDown; MethodInfo mi = type.GetMethod("DoEventsModal", BindingFlags.Static | BindingFlags.NonPublic); if (mi == null || editor == null) return; editor.DropDownControl = control; _UITypeEditorDropDownControl = true; editor.ShowDropDown(); while (editor != null && editor.IsPopupOpen) { mi.Invoke(null, null); MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 250, 0xff, 4); } if (editor != null) { editor.ProcessMouseUpOnGroup(); editor.DropDownControl = null; } _UITypeEditorDropDownControl = false; } DialogResult IWindowsFormsEditorService.ShowDialog(Form dialog) { return dialog.ShowDialog(); } #endregion } /// /// Defines an interface that is implemented by the control that will be used by AdvPropertyGrid control to edit property value. /// public interface IPropertyValueEditor { /// /// Gets or sets the font used by the edit part of the control. Font might be used to visually indicate that property value has changed. Implementing this property is optional. /// Font EditorFont { get;set;} /// /// Gets whether the edit part of the control is focused. /// bool IsEditorFocused { get;} /// /// Focus the edit part of the control. /// void FocusEditor(); /// /// Gets or sets the value being edited. /// object EditValue { get;set;} /// /// Occurs when EditValue changes. Raising this even will cause the property value to be updated with the EditValue. /// event EventHandler EditValueChanged; } /// /// Defines exception which is thrown when property value fails the validation in AdvPropertyGrid.ValidatePropertyValue event. /// public class InvalidPropertyValueException : Exception { /// /// Initializes a new instance of the InvalidPropertyValueException class. /// public InvalidPropertyValueException(string message) : base(message) { } } } #endif