简体   繁体   中英

How to remove the Multiline property in custom TextBox control?

I'm creating a custom TextBox control in winforms and I don't need the multiline option.

  1. In this case, I think that the arrow button in the designer that shows a dropdown with a Multiline option checkbox is useless. Is it possible somehow to get rid of it?

这是按钮

  1. I achieved to hide the Multiline property from the properties group by overriding it in the custom Textbox class and setting [Browsable(flase)] . However, it's still possible to change it from code. Is there a way to completely remove this attribute?
    Found something here ( How to remove a property from a custom user control ), but I don't how this could help me.

When you inherit from a class, you shouldn't remove features of the parent. Anyone should be able to use your class in place of the parent class (this is known as the Liskov Substitution Principle).

It sounds like you want to make a control that hosts a TextBox control instead. This allows you to have full control over which properties you expose, and doesn't violate the contract of the TextBox class.

The arrow button in the designer that shows a dropdown with a Multiline option checkbox is called a 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.

The TextBox SmartTag is generated based on properties exposed by its designer (System.Windows.Forms.Design.TextBoxDesigner); specifically the the ActionLists Property that it inherits from its ancestor ComponentDesigner . ActionLists is a collection of DesignerActionList objects.

You could create a custom control designer that does not define a SmartTag and assign it as the designer for your custom control. However this would require you to re-implement all the features of the TextBoxDesigner to provide an expected design experience as TextBoxDesigner is an internal class and can not be inherited. A simpler method is to hook into the available designer services and obtain a reference to the default TextBoxDesigner. This is done by overriding the control's 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
}

The code first obtains a reference to the designer host and the uses that reference to obtain a reference to the control's designer. Once the designer reference is obtained, it is possible to clear the ActionLists collection to prevent the generation of the SmartTag.

Your second requested feature to totally remove the MultiLine Property is not possible as you can not uninherit a property. The best you can do is hide it as much as possible for the code editor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM