Accesso ai dati di contesto aggiuntive in EditValue di UITypeEditor
-
23-09-2019 - |
Domanda
sto tweaking un'applicazione WinForms. Questa applicazione ha un Form
che contiene un PropertyGrid
. Un oggetto viene assegnato alla proprietà SelectedObject
modo che la griglia proprietà visualizza le proprietà dell'oggetto.
Il tipo di oggetto assegnato presenta una proprietà che trasporta un EditorAttribute
specificando un UITypeEditor
.
Questa implementazione dei rendimenti UITypeEditor
UITypeEditorEditStyle.Drop
nella sua override metodo GetEditStyle
. Il suo metodo EditValue
visualizza una ListBox
da cui può essere assegnato un valore per la proprietà di istanza.
Tutto bene un bene finora.
Ora ho un ulteriore requisito che prevede le voci disponibili nella lista per essere modificati sulla base di altro stato tenuto dal Form
che ospita il PropertyGrid
. Non riesco a capire come ottenere questo informazioni contestuali al metodo EditValue
.
Non sembra essere nulla sul parametro context
anche se cerco il cast ai tipi più specifici. Né posso lavorare come aggiungere qualche altro servizio per recuperare dal provider
.
Tutte le idee?
Soluzione
Mi chiedo se ciò che si sta cercando di fare sarebbe sarebbe meglio come TypeConverter
tramite GetStandardValues
? Ma in entrambi i casi, sia context.Instance
e context.PropertyDescriptor
sembrano per essere organizzati in un test rapido (per entrambi 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()
}
}
});
}
}
O come un tipo di convertitore:
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()
}
}
});
}
}
Altri suggerimenti
Io ero in una situazione simile, ho voluto iniettare un oggetto in costruttore di mio UITypeEditor personalizzato.
Ho seguito Nicolas Cadilhac commento a Qui , dargli tutto il merito. Esso utilizza TypeDescriptionProvider.
Questa è la serie completa di codice.
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
Nel metodo EditValue override, context.Container
fornirà l'oggetto che l'editor appartiene. La proprietà context.Container.Components
elencherà tutti i controlli che comprende la forma e tutti i suoi figli.