Acessando dados de contexto adicionais no editValue do UityPeeditor
-
23-09-2019 - |
Pergunta
Estou ajustando um aplicativo Winforms. Este aplicativo tem um Form
que contém a PropertyGrid
. Um objeto é atribuído ao SelectedObject
Propriedade para que a grade da propriedade exiba as propriedades do objeto.
O tipo de objeto designado possui uma propriedade que carrega um EditorAttribute
especificando a UITypeEditor
.
Esta implementação de UITypeEditor
retorna UITypeEditorEditStyle.Drop
em sua substituição de GetEditStyle
método. Seu EditValue
O método exibe a ListBox
a partir do qual um valor para a propriedade da instância pode ser atribuído.
Tudo bem, um bom até agora.
Agora eu tenho um requisito adicional que exige que os itens disponíveis na lista sejam modificados com base em outro estado mantido pelo Form
hospedando o PropertyGrid
. Não consigo descobrir como obter essas informações contextuais para o EditValue
método.
Não parece haver nada no context
Parâmetro Mesmo se eu tentar lançá -lo em tipos mais específicos. Nem posso descobrir como adicionar outro serviço para recuperar do provider
.
Alguma ideia?
Solução
Eu me pergunto se o que você está tentando fazer seria melhor como um TypeConverter
através da GetStandardValues
? Mas de qualquer maneira, ambos context.Instance
e context.PropertyDescriptor
parecer ser preenchido em um teste rápido (para ambos GetEditStyle
e EditValue
):
using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
class MyData
{
[Editor(typeof(MyEditor), typeof(UITypeEditor))]
public string Bar { get; set; }
public string[] Options { get; set; }
}
class MyEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// break point here; inspect context
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
// break point here; inspect context
return base.EditValue(context, provider, value);
}
}
class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form
{
Controls =
{
new PropertyGrid {
Dock = DockStyle.Fill,
SelectedObject = new MyData()
}
}
});
}
}
Ou como um conversor de tipo:
using System;
using System.ComponentModel;
using System.Windows.Forms;
class MyData
{
[TypeConverter(typeof(MyConverter))]
public string Bar { get; set; }
public string[] Options { get; set; }
}
class MyConverter : StringConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
MyData data = (MyData)context.Instance;
if(data == null || data.Options == null) {
return new StandardValuesCollection(new string[0]);
}
return new StandardValuesCollection(data.Options);
}
}
class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form
{
Controls =
{
new PropertyGrid {
Dock = DockStyle.Fill,
SelectedObject = new MyData()
}
}
});
}
}
Outras dicas
Eu estava em situação semelhante, queria injetar um objeto no construtor do meu UityPeeditor personalizado.
Eu segui o comentário de Nicolas Cadilhac em Aqui, Dê a ele todo o crédito. Ele usa o TypeDescriptionProvider.
Aqui está o conjunto completo de código.
class Foo
{
public Foo() { Bar = new Bar(); }
public Bar Bar { get; set; }
}
class Bar
{
public string Value { get; set; }
}
class BarTypeDescriptionProvider : TypeDescriptionProvider
{
private TypeDescriptionProvider _baseProvider;
string _extraParam;
public BarTypeDescriptionProvider(Type t, string extraParam)
{
this._extraParam = extraParam;
_baseProvider = TypeDescriptor.GetProvider(t);
}
public string ExtraParam
{
get { return _extraParam; }
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new BarTypeDescriptor(this, _baseProvider.GetTypeDescriptor(objectType, instance), objectType);
}
}
class BarTypeDescriptor : CustomTypeDescriptor
{
private Type _objectType;
private BarTypeDescriptionProvider _provider;
public BarTypeDescriptor(BarTypeDescriptionProvider provider, ICustomTypeDescriptor descriptor, Type objectType): base(descriptor)
{
if (provider == null) throw new ArgumentNullException("provider");
if (descriptor == null)
throw new ArgumentNullException("descriptor");
if (objectType == null)
throw new ArgumentNullException("objectType");
_objectType = objectType;
_provider = provider;
}
public override object GetEditor(Type editorBaseType)
{
return new BarEditor(_provider.ExtraParam);
}
}
class BarEditor : UITypeEditor
{
private string _extraParam;
public BarEditor(string x)
: base()
{
_extraParam = x;
}
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
MessageBox.Show(_extraParam);
return base.EditValue(context, provider, value);
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string extraParam = "Extra param from main form";
TypeDescriptor.AddProvider(new BarTypeDescriptionProvider(typeof(Bar), extraParam), typeof(Bar));
this.propertyGrid1.SelectedObject = new Foo();
}
}
Michael
No método de editValue substituído, context.Container
fornecerá o objeto ao qual o editor pertence. o context.Container.Components
A propriedade listará todos os controles que incluem o formulário e todos os seus filhos.