2502 lines
91 KiB
C#

#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
{
/// <summary>
/// Represents a property node in AdvPropertyGrid.
/// </summary>
public class PropertyNode : Node, ITypeDescriptorContext, IWindowsFormsEditorService
{
#region Private Variables
private const string ID_UITypeEditorImage = "UITypeEditorImage";
#endregion
#region Constructors
private PropertyDescriptor _Property = null;
/// <summary>
/// Initializes a new instance of the PropertyNode class.
/// </summary>
/// <param name="property"></param>
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;
}
}
/// <summary>
/// Releases the inline editor used by the node.
/// </summary>
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("<", "&lt;"); description = description.Replace(">", "&gt;");
description = "<b>" + this.Text + "</b><br/>" + description;
if (replaceNewLineCharacters)
description = description.Replace("\n", "<br/>");
}
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;
/// <summary>
/// Gets or sets whether property text box is read only. Default value is false.
/// </summary>
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);
}
/// <summary>
/// Gets whether node is in editing mode.
/// </summary>
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;
/// <summary>
/// Places the node into the editing mode if possible, raises the exception if node is read-only.
/// </summary>
/// <param name="action">Action that caused the edit mode.</param>
/// <param name="focusEditor">Indicates whether to focus the editor.</param>
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;
}
/// <summary>
/// Defines delegate that is called after property editor is created.
/// </summary>
/// <param name="sender">PropertyNode sender.</param>
/// <param name="editor">Reference to editor.</param>
public delegate void AfterEditorCreatedDelegate(object sender, object editor);
/// <summary>
/// Called after property editor is created.
/// </summary>
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<string> list = new List<string>(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);
}
/// <summary>
/// Exits the editor mode.
/// </summary>
/// <param name="action">Action that caused the editor mode exit.</param>
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;
}
/// <summary>
/// Called when visual part of the node has changed due to the changes of its properties or properties of the cells contained by node.
/// </summary>
internal override void OnDisplayChanged()
{
if (!IsDisposing && !IsDisposed)
base.OnDisplayChanged();
}
/// <summary>
/// Cancel the edit changes and applies the old property value.
/// </summary>
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;
}
}
/// <summary>
/// Attempts to apply current edit value to the property.
/// </summary>
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);
}
/// <summary>
/// Returns the full property path to the root of the selected object.
/// </summary>
/// <returns>Full property path.</returns>
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;
/// <summary>
/// Starts fade background color style highlight for the property node.
/// </summary>
/// <param name="color">Specifies the fade background color.</param>
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<string, object> propertyValues = new Dictionary<string, object>(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<string> ignoredProperties = this.IgnoredProperties;
List<string> 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;
/// <summary>
/// Gets or sets the property settings that are applied to this property node.
/// </summary>
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;
}
}
/// <summary>
/// Applies PropertySettings to this node.
/// </summary>
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<string> IgnoredCategories
{
get
{
List<string> categories = new List<string>();
AdvPropertyGrid grid = AdvPropertyGrid;
if (grid != null)
{
categories.AddRange(grid.IgnoredCategories);
}
return categories;
}
}
public List<string> IgnoredProperties
{
get
{
List<string> props = new List<string>();
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;
/// <summary>
/// Gets or sets whether property node represents property for multiple objects.
/// </summary>
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;
/// <summary>
/// Gets or sets whether property is password property which value is not displayed as plain text.
/// </summary>
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
}
/// <summary>
/// Defines an interface that is implemented by the control that will be used by AdvPropertyGrid control to edit property value.
/// </summary>
public interface IPropertyValueEditor
{
/// <summary>
/// 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.
/// </summary>
Font EditorFont { get;set;}
/// <summary>
/// Gets whether the edit part of the control is focused.
/// </summary>
bool IsEditorFocused { get;}
/// <summary>
/// Focus the edit part of the control.
/// </summary>
void FocusEditor();
/// <summary>
/// Gets or sets the value being edited.
/// </summary>
object EditValue { get;set;}
/// <summary>
/// Occurs when EditValue changes. Raising this even will cause the property value to be updated with the EditValue.
/// </summary>
event EventHandler EditValueChanged;
}
/// <summary>
/// Defines exception which is thrown when property value fails the validation in AdvPropertyGrid.ValidatePropertyValue event.
/// </summary>
public class InvalidPropertyValueException : Exception
{
/// <summary>
/// Initializes a new instance of the InvalidPropertyValueException class.
/// </summary>
public InvalidPropertyValueException(string message)
: base(message)
{
}
}
}
#endif