Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Windows Forms
  4. Maintain Textbox Scroll Position

Maintain Textbox Scroll Position

Scheduled Pinned Locked Moved Windows Forms
question
9 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    K L K
    wrote on last edited by
    #1

    Hi, I'm outputting some logging output to a TextBox, using the following code:

        public void AddNewMessage( String message )
        {
            lock (this)
            {
                if (disposed)
                    throw new ObjectDisposedException( "PeerMessagesDisplay" );
    
                String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message );
                SetText( text );
            }
        }
    
        private void SetText( String text )
        {
            if (this.InvokeRequired)
                this.textBox1.Invoke( new Action( SetTextHelper ), text );
            else
                SetTextHelper( text );
        }
    
        private void SetTextHelper( String text )
        {
            this.textBox1.Text = text;
        }
    

    But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk

    madness ? this.isSparta = true : this.isSparta = false;

    R L 2 Replies Last reply
    0
    • K K L K

      Hi, I'm outputting some logging output to a TextBox, using the following code:

          public void AddNewMessage( String message )
          {
              lock (this)
              {
                  if (disposed)
                      throw new ObjectDisposedException( "PeerMessagesDisplay" );
      
                  String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message );
                  SetText( text );
              }
          }
      
          private void SetText( String text )
          {
              if (this.InvokeRequired)
                  this.textBox1.Invoke( new Action( SetTextHelper ), text );
              else
                  SetTextHelper( text );
          }
      
          private void SetTextHelper( String text )
          {
              this.textBox1.Text = text;
          }
      

      But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk

      madness ? this.isSparta = true : this.isSparta = false;

      R Offline
      R Offline
      Rob Smiley
      wrote on last edited by
      #2

      Use the AppendText method on the TextBox. I think that maintains the scroll position.

      "An eye for an eye only ends up making the whole world blind"

      K 1 Reply Last reply
      0
      • R Rob Smiley

        Use the AppendText method on the TextBox. I think that maintains the scroll position.

        "An eye for an eye only ends up making the whole world blind"

        K Offline
        K Offline
        K L K
        wrote on last edited by
        #3

        Hey Rob, This is a better solution, you are right. Unfortunately, it still always keeps the textbox's scroll position locked at the bottom. Is there a way around that? klk

        madness ? this.isSparta = true : this.isSparta = false;

        R 1 Reply Last reply
        0
        • K K L K

          Hey Rob, This is a better solution, you are right. Unfortunately, it still always keeps the textbox's scroll position locked at the bottom. Is there a way around that? klk

          madness ? this.isSparta = true : this.isSparta = false;

          R Offline
          R Offline
          Rob Smiley
          wrote on last edited by
          #4

          Hi klk, I tried a couple of things here to try & get this working! Simplest solution is to use the SelectionStart property, although this is still not ideal... Try this:

              Dim i As Integer = TextBox1.SelectionStart
              Dim atEnd As Boolean = i >= TextBox1.Text.Length
          
              TextBox1.AppendText("New line: " + TextBox1.Text.Length.ToString() + vbNewLine)
          
              If Not atEnd Then
                  TextBox1.SelectionStart = i
                  TextBox1.ScrollToCaret()
          
              End If
          

          Other than this, you could look at using the native scroll functions (GetScrollInfo, SetScrollInfo) - see google & msdn for more info about these. Hope this helps! Rob

          "An eye for an eye only ends up making the whole world blind"

          K 1 Reply Last reply
          0
          • R Rob Smiley

            Hi klk, I tried a couple of things here to try & get this working! Simplest solution is to use the SelectionStart property, although this is still not ideal... Try this:

                Dim i As Integer = TextBox1.SelectionStart
                Dim atEnd As Boolean = i >= TextBox1.Text.Length
            
                TextBox1.AppendText("New line: " + TextBox1.Text.Length.ToString() + vbNewLine)
            
                If Not atEnd Then
                    TextBox1.SelectionStart = i
                    TextBox1.ScrollToCaret()
            
                End If
            

            Other than this, you could look at using the native scroll functions (GetScrollInfo, SetScrollInfo) - see google & msdn for more info about these. Hope this helps! Rob

            "An eye for an eye only ends up making the whole world blind"

            K Offline
            K Offline
            K L K
            wrote on last edited by
            #5

            Hey Rob, I tried that solution, but the SelectionStart property refers to where the cursor is, not the scrollbar. Basically, unless the user clicks inside the textbox to place the cursor somewhere, it doesn't work. I looked up the P/Invoke stuff for Get/SetScrollInfo, but that's not working either! It still always jumps down to the bottom of the textbox. Here's my refactored code:

            public partial class PeerMessagesDisplay : Form
            {
                #region ScrollInfo
            
                \[DllImport( "user32.dll" )\]
                \[return: MarshalAs( UnmanagedType.Bool )\]
                private static extern bool GetScrollInfo( IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi );
            
                \[DllImport( "user32.dll" )\]
                static extern int SetScrollInfo( IntPtr hwnd, int fnBar, \[In\] ref SCROLLINFO
                    lpsi, bool fRedraw );
            
                \[StructLayout( LayoutKind.Sequential )\]
                struct SCROLLINFO
                {
                    public uint cbSize;
                    public uint fMask;
                    public int nMin;
                    public int nMax;
                    public uint nPage;
                    public int nPos;
                    public int nTrackPos;
                }
            
                private enum ScrollBarDirection
                {
                    SB\_HORZ = 0,
                    SB\_VERT = 1,
                    SB\_CTL = 2,
                    SB\_BOTH = 3
                }
            
                private enum ScrollInfoMask
                {
                    SIF\_RANGE = 0x1,
                    SIF\_PAGE = 0x2,
                    SIF\_POS = 0x4,
                    SIF\_DISABLENOSCROLL = 0x8,
                    SIF\_TRACKPOS = 0x10,
                    SIF\_ALL = SIF\_RANGE + SIF\_PAGE + SIF\_POS + SIF\_TRACKPOS
                }
            
                #endregion
            
                private String title;
                private String logFile;
            
                private bool disposed;
            
                public PeerMessagesDisplay( String title, String logFilePath )
                {
                    InitializeComponent();
            
                    this.title = title;
                    this.logFile = logFilePath;
            
                    this.Show();
                }
            
            
                public void LoadLog( )
                {
                    ThreadPool.QueueUserWorkItem( delegate
                    {
                        try
                        {
                            if (this.InvokeRequired)
                                this.BeginInvoke( new Action( delegate( String s ) { this.Text = s; } ), title );
                            else
                                this.Text = title;
            
                            using (FileStream fs = File.OpenRead( this.logFile ))
                            {
                                using (StreamReader reader = new StreamReader( fs ))
            
            R 1 Reply Last reply
            0
            • K K L K

              Hey Rob, I tried that solution, but the SelectionStart property refers to where the cursor is, not the scrollbar. Basically, unless the user clicks inside the textbox to place the cursor somewhere, it doesn't work. I looked up the P/Invoke stuff for Get/SetScrollInfo, but that's not working either! It still always jumps down to the bottom of the textbox. Here's my refactored code:

              public partial class PeerMessagesDisplay : Form
              {
                  #region ScrollInfo
              
                  \[DllImport( "user32.dll" )\]
                  \[return: MarshalAs( UnmanagedType.Bool )\]
                  private static extern bool GetScrollInfo( IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi );
              
                  \[DllImport( "user32.dll" )\]
                  static extern int SetScrollInfo( IntPtr hwnd, int fnBar, \[In\] ref SCROLLINFO
                      lpsi, bool fRedraw );
              
                  \[StructLayout( LayoutKind.Sequential )\]
                  struct SCROLLINFO
                  {
                      public uint cbSize;
                      public uint fMask;
                      public int nMin;
                      public int nMax;
                      public uint nPage;
                      public int nPos;
                      public int nTrackPos;
                  }
              
                  private enum ScrollBarDirection
                  {
                      SB\_HORZ = 0,
                      SB\_VERT = 1,
                      SB\_CTL = 2,
                      SB\_BOTH = 3
                  }
              
                  private enum ScrollInfoMask
                  {
                      SIF\_RANGE = 0x1,
                      SIF\_PAGE = 0x2,
                      SIF\_POS = 0x4,
                      SIF\_DISABLENOSCROLL = 0x8,
                      SIF\_TRACKPOS = 0x10,
                      SIF\_ALL = SIF\_RANGE + SIF\_PAGE + SIF\_POS + SIF\_TRACKPOS
                  }
              
                  #endregion
              
                  private String title;
                  private String logFile;
              
                  private bool disposed;
              
                  public PeerMessagesDisplay( String title, String logFilePath )
                  {
                      InitializeComponent();
              
                      this.title = title;
                      this.logFile = logFilePath;
              
                      this.Show();
                  }
              
              
                  public void LoadLog( )
                  {
                      ThreadPool.QueueUserWorkItem( delegate
                      {
                          try
                          {
                              if (this.InvokeRequired)
                                  this.BeginInvoke( new Action( delegate( String s ) { this.Text = s; } ), title );
                              else
                                  this.Text = title;
              
                              using (FileStream fs = File.OpenRead( this.logFile ))
                              {
                                  using (StreamReader reader = new StreamReader( fs ))
              
              R Offline
              R Offline
              Rob Smiley
              wrote on last edited by
              #6

              Hi, you need to set the cbSize and fMask fields before calling GetScrollInfo. Try using:

              scrollInfo.cbSize = Marshal.SizeOf(SCROLLINFO);
              scrollInfo.fMask = ScrollInfoMask.SIF_POS;

              I think this should work, but havn't tried it... Rob

              "An eye for an eye only ends up making the whole world blind"

              1 Reply Last reply
              0
              • K K L K

                Hi, I'm outputting some logging output to a TextBox, using the following code:

                    public void AddNewMessage( String message )
                    {
                        lock (this)
                        {
                            if (disposed)
                                throw new ObjectDisposedException( "PeerMessagesDisplay" );
                
                            String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message );
                            SetText( text );
                        }
                    }
                
                    private void SetText( String text )
                    {
                        if (this.InvokeRequired)
                            this.textBox1.Invoke( new Action( SetTextHelper ), text );
                        else
                            SetTextHelper( text );
                    }
                
                    private void SetTextHelper( String text )
                    {
                        this.textBox1.Text = text;
                    }
                

                But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk

                madness ? this.isSparta = true : this.isSparta = false;

                L Offline
                L Offline
                Luc Pattyn
                wrote on last edited by
                #7

                Hi, for displaying log information I prefer a ListBox over a TextBox. For one, it is much faster, since it keeps all the text lines apart, it never needs them all concatenated. Furthermore, it has a TopIndex property, which determines the scroll state. So a typical log method would consist of:

                void log(string s) {
                lb.Items.Add(s);
                lb.TopIndex=lb.Items.Count-1;
                }

                :)

                Luc Pattyn [Forum Guidelines] [My Articles]


                Voting for dummies? No thanks. X|


                K 1 Reply Last reply
                0
                • L Luc Pattyn

                  Hi, for displaying log information I prefer a ListBox over a TextBox. For one, it is much faster, since it keeps all the text lines apart, it never needs them all concatenated. Furthermore, it has a TopIndex property, which determines the scroll state. So a typical log method would consist of:

                  void log(string s) {
                  lb.Items.Add(s);
                  lb.TopIndex=lb.Items.Count-1;
                  }

                  :)

                  Luc Pattyn [Forum Guidelines] [My Articles]


                  Voting for dummies? No thanks. X|


                  K Offline
                  K Offline
                  K L K
                  wrote on last edited by
                  #8

                  Thanks luc, this worked perfectly.

                  madness ? this.isSparta = true : this.isSparta = false;

                  L 1 Reply Last reply
                  0
                  • K K L K

                    Thanks luc, this worked perfectly.

                    madness ? this.isSparta = true : this.isSparta = false;

                    L Offline
                    L Offline
                    Luc Pattyn
                    wrote on last edited by
                    #9

                    You're welcome. :)

                    Luc Pattyn [Forum Guidelines] [My Articles]


                    Voting for dummies? No thanks. X|


                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups