【问题标题】:How to remove the Multiline property in custom TextBox control?如何删除自定义 TextBox 控件中的 Multiline 属性?
【发布时间】:2020-01-07 01:49:58
【问题描述】:

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

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


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

【问题讨论】:

  • 你为什么要这样做?
  • 您不能取消继承基类的成员。还要添加 [EditorBrowsable(EditorBrowsableState.Never)],这样它就不会出现在 IntelliSense 弹出窗口中。该属性是虚拟的,因此覆盖它并有意不在 setter 中调用基本属性会使其安全。

标签: c# winforms designer


【解决方案1】:

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

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) 公开的属性生成的;特别是它从其祖先ComponentDesigner 继承的ActionLists Property。 ActionLists 是DesignerActionList 对象的集合。

您可以创建一个不定义 SmartTag 的自定义控件设计器并将其指定为自定义控件的设计器。但是,这将需要您重新实现 TextBoxDesigner 的所有功能以提供预期的设计体验,因为 TextBoxDesigner 是一个内部类并且不能被继承。一种更简单的方法是挂钩可用的设计器服务并获取对默认 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的生成。

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

【讨论】:

    【解决方案2】:

    当你从一个类继承时,你不应该删除父类的特性。任何人都应该能够使用您的类代替父类(这被称为 Liskov 替换原则)。

    听起来您想创建一个托管 TextBox 控件的控件。这使您可以完全控制要公开的属性,并且不会违反 TextBox 类的约定。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-26
      • 2011-03-20
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多