如何对用户控件中的公开属性使用内置编辑器-遮罩属性编辑器问题
我认为我的愚蠢问题有一个简单的解决方案,但我今天无法解决.
I think there is a simple solution for my stupid question but I just can't solve it today.
我有一个本身具有MaskedTextBox
控件的用户控件.我还公开了它的一些属性供用户修改.
I have a User Control that has a MaskedTextBox
Control in itself. I have also exposed a few of its properties for the user to modify.
这些属性之一是Mask
属性,我希望使用常规的MaskedTextBox控件中的预定义值启动编辑器来公开该属性.
One of these properties is Mask
property which I want to expose with the ability of starting an editor with predefined values like in a normal MaskedTextBox control.
因此,我创建了一个公共属性InputMask并进行了所有设置,使其可以正常工作,但是在显示编辑器后,出现一个包含以下错误的错误对话框:
So I created a public property InputMask and set up everything so that it can work but after showing the editor, I get an error dialog which contains this error:
对象引用未设置为对象的实例
Object reference not set to an instance of an object
如果我不使用编辑器并复制蒙版或将其设置为低谷代码,则不会出现问题.
If i don't use editor and copy a mask or set it trough code works without problems.
这是一个代码示例:
...
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
并转换
In normal cases it's enough to register ui type editor and you don't need to do anything extra. But in MaskPropertyEditor
case, when editing the property, the editor expect the the property belong to a MaskedTextBox
and converts ITypeDescriptorContext.Instance
to MaskedTextBox
and since our editing Mask
property belongs to our UserControl
which is not a masked text box, a null reference exception will throw.
要解决此问题,您需要创建一个自定义UITypeEditor
并覆盖EditValue
并编辑私有MaskedTextBox
字段的Mask
属性.为此,我们需要创建一个包含MaskedTextBox
的ITypeDescriptorContext
实例,并将其传递给编辑器的EditValue
方法.
To solve the problem, you need to create a custom UITypeEditor
and override EditValue
and edit Mask
property of the private MaskedTextBox
field. To do so, we need to create an instance of ITypeDescriptorContext
containing the MaskedTextBox
and pass it to EditValue
method of the editor.
这里是实现.
UserControl
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);
}
}