tags:

views:

208

answers:

4

I'm working through Ron Jeffries's Extreme Programming Adventures in C#. His main example is a simple XML text editor. Given the age of the book (published in 2004), I suspected that a lot of his initial coding, finding what line the cursor is on and where the insertion point is, can be replaced with new TextBox methods or properties. I'm Visual Studio 2005. Trying to keep with the spirit of Agile development and XP, I wrote some tests first:

[Test]
public void TestGetFirstCharIndexOfCurrentLine() {
  String[] newlines = new string[] { "<P>one</P>", "<P>two</P>" }; //TextLength == 20
  notepad.txtbox.Lines = newlines;
  Expect(notepad.txtbox.SelectionStart, EqualTo(20));
  Expect(notepad.txtbox.GetFirstCharIndexOfCurrentLine(), EqualTo(11));
  Expect(notepad.txtbox.GetLineFromCharIndex(11), EqualTo(1));
}

(I'm being lazy (erm... I mean I'm trying to save space). This code actually combines three tests that I actually run in separate methods.)

In any event, each of the tests fails. First, the txtbox.SelectionStart returns 0. This may be consistent with what the documentation suggests, but when I step through in debug, the value is 20. The other two tests yield similar results; a zero where I would expect a positive integer value. These latter two cases, in particular, do not comport with my reading of the documentation.

I would really appreciate a clue where I'm going wrong.

Thanks.

A: 

From reading the tests, it appears that GetLineFromCharIndex should return the number of the line corresponding to the index of the character in the combined strings. I suspect that we're missing some set up in the test as GetFirstCharIndexOfCurrentLine() ought to return 0 (I presume it's zero-based) rather than 11 since the current line ought to start at 0.

tvanfosson
It certainly returning zero but then what's the point of the method? Alternatively, what does "Index" really mean in this context? The documentation is ambiguous whether it's an index of the Text property, and therefore only 1st char in 1st line is 0. More on next rock...
EoRaptor013
Or, is there a separate index for each line. If the latter, the method is worthless since it always returns zero. I guess that's the real prob - MS doesn't define what Index means in this context.
EoRaptor013
+1  A: 

Ok, I haven't tested any of this, but I can make fairly educated guesses as to the reason for each of your results:

  1. When executing normally (not stepping through), you would expect SelectionStart to remain 0, since the property value needs to be fetched via the Windows message pump, which hasn't yet had time to run. However, when stepping through, the message pump does have time to execute and therefore SelectionStart will refer to the end of the text. I'm not confident about this, so I recommend a little testing.
  2. This should now be obvious, providing point 1 is valid.
  3. I believe the char at position 11 is in fact a CR (ASCII 13), which could be interpreted as being part of the first line. Admittedly, this is slightly confusing. Position 12 (or certainly 13) should return 1, for the second line.

This should explain things, though do let me know if any further tests disagree with my explanation.

Noldorin
OK, you're right about the CR. It is counted even though it does not appear in the debugger and does not affect the text length. Still working on the other two. Thanks!
EoRaptor013
+1  A: 

I think I have something of an answer. It seems to be an expansion from what Noldorin said about the message.pump.

If I do this:

  String[] newlines = new string[] { "<P>one</P>" }; //TextLength == 10
  notepad.txtbox.Lines = newlines;
  notepad.txtbox.AppendText("\n<P>two</P>");
  Expect(notepad.txtbox.SelectionStart, EqualTo(21));

The test passes. (BTW, I used this form first just to show myself that the AppendText method worked.) If, however, I do this:

  String[] newlines = new string[] { "<P>one</P>","<P>two</P>" };
  notepad.txtbox.Lines = newlines;
  Expect(notepad.txtbox.SelectionStart, EqualTo(21));

the test fails.

I have no real explanation except that first case triggers some event that resets the SelectionStart property. The second case simply instantiates the textbox with two lines, not triggering whatever event it is, and leaves SelectionStart at 0.

Interestingly, the following works exactly the opposite:

[Test]
public void TestGetLineFromCharIndex_UseAppendText() {
  String[] newlines = new string[] { "<P>one</P>" }; //TextLength == 10
  notepad.txtbox.Lines = newlines;
  notepad.txtbox.AppendText("\n<P>two</P>");
  Expect(notepad.txtbox.GetLineFromCharIndex(15), EqualTo(1));    
}

[Test]
public void TestGetLineFromCharIndex() {
  String[] newlines = new string[] { "<P>one</P>", "<P>two</P>" };
  notepad.txtbox.Lines = newlines;
  Expect(notepad.txtbox.GetLineFromCharIndex(15), EqualTo(1));
}

The first test fails; the second passes! Isn't life wonderful? I'm going to fool around a little more; I hope this is helpful to somebody!

EoRaptor013
BTW, in the second SelectionStart test, the return was 0,so it wasn't just me counting characters wrong.
EoRaptor013
+1  A: 

Not sure if this will solve it, but try inserting the following line after you've done all the TextBox manipulation (i.e. just before the first Expect call):

Application.DoEvents();

This should allow the Windows message pump to operate briefly and insure that the TextBox is in the correct state regardless of everything else. Also, the second test of your previous post might be failing because you use \n rather than \r\n (the standard line break sequence) in your call to AppendText.

Noldorin
\r\n! Too much Linux, I guess. This got the tests to pass, I'm assuming because MS, couldn't properly count the lines. Not sure why that should be, though. Oh well, live, learn, move on! Thanks!
EoRaptor013
Yeah, line breaks can be a confusing matter. One-character line breaks (\r and \n) are present/acceptable on Windows too, but only in certain situations (which I won't pretend to understand). This is why it's often wise to normalise line breaks when dealing with text from unknown sources.
Noldorin
System.Environment.Newline takes care of it, I guess. I'll have to check MONO to see if it has the same thing.
EoRaptor013