C# 如何为用户控件中的公开属性使用内置编辑器-掩码属性编辑器问题

C# 如何为用户控件中的公开属性使用内置编辑器-掩码属性编辑器问题,c#,winforms,user-controls,windows-forms-designer,maskedtextbox,C#,Winforms,User Controls,Windows Forms Designer,Maskedtextbox,我想我这个愚蠢的问题有一个简单的解决办法,但我今天就是解决不了 我有一个用户控件,它本身有一个MaskedTextBox控件。我还公开了它的一些属性供用户修改 其中一个属性是Mask属性,我想公开它,使它能够像在普通MaskedTextBox控件中一样使用预定义值启动编辑器 因此,我创建了一个公共属性InputMask,并对所有内容进行了设置,使其能够工作,但在显示编辑器后,我得到一个错误对话框,其中包含以下错误: 对象引用未设置为对象的实例 如果我不使用编辑器,复制一个掩码,或者通过代码设置它

我想我这个愚蠢的问题有一个简单的解决办法,但我今天就是解决不了

我有一个用户控件,它本身有一个
MaskedTextBox
控件。我还公开了它的一些属性供用户修改

其中一个属性是
Mask
属性,我想公开它,使它能够像在普通MaskedTextBox控件中一样使用预定义值启动编辑器

因此,我创建了一个公共属性InputMask,并对所有内容进行了设置,使其能够工作,但在显示编辑器后,我得到一个错误对话框,其中包含以下错误:

对象引用未设置为对象的实例

如果我不使用编辑器,复制一个掩码,或者通过代码设置它,代码就可以正常工作

下面是一个代码示例:

...
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
并转换为
MaskedTextBox
,并且由于编辑
Mask
属性属于我们的
UserControl
,而不是一个屏蔽文本框,将引发空引用异常

要解决此问题,您需要创建一个自定义的
UITypeEditor
并重写私有
MaskedTextBox
字段的
EditValue
和编辑
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);
    }
}

在这种情况下就没那么简单了。在正常情况下,注册ui类型编辑器就足够了,您不需要做任何额外的事情。但是在
MaskPropertyEditor
情况下,编辑属性时,编辑器希望属性属于
MaskedTextBox
。因此,您应该准确地编辑
MaskedTextBox
Mask
属性。非常感谢。它工作得很好。我更喜欢Photoshop(10年以上的设计师)而不是C#开发者,但多亏了你几次的帮助,我为windows窗体应用程序设计并实现了一个漂亮的UI。非常感谢。