I want to use "Select resource" dialog in my dropdown UITypeEditor for custom struct property.
I already have TestEditorControl:UserControl
, which contains a button1
with event handler for Click
:
btn.Click+=(s,a)=>{
OpenFileDialog oDlg = new OpenFileDialog();
if (oDlg.ShowDialog() == DialogResult.OK)
{
...
}
}
How to replace "OpenFileDialog" with "Select resource" dialog? I tried this code (based on Visual Studio "Select Resource" dialog replacement):
private Form resDialog;
public TestEditorControl()
{
InitializeComponent();
var property = TypeDescriptor.GetProperties(button1)["Image"];
var resourceEditorSwitch = property.GetEditor(typeof(UITypeEditor)) as UITypeEditor;
var editorToUseField = resourceEditorSwitch.GetType().GetProperty("EditorToUse",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
var editorToUse = editorToUseField.GetValue(resourceEditorSwitch);
//System.NullReferenceException (editorToUseField == null)
var resourcePickerUIField = editorToUse.GetType().GetField("resourcePickerUI",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
var resDialog= (Form)Activator.CreateInstance(resourcePickerUIField.FieldType);
}
btn.Click+=(s,a)=>{
if (resDialog.ShowDialog() == DialogResult.OK)
{
...
}
}
To show editor of a property, you need to get the UITypeEditor
of the property and call its EditValue
:
var editor = (UITypeEditor)propertyDescriptor.GetEditor(typeof(UITypeEditor));
var editedValue = editor.EditValue(context, provider, propertyValue);
The values you need to pass to the method, depend to the context of the code, in addition to the example in this post, I've shared a few other links at bottom of this post.
In this example I have created a MyTestControl
, which has a property called MyTestProperty
which is of MyTestClass
type, which has a MyTestImage
property of Image
type. I'm going to show a UITypeEditor
for MyTestProperty
, and a button inside the editor which shows select image dialog and changes the image property:
The Control
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
public class MyTestControl : Control
{
[Editor(typeof(MyTestClassEditor), typeof(UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MyTestClass MyTestProperty { get; set; } = new MyTestClass();
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (MyTestProperty != null &&
MyTestProperty.MyTestImageProperty != null)
e.Graphics.DrawImage(MyTestProperty.MyTestImageProperty,
ClientRectangle.Location);
}
}
public class MyTestClass
{
public Image MyTestImageProperty { get; set; }
}
UITypeEditor
public class MyTestClassEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(
ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
var svc = (IWindowsFormsEditorService)provider
.GetService(typeof(IWindowsFormsEditorService));
var propertyToEdit = TypeDescriptor.GetProperties(value)
[nameof(MyTestClass.MyTestImageProperty)];
var ctx = new TypeDescriptionContext(
(Control)context.Instance, provider, value, propertyToEdit);
var editorControl = new MyTestClassEditorControl(svc, ctx, provider);
svc.DropDownControl(editorControl);
return editorControl.Result;
}
}
Editor control
public class MyTestClassEditorControl : Control
{
public Object Result { get; private set; }
public MyTestClassEditorControl(IWindowsFormsEditorService service,
ITypeDescriptorContext context, IServiceProvider provider)
{
Result = context.Instance;
var button = new Button() { Text = "Choose Image", AutoSize = true };
button.Click += (sender, e) =>
{
try
{
var imageProp = context.PropertyDescriptor;
var imageValue = imageProp.GetValue(context.Instance);
var editor = (UITypeEditor)imageProp
.GetEditor(typeof(UITypeEditor));
var selectedImage = editor.EditValue(
context, provider, imageValue);
imageProp.SetValue(context.Instance, selectedImage);
context.OnComponentChanging();
context.OnComponentChanged();
service.CloseDropDown();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
};
this.Controls.Add(button);
this.Height = 100;
}
}
TypeDescriptionContext
public class TypeDescriptionContext : ITypeDescriptorContext
{
Control control;
IServiceProvider provider;
object instannce;
PropertyDescriptor property;
public TypeDescriptionContext(Control control,
IServiceProvider provider, object instannce,
PropertyDescriptor property)
{
this.control = control;
this.provider = provider;
this.instannce = instannce;
this.property = property;
}
public IContainer Container => control.Site?.Container;
public object Instance => instannce;
public void OnComponentChanged() =>
GetService<IComponentChangeService>()
?.OnComponentChanged(control, null, null, null);
public bool OnComponentChanging() => true;
public PropertyDescriptor PropertyDescriptor => property;
public object GetService(Type type) => provider?.GetService(type);
public T GetService<T>() => (T)this.GetService(typeof(T));
}
You may want to look into following posts for more example: