如何使用内置 UITypeEditors 的控件?

How to use controls from built-in UITypeEditors?

我想在自定义结构 属性 的下拉 UITypeEditor 中使用“Select 资源”对话框。 我已经有了 TestEditorControl:UserControl,其中包含 button1Click:

的事件处理程序
btn.Click+=(s,a)=>{
    OpenFileDialog oDlg = new OpenFileDialog();
    if (oDlg.ShowDialog() == DialogResult.OK)
    {
        ...
    }
}

如何用“Select资源”对话框替换“OpenFileDialog”? 我试过这段代码(基于 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)
    {
        ...
    }
}

要显示 属性 的编辑器,您需要获取 UITypeEditor of the property and call its EditValue:

var editor = (UITypeEditor)propertyDescriptor.GetEditor(typeof(UITypeEditor));
var editedValue = editor.EditValue(context, provider, propertyValue);

您需要传递给方法的值取决于代码的上下文,除了本 post 中的示例外,我还在本 [=] 底部共享了一些其他链接67=].

示例 - 显示 Select 嵌套 属性

的图像对话框

在这个例子中,我创建了一个 MyTestControl,它有一个名为 MyTestProperty 的 属性,它是 MyTestClass 类型,它有一个 MyTestImage 属性 Image 类型。我要为 MyTestProperty 显示一个 UITypeEditor,并在编辑器中显示一个按钮,该按钮显示 select 图像对话框并更改图像 属性:

控件

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;
    }
}

编辑器控件

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));
}

更多示例

您可能需要查看以下 post 以获得更多示例:

  • Obtain ITypeDescriptorContext in designer