tags:

views:

803

answers:

4

I have a GUI with a flat style for the buttons. I would like to use TextBox controls with the same appearance, but I can't find where can I configure the outer line with. Is there any control in WinForms which can be given FlatStyle? Thanks!


Edit 1

Thanks for the information about FixedSingle border style, but then, how can I change the line properties?


Edit 2

I've implemented a solution with a little bit of both. I would like if you could help improving this class, as I'm not an expert in C# and I find this code somewhat messy. Here is the code:

class BorderTextBox : UserControl
{
    private TextBox m_textBox;
    private int m_borderSize;

    private void ResizeComponent()
    {
        m_textBox.Size = new Size(Size.Width - 2 * m_borderSize, m_textBox.Size.Height);
        Size = new Size(Size.Width, m_textBox.Size.Height + 2 * m_borderSize);
    }

    protected override void OnResize(EventArgs z_event)
    {
        base.OnResize(z_event);
        ResizeComponent();
    }

    public BorderTextBox()
    {
        SuspendLayout();

        // TextBox
        m_textBox = new TextBox();
        m_textBox.BorderStyle = BorderStyle.None;
        m_textBox.Name = "textBox";
        m_textBox.TabIndex = 0;

        // Body
        BackColor = Color.Black;
        Name = "Body";
        Controls.Add(m_textBox);

        ResumeLayout(false);
        PerformLayout();
    }

    public bool UsePasswordStyle
    {
        get { return m_textBox.UseSystemPasswordChar; }
        set { m_textBox.UseSystemPasswordChar = value; }
    }

    public int BorderSize
    {
        get { return m_borderSize; }
        set
        {
            m_borderSize = value;
            m_textBox.Location = new Point(m_borderSize, m_borderSize);
            ResizeComponent();
        }
    }
}


Edit 3

I'm having some problems in implementing the ReadOnly property. I was trying to prevent the edit box to process the OnClick event and show the intermitent cursor inside. When I define the OnClick method inside this class:

class BorderTextBox : UserControl
{
    ...

    protected override void OnClick(EventArgs e)
    {
        if (!ReadOnly)
            base.OnClick(e);
    }        

    ...
}

This method only gets the clicks on the border, but not inside the textBox. Is there a way to catch that events? or how can you remove the event handlers of an element inside your component?

m_textBox.Click -= //the EventHandler we don't want
A: 

There are border styles you can set on the text box control in c#. On my system, they are already set by default to a "flat" style.

Robert Harvey
Where can they be set to flat?
yeyeyerman
+7  A: 

Set the BorderStyle of the TextBox to FixedSingle.

Update: there isn't an easy way to control the border width of a TextBox, but you can easily create this effect yourself by creating your own UserControl. Basically, you would just set the BackColor of the UserControl to SystemColors.WindowFrame, and then put a TextBox on the control with a BorderStyle of None. In the Resize event of the control, you can then reposition the TextBox so that it leaves a border (which is just the UserControl itself showing through around the edges) of 2 pixels or 5 or whatever you want.

Update 2: I've written a sample UserControl called "ThextBox" ( for Thick-bordered T extBox ) that has an adjustable border:

public partial class ThextBox : UserControl
{
    private TextBox _TextBox;
    private int _BorderWidth = 1;

    [Browsable(true)]
    [DesignerSerializationVisibility
        (DesignerSerializationVisibility.Visible)]
    public override string Text
    {
        get
        {
            return _TextBox.Text;
        }
        set
        {
            _TextBox.Text = value;
        }
    }

    [DesignerSerializationVisibility
        (DesignerSerializationVisibility.Visible)]
    public bool Multiline
    {
        get
        {
            return _TextBox.Multiline;
        }
        set
        {
            _TextBox.Multiline = value;
            ResizeMe();
        }
    }

    [DesignerSerializationVisibility
        (DesignerSerializationVisibility.Visible)]
    public bool UseSystemPasswordChar
    {
        get
        {
            return _TextBox.UseSystemPasswordChar;
        }
        set
        {
            _TextBox.UseSystemPasswordChar = value;
        }
    }

    [DesignerSerializationVisibility
        (DesignerSerializationVisibility.Visible)]
    public char PasswordChar
    {
        get
        {
            return _TextBox.PasswordChar;
        }
        set
        {
            _TextBox.PasswordChar = value;
        }
    }

