views:

235

answers:

3

I'm trying to create a search tool and would like to display the results in a text box, much like the one contained in Visual Studio - this means that for long searches results will be appended to the end of the text box while the user is attempting to look at the results at the top of the text box.

At the moment I'm using a standard textbox, however it has many problems:

  • The text box flickers madly while the search is in progress
  • Its not possible for the user to scroll while results are being appended to the box
  • Its not possible for the user to copy and paste results in the text box while results are being appended.

Are there any ways of working around these issues, or should I look into using another control / creating my own?

+1  A: 

Textboxes are good for editable content -- are the search results editable?

If you're displaying results to a search, why don't you use a DataGrid? You can design it to look however you want (it can look like a textbox with rows & rows of text)

statichippo
One of the reasons I wanted to use a text box was to allow users to copy and paste part of the results - for example I generally show the path to a match as well as an extract from the matching file to show some context. I want to the user to be able to do things like selecting a portion of the path, or selecting a portion of the matching text itself. Both are *possible* with a DataGrid, however are possibly more difficult to achieve and certainly less intuitive.
Kragen
+3  A: 

At first to access your TextBox while your search is running you should put your search into a BackgroundWorker and put the (intermediate) results with BeginInvoke() into your TextBox. So your GUI doesn't hang while your search is running.

Also you should use the TextBox.AppendText() method to add the text to your box. And if you want an auto-scroll use the two liner below after AppendText:

textBoxMessages.SelectionStart = textBoxMessages.Text.Length;
textBoxMessages.ScrollToCaret();

And if you want to enable/disable autoscroll you can before AppendText check if SelectionStart is equal to Text.Lenght and only if this is true make the above two liner after AppendText

Update

Ok, to get rid of that flickering there is no real solution within the textbox. When i mentioned right, you can give the RichTextBox a try, because it performs better with these scrolling problems.

Last but not least you can use ScintillaNET. I used it already several times and for these purposes it solves all the problems.

The only thing you can't do elegant by ScintillaNet (or better with Scintilla) is colorize manually a custom section. You have always to use a lexer which works with pre-defined formatting on a list of keywords.

Oliver
Nope - no joy. If I set the SelectionStart to somewhere near the top of the text box and then do ScrollToCaret every time I append, it just flickers really quickly as it alternates between being scrolled to where the text was last appended and where the caret is. I need some way of preventing it from drawing between appending the text, and scrolling the text box back to the top again (SuspendLayout doesnt seem to work for this)
Kragen
Scrintilla looks good - I think I'll give that a try - Thanks.
Kragen
+1  A: 

Microsoft forgot to implement the Begin/EndUpdate() methods for TextBox. You can add them yourself, it solves the problem. You can't get rid of the flicker though. Sample code:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
            timer1.Interval = 10;
            timer1.Tick += new EventHandler(timer1_Tick);
            button1.Click += new EventHandler(button1_Click);
        }
        void timer1_Tick(object sender, EventArgs e) {
            int pos = textBox1.SelectionStart;
            int len = textBox1.SelectionLength;
            SendMessage(textBox1.Handle, 11, IntPtr.Zero, IntPtr.Zero);
            textBox1.AppendText(DateTime.Now.ToString() + Environment.NewLine);
            SendMessage(textBox1.Handle, 11, (IntPtr)1, IntPtr.Zero);
            //if (textBox1 is RichTextBox) textBox1.Invalidate();
            textBox1.SelectionStart = pos;
            textBox1.SelectionLength = len;
        }
        private void button1_Click(object sender, EventArgs e) {
            timer1.Enabled = !timer1.Enabled;
        }
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }
}
Hans Passant
Thanks - that does help a lot, although it still seems to attempt to redraw the entire text box whenever I append. Is there any way to suppress that redraw?
Kragen
No, TextBox isn't smart enough. It just isn't made to do this.
Hans Passant