Aggiunta Editor / EditorAttribute a run-time (dinamicamente) per proprietà di un oggetto
-
19-09-2019 - |
Domanda
Come aggiungere l'EditorAttribute (Editor) per la proprietà di un oggetto a run-time?
Ho My.Settings.ExcludeFiles
, che è stato creato dal designer impostazioni come Public Property ExcludedFiles() As Global.System.Collections.Specialized.StringCollection
. Quando si modifica ExcludedFiles
tramite una griglia di proprietà, la "Editor dell'insieme String" genera un "costruttore del tipo 'System.String' non trovato" run-time eccezioni.
Non riesco a modificare gli attributi della proprietà ExcludeFiles
perché saranno sovrascritti la prossima volta che vengono apportate modifiche alle impostazioni. Pertanto, devo collegare / aggiungere l'Editor / EditorAttribute in fase di esecuzione.
Quello che voglio fare è aggiungere il StringCollectionEditor
a run-time, come illustrato di seguito attributo in fase di progettazione.
<Editor(GetType(StringCollectionEditor), GetType(UITypeEditor))> _
Soluzioni
Metodo # 1
TypeDescriptor.AddAttributes( _
GetType(Specialized.StringCollection), _
New EditorAttribute( _
"System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", _
GetType(System.Drawing.Design.UITypeEditor)))
È sufficiente aggiungere questo attributo una volta, come ad esempio l'inizializzazione dell'applicazione.
Metodo # 2
Più flessibile. Vedi Nicolas Cadilhac rispondere a seguito Aggiunta Editor / EditorAttribute a runtime (dinamicamente) per un oggetto di proprietà . Esso utilizza classi derivate CustomTypeDescriptor e TypeDescriptionProvider. Basta aggiungere il provider una volta, come ad esempio l'inizializzazione dell'applicazione.
Soluzione
Dopo aver dato la mia prima risposta, mi sono ricordato di un'altra soluzione data dal Marc Gravell che ho anche commentato. Che ci crediate o no, è sufficiente chiamare TypeDescriptor.AddAttributes ().
Questa è qui: Come faccio a iniettare un UITypeEditor personalizzato per tutte le proprietà di un tipo closed-source? .
Per il vostro caso si dà:
TypeDescriptor.AddAttributes(
typeof(StringCollection),
new EditorAttribute("System.Windows.Forms.Design.StringCollectionEditor,
System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
typeof(UITypeEditor)))
Così forse si dovrebbe deselezionare la mia risposta precedente e confermare questa come la soluzione (anche se tutto il merito va a Marc). Ma il mio precedente post vi dà ancora una buona tecnica quando si ha bisogno di fare cose più complesse con un TypeDescriptor.
Altri suggerimenti
Non è possibile. Un attributo può essere definito solo in fase di compilazione (a meno che non si genera il tipo dinamico ovviamente)
Sì, è possibile cambiare dinamicamente un TypeDescriptor in modo che ritorni l'UITypeEditor che si desidera. Questo è spiegato in questo articolo . Ma si noti che questo verrà aggiunto per tutte le proprietà di questo tipo.
Ho afferrato il codice da qui e grosso modo cambiato per il seguente:
private class StringCollectionTypeDescriptor : CustomTypeDescriptor
{
private Type _objectType;
private StringCollectionTypeDescriptionProvider _provider;
public StringCollectionTypeDescriptor(
StringCollectionTypeDescriptionProvider 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;
}
/* Here is your customization */
public override object GetEditor(Type editorBaseType)
{
return new MultilineStringEditor();
}
}
public class StringCollectionTypeDescriptionProvider : TypeDescriptionProvider
{
private TypeDescriptionProvider _baseProvider;
public StringCollectionTypeDescriptionProvider(Type t)
{
_baseProvider = TypeDescriptor.GetProvider(t);
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new StringCollectionTypeDescriptor(this, _baseProvider.GetTypeDescriptor(objectType, instance), objectType);
}
}
Poi si registra il fornitore:
TypeDescriptor.AddProvider(new StringCollectionTypeDescriptionProvider
(typeof(System.Collections.Specialized.StringCollection)),
typeof(System.Collections.Specialized.StringCollection));
Questo metodo funziona bene, tranne che vi farà scoprire di non avere un altro problema: MultilineStringEditor è un editor che funziona con il tipo String, non con il tipo StringCollection. Che cosa hai veramente bisogno è lo StringCollectionEditor privato nel quadro .Net. Quindi cerchiamo di sostituire GetEditor da:
public override object GetEditor(Type editorBaseType)
{
Type t = Type.GetType("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
return TypeDescriptor.CreateInstance(null, t, new Type[] { typeof(Type) }, new object[] { typeof(string) });
}
Spero che questo aiuta.