Этот вопрос (Как создать редактор PropertyGrid, который ограничивает строку символами n) почти делает именно то, что мне нужно, но вместо того, чтобы использовать раскрывающийся список, я хотел бы, чтобы редактирование произошло в самой сетке.
UITypeEditorEditStyle
, похоже, не очень помогает, поскольку установка его в None полностью исключает элемент управления UITypeEditorEditStyle
.
Или, есть ли более простой способ получить доступ к TextBox, который элемент управления использует, чтобы подключиться к событиям там?
В конечном счете, я ищу виджет ввода текста, который ограничивает длину ввода, который 1. сделал inline, и 2. не дожидаясь, пока пользователь перестанет печатать, чтобы дать им ошибку или усечь вход.
Вы можете использовать TypeConverter, который бы ограничивал текст после его ввода. Это будет работать только с текстовым полем. Предположим, что у меня есть этот класс, который я хочу редактировать, используя сетку свойств:
public class MyClass
{
[TypeConverter(typeof(MyTypeConverter))]
public string MyText { get; set; }
}
Вот код конвертера типов, который делает это:
public class MyTypeConverter : TypeConverter
{
public const int MaxLength = 10;
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Truncate(value as string, MaxLength);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return Truncate(value as string, MaxLength);
}
private static string Truncate(string value, int maxLength)
{
if (value == null)
return null;
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
}
}
В противном случае вы можете взломать сетку, как я здесь демонстрирую. Это не UITypeEditor, потому что базовое текстовое поле используется для всех элементов. Следующий подход основан на событиях выбора. Опять же, это еще один класс, который я хочу изменить:
public class MyClass
{
[Editor(typeof(NoneEditor), typeof(UITypeEditor))]
public string MyText { get; set; }
public string MyOtherText { get; set; }
}
Обратите внимание, что свойство MyText украшено редактором "маркер", который просто ничего не делает:
public class NoneEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.None;
}
}
Я могу просто подключить сетку, например:
propertyGrid1.SelectedGridItemChanged += OnPropertyGridSelectedGridItemChanged;
public static void OnPropertyGridSelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
PropertyGrid pg = (PropertyGrid)sender;
GridItem item = e.NewSelection;
// yes, a grid item is also an IServiceProvider
IServiceProvider sp = (IServiceProvider)item;
// get the property grid view control
IWindowsFormsEditorService svc = (IWindowsFormsEditorService)sp.GetService(typeof(IWindowsFormsEditorService));
// WARNING: hack time! this uses private members, so use at your own risks...
TextBox edit = (TextBox)svc.GetType().GetProperty("Edit", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(svc, null);
// is this our funky stuff?
if (item.PropertyDescriptor.GetEditor(typeof(UITypeEditor)) is NoneEditor)
{
edit.MaxLength = 10;
edit.BackColor = Color.Blue;
}
else // don't forget to reset the edit box here
{
edit.MaxLength = int.MaxValue;
edit.BackColor = Color.White;
}
}
SelectedGridItemChanged
, и он работал очень хорошо. Я пошел по пути подклассаPropertyGrid
... и в конце концов забрел на что-то подобное. Благодарю.