如何删除自定义 TextBox 控件中的多行 属性?

How to remove the Multiline property in custom TextBox control?

我正在 winforms 中创建自定义 TextBox 控件,我不需要多行选项。

  1. 在这种情况下,我认为设计器中显示带有多行选项复选框的下拉菜单的箭头按钮没有用。是否有可能以某种方式摆脱它?


  1. 我通过在自定义文本框 class 中覆盖它并设置 [Browsable(flase)] 实现了从属性组中隐藏多行 属性。但是,仍然可以从代码中更改它。有没有办法完全删除这个属性?
    在这里找到了一些东西 (How to remove a property from a custom user control),但我不知道这对我有什么帮助。

当您从 class 继承时,您不应删除父项的功能。任何人都应该能够使用您的 class 代替父 class(这被称为 Liskov 替换原则)。

听起来您想制作一个 hosts 的控件,而不是 TextBox 控件。这使您可以完全控制公开的属性,并且不会违反 TextBox class.

的约定

设计器中显示带有多行选项复选框的下拉列表的箭头按钮称为 SmartTag。

To speed development, many controls offer smart tags, which are context-sensitive menus that allow you to perform common tasks like these in a single gesture at design time. These tasks are called smart-tag verbs.

TextBox SmartTag 是根据其设计者公开的属性生成的 (System.Windows.Forms.Design.TextBoxDesigner);特别是 ActionLists Property that it inherits from its ancestor ComponentDesigner. ActionLists is a collection of DesignerActionList 个对象。

您可以创建一个未定义 SmartTag 的自定义控件设计器,并将其指定为您的自定义控件的设计器。但是,这将需要您重新实现 TextBoxDesigner 的所有功能以提供预期的设计体验,因为 TextBoxDesigner 是内部 class 并且不能被继承。一种更简单的方法是连接到可用的设计器服务并获取对默认 TextBoxDesigner 的引用。这是通过覆盖控件的 Site Property.

来完成的
// add project assembly reference: System.Design
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design;
using System;
using System.Windows.Forms.Design;

public class SingleLineTB : TextBox
{
    [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
    public override bool Multiline
    {
        get {return base.Multiline;}
        set {}
    }

    #region Designer Services
    private IDesignerHost designerHost;

    public override ISite Site
    {
        get {return base.Site;}
        set 
        {
            base.Site = value;
            if (value == null)
            {
                // this instance is being removed from the design surface
                DetachDesignerServices();
            }
            else // being added to the design surface
            {
                designerHost = (IDesignerHost)value.GetService(typeof(IDesignerHost));
                if (designerHost != null)
                {
                    if (designerHost.Loading)
                    {
                        // the designer has not finished loading, 
                        // postpone all other connections until it has finished loading
                        designerHost.LoadComplete += DesignerHostLoaded;
                    }
                    else
                    {
                        if (designerHost.InTransaction)
                        {
                            // designerHost loaded, but is in the in the process of creating this instance
                            designerHost.TransactionClosed += DesignerTransactionClosed;
                        }
                        else
                        {
                            // this will probably never be hit as the designer
                            // should be siting the component in a transaction
                            ClearDesignerActionLists();
                        }
                    }
                }
            }
        }
    }

    private void DesignerHostLoaded(object sender, EventArgs e)
    {
        designerHost.LoadComplete -= DesignerHostLoaded;
        ClearDesignerActionLists();
    }

    private void DesignerTransactionClosed(object sender, DesignerTransactionCloseEventArgs e)
    {
        designerHost.TransactionClosed -= DesignerTransactionClosed;
        ClearDesignerActionLists();
    }
    private void DetachDesignerServices()
    {
        if (designerHost != null)
        {
            designerHost.TransactionClosed -= DesignerTransactionClosed;
            designerHost.LoadComplete -= DesignerHostLoaded;
            designerHost = null;
        }
    }

    private void ClearDesignerActionLists()
    {
        ControlDesigner myDesigner = designerHost.GetDesigner(this) as ControlDesigner;
        myDesigner?.ActionLists.Clear();
    }

    #endregion // "Designer Services
}

代码首先获取对设计器宿主的引用,然后使用该引用获取对控件设计器的引用。获得设计者参考后,可以清除 ActionLists 集合以防止生成 SmartTag。

您要求的第二个功能完全删除多行 属性 是不可能的,因为您不能 uninherit a 属性。您能做的最好的事情就是为代码编辑器尽可能地隐藏它。