TextBox vertical text alignment (Windows Forms)

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • alextj
    New Member
    • Sep 2009
    • 7

    TextBox vertical text alignment (Windows Forms)

    I need to align text to the bottom of a multiline TextBox in Windows Forms - can't figure out how!

    In WPF you can set the VerticalContent Alignment property, easy answer, but it looks like there is no such property in Windows Forms TextBox!

    But I have seen it done many times in Windows Forms-based apps and I wonder how do they do it?
  • cloud255
    Recognized Expert Contributor
    • Jun 2008
    • 427

    #2
    Hmmm, I couldn't get this right either, the closest I got to getting this right is to add a label to the textbox, set the label's parent to the textbox and set label's dockstyle to bottom. Maybe someone else has a better solution for the OP?

    Comment

    • GaryTexmo
      Recognized Expert Top Contributor
      • Jul 2009
      • 1501

      #3
      Ahhh, my brain refuses to process the problem apparently. Can you provide like a mockup or a mspaint image presenting what you what?

      Thanks, and sorry for my denseness :)

      Comment

      • alextj
        New Member
        • Sep 2009
        • 7

        #4
        What can be archived with this is a terminal-like application, where you type commands on the bottom of the window and the text scrolls from the bottom towards the top.
        Here is a screenshot of my quick and dirty CAN (Control Area Network) console app made using WPF, which uses textBox.Vertica lContentAlignme nt = VerticalAlignme nt.Top property:

        This looks like it's a very simple and basic feature, but somehow it seems it's missing completely from Windows Forms.

        Edit: I am not quite sure whether this forum image thing will work for everyone, so here's direct URL just in case:
        Code:
        http://img410.imageshack.us/img410/5440/textboxvalign.jpg

        Comment

        • GaryTexmo
          Recognized Expert Top Contributor
          • Jul 2009
          • 1501

          #5
          Oh ok cool, thanks. I thought that might have been what you meant, but I wasn't sure. I don't have time tonight so I'll take a look tomorrow.

          Comment

          • GaryTexmo
            Recognized Expert Top Contributor
            • Jul 2009
            • 1501

            #6
            I don't have an easy solution for you, unfortunately. I can't imagine why they have that functionality in WPF but not in .NET, it seems so useful! :)

            That said, I do have something for you... whether or not you want to use it over Cloud's solution is up to you. In your screenshot, it looks like you're not editing from the bottom up, just appending text to the text box that way. This makes life a little simpler... you just have to pad the text box with newline characters.

            This is the code for a form with a text box and a rich textbox (named appropriately) on it.

            Code:
                public partial class Form1 : Form
                {
                    string rawText = "";
            
                    public Form1()
                    {
                        InitializeComponent();
                    }
            
                    private void textBox1_KeyDown(object sender, KeyEventArgs e)
                    {
                        if (e.KeyCode == Keys.Return)
                        {
                            if (rawText != "") rawText += Environment.NewLine + textBox1.Text;
                            else rawText = textBox1.Text;
                            textBox1.Text = "";
            
                            Graphics g = richTextBox2.CreateGraphics();
                            SizeF singleLine = g.MeasureString("blah", richTextBox2.Font);
                            SizeF strSize = g.MeasureString(rawText, richTextBox2.Font);
            
                            // copy to the display RTB
                            richTextBox2.Clear();
            
                            string[] lines = rawText.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                            float textHeight = lines.Length * singleLine.Height;
                            float leftoverHeight = richTextBox2.Height - textHeight;
            
                            float pad = (float)Math.Ceiling(leftoverHeight / (double)singleLine.Height);
            
                            for (int i = 0; i < pad; i++)
                                richTextBox2.AppendText(Environment.NewLine);
                            richTextBox2.AppendText(rawText);
                            richTextBox2.ScrollToCaret();
                        }
                    }
                }
            Remember, this is just a rough test I did, which seems to work... you can clean it up a bit better if you want to use it. Also, you'd need to do something when the text box is resized because as it is, it doesn't realign itself when you change it.

            I hope that helped.

            Comment

            • alextj
              New Member
              • Sep 2009
              • 7

              #7
              Hi Gary, I've checked your code and wrote my own version here - it seems like a working hack - but hack it is indeed.

              This one has an input TextBox - the one where you type into and an output TextBox - the multiline TextBox which shows terminal output with the scrolling text. I use an ordinary multiline TextBox here.

              This version handles resizing too, by calling AlignTextToBott om() and ScrollToBottom( ) on Form1 - Size Changed event.

              Code:
              private void textBoxInput_KeyUp(object sender, KeyEventArgs e) {
              	if (e.KeyCode == Keys.Enter) {
              		textBoxOutput.AppendText(Environment.NewLine + textBoxInput.Text);
              		textBoxOutput_AlignTextToBottom();
              		textBoxOutput_ScrollToBottom();
              		textBoxInput.Clear();
              	}
              }
              private void textBoxOutput_AlignTextToBottom() {
              	int visibleLines = (int)(textBoxOutput.Height / textBoxOutput.Font.GetHeight())-1;
              	if (visibleLines > textBoxOutput.Lines.Length) {
              		int emptyLines = (visibleLines - textBoxOutput.Lines.Length);
              		for (int i = 0; i < emptyLines; i++) {
              			textBoxOutput.Text = (Environment.NewLine + textBoxOutput.Text);
              		}
              	}
              }
              private void textBoxOutput_ScrollToBottom() {
              	textBoxOutput.SelectionStart = textBoxOutput.Text.Length;
              	textBoxOutput.ScrollToCaret();
              }
              private void Form1_SizeChanged(object sender, EventArgs e) {
              	textBoxOutput_AlignTextToBottom();
              	textBoxOutput_ScrollToBottom();
              }
              I guess there are a few things that should be optimized here... The crazy amount of string operations at the time when the scroll buffer gets large enough is what's scaring me (I come from embedded software world - I'm clueless here).

              At the end I don't know how much resources this is gonna save compared to a WPF based application. It seems to consume less memory looking in Task Manager, but things will change once I add CAN interface. And what about CPU time?

              This is the first time I'm doing Windows app programming, so I'm quite new to the tools and haven't yet looked into how you guys measure performance here.

              Anyway thanks again for your replies, cloud and Gary :)

              Comment

              • GaryTexmo
                Recognized Expert Top Contributor
                • Jul 2009
                • 1501

                #8
                I agree it feels like a hack, but at the same time I'm not sure how else you'd do it. I mean, if I were to do this kind of thing in a console style program, I'd be taking pretty much the exact same approach :)

                That said, in terms of optimization, you actually shouldn't have much to worry about. Worst case scenario is when you have one line of text that needs to be pushed to the bottom of the text box. As you add more lines you actually add less padding, to the point where you aren't adding any.

                As for what it saves you over a WPF application, unfortunately I don't know anything about WPF so I can't really offer any insight there.

                Comment

                • alextj
                  New Member
                  • Sep 2009
                  • 7

                  #9
                  Yeah, that's true about the worst case scenario.

                  Actually, it adds padding only one time - at the first line of input. After that it already has the needed number of line breaks that fill the entire thing, so there is no more need to add anything after that.

                  Only when if you resize the window to be large enough, it will start adding more line fillers. But that, of course, only counts when the window is large enough to fit the entire text.

                  So yeah, you're right - I guess there's need to worry about it too much :)

                  Ahh - the bliss of the community - I wouldn't get this right without your help. Hope this topic helps someone with the same problem some day ;)

                  Comment

                  • cloud255
                    Recognized Expert Contributor
                    • Jun 2008
                    • 427

                    #10
                    Originally posted by alextj

                    At the end I don't know how much resources this is gonna save compared to a WPF based application. It seems to consume less memory looking in Task Manager, but things will change once I add CAN interface. And what about CPU time?
                    Well, I've also started delving into WPF over the last few months, in my experience it is far more resource intensive than winforms. But this is the direction that MS is taking .Net so maybe creating your application in WPF would give it a longer lifetime and I suppose the sooner all us .Net people get used to XAML the better...

                    Do remember that your core C# code will remain unchanged; WPF is just a technology for fancy UIs.

                    Comment

                    • alextj
                      New Member
                      • Sep 2009
                      • 7

                      #11
                      Originally posted by cloud255
                      Hmmm, I couldn't get this right either, the closest I got to getting this right is to add a label to the textbox, set the label's parent to the textbox and set label's dockstyle to bottom. Maybe someone else has a better solution for the OP?
                      I just gave this another though and realized that if label is used for output text - then the text cannot be selected, which is sometimes a needed feature. Add to that the fact that there is no vertical scrolling to view the history - and it makes it a pretty poor terminal application.

                      But if label text could be made selectable and a vertical scrollbar added - this solution would be a winner. I guess we can think of something to add the scrollbar, but what about selectable label text? Possible?

                      Comment

                      Working...