在.NET Framework 4.x WinForms中无需自定义类获取IWindowsFormsEditorService实例
在.NET Framework 4.x WinForms中调用控件属性默认UI编辑器的通用实现
我需要在.NET Framework 4.x的Windows Forms项目中,用C#或VB.NET编写一个通用函数,实现在运行时调用指定控件属性类型的默认UI编辑器。
现有不完整代码
public T EditValue<T>(Component component, string propertyName, T value) { PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(component)[propertyName]; UITypeEditor editor = (UITypeEditor)propDescriptor.GetEditor(typeof(UITypeEditor)); IWindowsFormsEditorService serviceProvider = ??????; object result = editor.EditValue(serviceProvider, serviceProvider, value); return (T)result; }
注:可以给函数添加
ExtensionAttribute来简化调用。
示例用法
示例1:编辑Control.Font属性
TextBox ctrl = this.TextBox1; Font value = EditValue(ctrl, nameof(ctrl.Font), ctrl.Font); ctrl.Font = value;
示例2:编辑ListBox的项
ListBox ctrl = this.ListBox1; ListBox.ObjectCollection value = EditValue(ctrl, nameof(ctrl.Items), ctrl.Items);
我的疑问
- 当前的实现思路是否正确?有没有通过反射等更简单的实现方式?
- Form、Component或Control类型中是否已有现成实现
IServiceProvider/IWindowsFormsEditorService接口的类,可以通过实例化或反射获取,从而避免自定义类?
解答
实现思路的正确性
当前通过TypeDescriptor获取属性描述符、再获取对应UITypeEditor的思路是完全正确的,这是WinForms设计器中调用属性编辑器的标准流程。直接用反射实现反而更复杂:因为UI编辑器的正常工作依赖于IWindowsFormsEditorService提供的上下文服务(比如弹出对话框、显示下拉控件等),反射调用编辑器的方法会缺失这些必要的服务支持,所以当前的实现方式是更可靠的选择。现成的服务实现是否存在
Form、Control和Component本身并没有实现IWindowsFormsEditorService接口,这个接口是设计器环境(比如Visual Studio的WinForms设计器)提供的服务。在运行时(非设计器场景),.NET框架并没有公开的现成实例可供直接使用,因此自定义实现IWindowsFormsEditorService和IServiceProvider是常规解决方案。
可直接使用的自定义实现示例
public class RuntimeEditorService : IWindowsFormsEditorService, IServiceProvider { private IWin32Window _owner; public RuntimeEditorService(IWin32Window owner) { _owner = owner; } // IServiceProvider实现 public object GetService(Type serviceType) { if (serviceType == typeof(IWindowsFormsEditorService)) return this; return null; } // IWindowsFormsEditorService实现 public void CloseDropDown() { // 运行时场景下拉编辑器较少用到,此处留空或按需实现 } public void DropDownControl(Control control) { // 如需支持下拉式编辑器,可在此实现弹出逻辑 throw new NotImplementedException("下拉式编辑器暂未实现"); } public DialogResult ShowDialog(Form dialog) { return dialog.ShowDialog(_owner); } }
修改后的完整通用函数(扩展方法版)
public static T EditValue<T>(this Component component, string propertyName, T value, IWin32Window owner = null) { PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(component)[propertyName]; if (propDescriptor == null) throw new ArgumentException($"属性 {propertyName} 不存在"); UITypeEditor editor = (UITypeEditor)propDescriptor.GetEditor(typeof(UITypeEditor)); if (editor == null) return value; var service = new RuntimeEditorService(owner ?? component as IWin32Window); object result = editor.EditValue(service, component, value); // 验证编辑结果是否符合属性类型要求 return propDescriptor.PropertyType.IsInstanceOfType(result) ? (T)result : value; }
调用示例
// 编辑Font属性 this.TextBox1.Font = this.TextBox1.EditValue(nameof(TextBox.Font), this.TextBox1.Font, this); // 编辑ListBox.Items属性 var newItems = this.ListBox1.EditValue(nameof(ListBox.Items), this.ListBox1.Items, this); this.ListBox1.Items.Clear(); this.ListBox1.Items.AddRange(newItems.Cast<object>().ToArray());
内容的提问来源于stack exchange,提问作者ElektroStudios
相关产品推荐
相关产品推荐

