如何使用内置 UITypeEditors 的控件?
How to use controls from built-in UITypeEditors?
我想在自定义结构 属性 的下拉 UITypeEditor 中使用“Select 资源”对话框。
我已经有了 TestEditorControl:UserControl
,其中包含 button1
和 Click
:
的事件处理程序
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
我想在自定义结构 属性 的下拉 UITypeEditor 中使用“Select 资源”对话框。
我已经有了 TestEditorControl:UserControl
,其中包含 button1
和 Click
:
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