    [DesignerSerializationVisibility
        (DesignerSerializationVisibility.Visible)]
    public int BorderWidth
    {
        get
        {
            return _BorderWidth;
        }
        set
        {
            _BorderWidth = value;
            ResizeMe();
        }
    }

    public ThextBox()
    {
        InitializeComponent();
        this.BackColor = SystemColors.WindowFrame;
        _TextBox = new TextBox();
        _TextBox.Multiline = false;
        _TextBox.BorderStyle = BorderStyle.None;
        this.Controls.Add(_TextBox);
        ResizeMe();
    }

    protected override void OnFontChanged(EventArgs e)
    {
        base.OnFontChanged(e);
        ResizeMe();
    }

    private void ResizeMe()
    {
        if (this.Multiline)
        {
            _TextBox.Height = this.Height - (2 * _BorderWidth);
        }
        else
        {
            this.Height = _TextBox.Height + (2 * _BorderWidth);
        }
        _TextBox.Width = this.Width - (2 * _BorderWidth);
        _TextBox.Location = new Point(_BorderWidth, _BorderWidth);
    }

    private void ThextBox_Resize(object sender, EventArgs e)
    {
        ResizeMe();
    }
}

To use this code in your project, add a UserControl named "ThextBox" to your project and paste this code over what the designer added. This control has the adjustable border, and it also "plays nicely" with the designer, allowing you to set all its relevant properties in design mode. It also automatically persists things like the text entered, the border width, the password character etc.

If you need to extend this by including additional TextBox-specific properties (such as MaxLength and RightToLeft, just follow the example in the PasswordChar property of this control. One of the advantages of inheriting directly from TextBox instead of UserControl like this would be that your control would automatically have all of the TextBox properties. However, you couldn't do the border that way.

MusiGenesis
But, how can I adjust the width of the line?
yeyeyerman
@MusiGenesis: Is there a way to get a little more control over the borders, or do you have to paint your own control?
Robert Harvey
@Robert: I think there's a Windows API way of controlling the border width, but I'm not sure and it's a big PITA anyway. Just plopping a borderless TextBox on a slightly larger UserControl is an easy way to achieve this effect.
MusiGenesis
OK, makes sense. Makes you yearn for WPF, doesn't it? +1 for the trouble.
Robert Harvey
@Robert: it makes me yearn for a WPF that works with Mono. It's hard to pass up the ability to run on the iPhone these days.
MusiGenesis
@MusicGenesis: your comments about the code above will be much appreciated... thanks!
yeyeyerman
@yeyeyerman: your version would work just fine, but the version I added plays nicely in the designer and lets you use this control just like an ordinary TextBox. Also, it deals with the Multiline problem - if a TextBox has Multiline false, then its Height is actually fixed by the Font size.
MusiGenesis
@MusicGenesis: Thanks for your help! Just one question before closing this topic... what are the attributes Browsable and DesignerSerializationVisibility for? I have read MSDN info but it is not so clear...
yeyeyerman
@yeyeyerman (wow that's hard to type): DesignerSerializationVisibility is so that when you use the control on a form designer and change its properties in the properties window, these values are persisted when you close and re-open the form. Browsable(true) is necessary for the Text property to appear in the designer because it is an override (the other "custom" properties don't require this one).
MusiGenesis
A: 

Have you tried setting the BorderStyle property to BorderStyle.FixedSingle or BorderStyle.None?

Simon
+2  A: 

Option 1:

A slightly ugly Hack: (not recommended unless absolutly necessary)

You can have a TextBox with no border and add it into a panel which is x pixels bigger than the TextBox. By altering the Panel (and keeping the TextBox in the middle) you can vary the appearance of the TextBox's border.

Option 2:

A more robust solution, but more of a pain. You could create your own Custom Control and inherit from TextBox. By setting the TextBox's Border to None, you would then be able to draw your own border onto the control. This has the advantage of you being able fto exactly control what the border looks like (e.g. rounded corners etc.) but be warned, this can encroach on the text in the TextBox and look wierd. You could do it something like this:

public class BorderedTextBox: TextBox
{
    protected override void OnPaint( PaintEventArgs pe )
    {
        base.OnPaint(pe);

        // Draw your border here
    }
}
TK
your comments about the code above will be much appreciated... thanks!
yeyeyerman