Initial commit
This commit is contained in:
155
Shackle/DynamicDescriptor.cs
Normal file
155
Shackle/DynamicDescriptor.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace UnshackleGUI
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the object assigned to PropertyGrid.SelectedObject
|
||||
/// It correctly implements ICustomTypeDescriptor.
|
||||
/// </summary>
|
||||
public class DynamicObject : ICustomTypeDescriptor
|
||||
{
|
||||
private readonly Dictionary<string, object> _values;
|
||||
private readonly List<UnshackleParameter> _defs;
|
||||
|
||||
public DynamicObject(Dictionary<string, object> values, List<UnshackleParameter> defs)
|
||||
{
|
||||
_values = values;
|
||||
_defs = defs;
|
||||
}
|
||||
|
||||
public PropertyDescriptorCollection GetProperties()
|
||||
{
|
||||
return new DynamicCustomTypeDescriptor(_values, _defs).GetProperties();
|
||||
}
|
||||
|
||||
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
|
||||
{
|
||||
return GetProperties();
|
||||
}
|
||||
|
||||
public object GetPropertyOwner(PropertyDescriptor pd) => this;
|
||||
|
||||
public AttributeCollection GetAttributes() => AttributeCollection.Empty;
|
||||
public string GetClassName() => nameof(DynamicObject);
|
||||
public string GetComponentName() => null;
|
||||
public TypeConverter GetConverter() => null;
|
||||
public EventDescriptor GetDefaultEvent() => null;
|
||||
public PropertyDescriptor GetDefaultProperty() => null;
|
||||
public object GetEditor(Type editorBaseType) => null;
|
||||
public EventDescriptorCollection GetEvents() => EventDescriptorCollection.Empty;
|
||||
public EventDescriptorCollection GetEvents(Attribute[] attributes) => EventDescriptorCollection.Empty;
|
||||
}
|
||||
|
||||
internal class DynamicCustomTypeDescriptor : CustomTypeDescriptor
|
||||
{
|
||||
private readonly Dictionary<string, object> _values;
|
||||
private readonly List<UnshackleParameter> _defs;
|
||||
private PropertyDescriptorCollection _cache;
|
||||
|
||||
public DynamicCustomTypeDescriptor(Dictionary<string, object> values, List<UnshackleParameter> defs)
|
||||
{
|
||||
_values = values;
|
||||
_defs = defs;
|
||||
}
|
||||
|
||||
public override PropertyDescriptorCollection GetProperties()
|
||||
{
|
||||
return GetProperties(null);
|
||||
}
|
||||
|
||||
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
|
||||
{
|
||||
if (_cache == null)
|
||||
{
|
||||
var props = new List<PropertyDescriptor>();
|
||||
|
||||
foreach (var def in _defs)
|
||||
{
|
||||
props.Add(new DynamicPropertyDescriptor(def, _values));
|
||||
}
|
||||
|
||||
_cache = new PropertyDescriptorCollection(props.ToArray());
|
||||
}
|
||||
|
||||
return _cache;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DynamicPropertyDescriptor : PropertyDescriptor
|
||||
{
|
||||
private readonly UnshackleParameter _parameter;
|
||||
private readonly Dictionary<string, object> _values;
|
||||
|
||||
public DynamicPropertyDescriptor(UnshackleParameter parameter, Dictionary<string, object> values)
|
||||
: base(parameter.Name, null)
|
||||
{
|
||||
_parameter = parameter;
|
||||
_values = values;
|
||||
}
|
||||
|
||||
public override string Category => _parameter.Category;
|
||||
|
||||
// IMPORTANT FIX
|
||||
public override Type ComponentType => typeof(object);
|
||||
|
||||
public override bool IsReadOnly => false;
|
||||
|
||||
public override Type PropertyType =>
|
||||
_parameter.Type switch
|
||||
{
|
||||
"Bool" => typeof(bool),
|
||||
"Number" => typeof(int),
|
||||
_ => typeof(string)
|
||||
};
|
||||
|
||||
public override TypeConverter Converter =>
|
||||
(_parameter.Type == "Selection" && _parameter.Options != null)
|
||||
? new StandardValuesConverter(_parameter.Options)
|
||||
: base.Converter;
|
||||
|
||||
public override object GetValue(object component)
|
||||
{
|
||||
return _values.ContainsKey(_parameter.Name)
|
||||
? _values[_parameter.Name]
|
||||
: _parameter.Default;
|
||||
}
|
||||
|
||||
public override void SetValue(object component, object value)
|
||||
{
|
||||
_values[_parameter.Name] = value;
|
||||
|
||||
OnValueChanged(component, EventArgs.Empty);
|
||||
|
||||
// Force grid refresh
|
||||
TypeDescriptor.Refresh(component);
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component) => true;
|
||||
|
||||
public override void ResetValue(object component)
|
||||
{
|
||||
_values[_parameter.Name] = _parameter.Default;
|
||||
}
|
||||
|
||||
public override bool ShouldSerializeValue(object component) => true;
|
||||
}
|
||||
|
||||
internal class StandardValuesConverter : TypeConverter
|
||||
{
|
||||
private readonly List<string> _values;
|
||||
|
||||
public StandardValuesConverter(List<string> values)
|
||||
{
|
||||
_values = values;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) => true;
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
{
|
||||
return new StandardValuesCollection(_values);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user