I don't have anything to hand, but it isn't hugely difficult to knock one up... the biggest gotcha is the issue of not unloading the dlls... but a crude example:
(this uses the string AssemblyQualifiedName
, but a Type
works virtually identically - just change about 3 lines)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Reflection;
using System.Windows.Forms;
using System.Windows.Forms.Design;
class MyData {
[Editor(typeof(TypeTypeEditor), typeof(UITypeEditor))]
[DisplayName("Some Type"), Description("Which type to use...")]
public string SomeType { get; set; }
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.Run(new Form {
Controls = {
new PropertyGrid {
Dock = DockStyle.Fill,
SelectedObject = new MyData()
}
}
});
}
}
class TypeTypeEditor : UITypeEditor {
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value) {
IWindowsFormsEditorService svc = provider == null ? null
: provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
if (svc != null) {
using(TypeForm form = new TypeForm()) {
form.TypeName = Convert.ToString(value);
if (svc.ShowDialog(form) == DialogResult.OK) {
value = form.TypeName;
}
}
}
return value;
}
}
class TypeForm : Form {
public string TypeName { get; set; }
Button ok, load;
TreeView tree;
public TypeForm() {
Text = "Select type";
ok = new Button { Text = "OK" };
ok.Enabled = false;
ok.DialogResult = DialogResult.OK;
load = new Button { Text = "Load..." };
load.Dock = ok.Dock = DockStyle.Bottom;
this.AcceptButton = ok;
tree = new TreeView();
tree.Dock = DockStyle.Fill;
load.Click += load_Click;
Controls.Add(load);
Controls.Add(ok);
Controls.Add(tree);
tree.AfterSelect += tree_AfterSelect;
}
void tree_AfterSelect(object sender, TreeViewEventArgs e) {
ok.Enabled = false;
if (e.Node != null && e.Node.Tag != null) {
string s = Convert.ToString(e.Node.Tag);
if (!string.IsNullOrEmpty(s)) {
TypeName = s;
ok.Enabled = true;
}
}
}
void load_Click(object sender, EventArgs e) {
try {
string path = null;
using (OpenFileDialog dlg = new OpenFileDialog()) {
dlg.Filter = "dll|*.dll|exe|*.exe";
if (dlg.ShowDialog(this) == DialogResult.OK) {
path = dlg.FileName;
}
}
if (!string.IsNullOrEmpty(path)) {
Assembly asm = Assembly.LoadFrom(path);
SortedList<string, TreeNode> namespaces = new SortedList<string, TreeNode>();
foreach (Type type in asm.GetTypes()) {
if (!type.IsPublic) continue;
TreeNode nsNode;
if (!namespaces.TryGetValue(type.Namespace, out nsNode)) {
nsNode = new TreeNode(type.Namespace);
namespaces.Add(type.Namespace, nsNode);
}
nsNode.Nodes.Add(type.Name).Tag = type.AssemblyQualifiedName;
}
tree.BeginUpdate();
tree.Nodes.Clear();
try {
foreach (TreeNode node in namespaces.Values) {
tree.Nodes.Add(node);
}
}
finally {
tree.EndUpdate();
}
}
}
catch (Exception ex) {
MessageBox.Show(this, ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}