2502 lines
91 KiB
C#
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("<", "<"); description = description.Replace(">", ">");
|
|
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 |