如何对用户控件中公开的属性使用内置编辑器 - Mask 属性 编辑器问题
How to use built-in editors for a exposed properties in User Controls - Mask Property Editor Issue
我认为我的愚蠢问题有一个简单的解决方案,但我今天无法解决它。
我有一个用户控件,它本身有一个 MaskedTextBox
控件。我也公开了它的一些属性供用户修改。
其中一个属性是 Mask
属性,我想展示它能够像在普通 MaskedTextBox 控件中一样使用预定义值启动编辑器。
所以我创建了一个 public 属性 InputMask 并设置了所有内容以便它可以工作但是在显示编辑器之后,我得到一个包含以下错误的错误对话框:
Object reference not set to an instance of an object
如果我不使用编辑器并复制掩码或通过代码设置它,则没有问题。
这是一个代码示例:
...
MaskedTextBox maskedtextbox;
myUserControl()
{
...
maskedtextbox = new MaskedTextBox(){
some stuff...
};
}
[DefaultValue("")]
[Editor("System.Windows.Forms.Design.MaskPropertyEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[Localizable(true)]
[MergableProperty(false)]
[RefreshProperties(RefreshProperties.Repaint)]
public string InputMask
{
get { return this.maskedtextbox.Mask; }
set { this.maskedtextbox.Mask = value; }
}
一般情况下,注册UI类型编辑器即可,无需额外操作。但是在 MaskPropertyEditor
的情况下,当编辑 属性 时,编辑器期望 属性 属于 MaskedTextBox
并将 ITypeDescriptorContext.Instance
转换为 MaskedTextBox
并且由于我们的编辑 Mask
属性 属于我们的 UserControl
而不是屏蔽文本框,因此将抛出空引用异常。
要解决此问题,您需要创建自定义 UITypeEditor
并覆盖 EditValue
并编辑私有 MaskedTextBox
字段的 Mask
属性。为此,我们需要创建一个包含 MaskedTextBox
的 ITypeDescriptorContext
实例,并将其传递给编辑器的 EditValue
方法。
这是实现。
用户控件
public partial class UserControl1 : UserControl
{
MaskedTextBox maskedTextBox;
public UserControl1()
{
InitializeComponent();
maskedTextBox = new MaskedTextBox();
}
[Editor(typeof(MaskEditor), typeof(UITypeEditor))]
public string Mask
{
get { return maskedTextBox.Mask; }
set { maskedTextBox.Mask = value; }
}
}
编辑器
public class MaskEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
var field = context.Instance.GetType().GetField("maskedTextBox",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var maskedTextBox = (MaskedTextBox)field.GetValue(context.Instance);
var maskProperty = TypeDescriptor.GetProperties(maskedTextBox)["Mask"];
var tdc = new TypeDescriptionContext(maskedTextBox, maskProperty);
var editor = (UITypeEditor)maskProperty.GetEditor(typeof(UITypeEditor));
return editor.EditValue(tdc, provider, value);
}
}
ITypeDescriptionContext 实现
public class TypeDescriptionContext : ITypeDescriptorContext
{
private Control editingObject;
private PropertyDescriptor editingProperty;
public TypeDescriptionContext(Control obj, PropertyDescriptor property)
{
editingObject = obj;
editingProperty = property;
}
public IContainer Container
{
get { return editingObject.Container; }
}
public object Instance
{
get { return editingObject; }
}
public void OnComponentChanged()
{
}
public bool OnComponentChanging()
{
return true;
}
public PropertyDescriptor PropertyDescriptor
{
get { return editingProperty; }
}
public object GetService(Type serviceType)
{
return editingObject.Site.GetService(serviceType);
}
}
可能需要重新加载项目,然后 Visual Studio 才能识别新的 UITypeEditor
我认为我的愚蠢问题有一个简单的解决方案,但我今天无法解决它。
我有一个用户控件,它本身有一个 MaskedTextBox
控件。我也公开了它的一些属性供用户修改。
其中一个属性是 Mask
属性,我想展示它能够像在普通 MaskedTextBox 控件中一样使用预定义值启动编辑器。
所以我创建了一个 public 属性 InputMask 并设置了所有内容以便它可以工作但是在显示编辑器之后,我得到一个包含以下错误的错误对话框:
Object reference not set to an instance of an object
如果我不使用编辑器并复制掩码或通过代码设置它,则没有问题。
这是一个代码示例:
...
MaskedTextBox maskedtextbox;
myUserControl()
{
...
maskedtextbox = new MaskedTextBox(){
some stuff...
};
}
[DefaultValue("")]
[Editor("System.Windows.Forms.Design.MaskPropertyEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[Localizable(true)]
[MergableProperty(false)]
[RefreshProperties(RefreshProperties.Repaint)]
public string InputMask
{
get { return this.maskedtextbox.Mask; }
set { this.maskedtextbox.Mask = value; }
}
一般情况下,注册UI类型编辑器即可,无需额外操作。但是在 MaskPropertyEditor
的情况下,当编辑 属性 时,编辑器期望 属性 属于 MaskedTextBox
并将 ITypeDescriptorContext.Instance
转换为 MaskedTextBox
并且由于我们的编辑 Mask
属性 属于我们的 UserControl
而不是屏蔽文本框,因此将抛出空引用异常。
要解决此问题,您需要创建自定义 UITypeEditor
并覆盖 EditValue
并编辑私有 MaskedTextBox
字段的 Mask
属性。为此,我们需要创建一个包含 MaskedTextBox
的 ITypeDescriptorContext
实例,并将其传递给编辑器的 EditValue
方法。
这是实现。
用户控件
public partial class UserControl1 : UserControl
{
MaskedTextBox maskedTextBox;
public UserControl1()
{
InitializeComponent();
maskedTextBox = new MaskedTextBox();
}
[Editor(typeof(MaskEditor), typeof(UITypeEditor))]
public string Mask
{
get { return maskedTextBox.Mask; }
set { maskedTextBox.Mask = value; }
}
}
编辑器
public class MaskEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
var field = context.Instance.GetType().GetField("maskedTextBox",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var maskedTextBox = (MaskedTextBox)field.GetValue(context.Instance);
var maskProperty = TypeDescriptor.GetProperties(maskedTextBox)["Mask"];
var tdc = new TypeDescriptionContext(maskedTextBox, maskProperty);
var editor = (UITypeEditor)maskProperty.GetEditor(typeof(UITypeEditor));
return editor.EditValue(tdc, provider, value);
}
}
ITypeDescriptionContext 实现
public class TypeDescriptionContext : ITypeDescriptorContext
{
private Control editingObject;
private PropertyDescriptor editingProperty;
public TypeDescriptionContext(Control obj, PropertyDescriptor property)
{
editingObject = obj;
editingProperty = property;
}
public IContainer Container
{
get { return editingObject.Container; }
}
public object Instance
{
get { return editingObject; }
}
public void OnComponentChanged()
{
}
public bool OnComponentChanging()
{
return true;
}
public PropertyDescriptor PropertyDescriptor
{
get { return editingProperty; }
}
public object GetService(Type serviceType)
{
return editingObject.Site.GetService(serviceType);
}
}
可能需要重新加载项目,然后 Visual Studio 才能识别新的 UITypeEditor