Take a look at that XMLKeyDownHandler method. It is fielding and decoding the keys typed to see if it likes them, but it s also doing actual work for the application. Most of it now is just debugging and information-providing methods , but take a look at the highlighted Keys.Enter case, for example. This code is manipulating the contents of the Textbox as follows :
Get the lines from the Textbox.
Figure out where the cursor is.
Allocate a new line buffer with room for two more lines.
Copy all the lines up to the cursor line.
Insert a blank line and one with a P tag.
Copy the rest of the lines into the buffer.
Set the Textbox text to the new lines.
Look at the code; can you see where it does those seven things? You ll be able to figure it out. But why should we have to figure out what code does? Why doesn t the code say what it does? We call that sb expressing intention .
We look at this code, and we realize that we haven t clearly expressed our intention in writing it. Perhaps even worse is that this functionality is all about manipulating the Textbox and not at all about being part of the form. That suggests that we want a new object, which we ll call a TextModel, to start handling the text processing.
Reflecting on what we would have to do to build this, one issue that Chet and I worried about was that the way it works now, the TextModel would have to have a reference to the view, or else the Form would have to rip stuff out of the Textbox and jam it into the TextModel and rip stuff out of the TextModel and jam it into the view. Both of these seemed wrong.
We could have stopped at this point and done some heavy design to figure out a really good way to do this. That would have stopped our progress on the actual project, which is to get the Enter key working and to have an acceptable design. We aren t entirely comfortable continuing with everything jammed together, but we don t feel that we should delay progress while we figure out a perfect design. This is a tradeoff we have to make every day: is our work good enough but not so good that we are wasting time?
It will turn out, as the code evolves, that a good design will emerge, and if we had more experience, we might have seen it right away. Our unfamiliarity with .NET and the way that events work caused us not to see the solution, so watch as we go forward to see how the design continues to improve. For now, Chet and I decided to do the refactoring we could see, because we re sure that breaking this function out into a separate TextModel object will help.
One more thing: if you know more C# than we did at the time we wrote the code above, you re probably wondering why we weren t using an ArrayList or some other more capable data structure. At the time, we didn t know much about ArrayList, and since the TextBox uses an array, we had gone down that path . Of course it s always good to know more, but this book isn t about what we should have known, or what you should know ”it s about what we do with what we know, to make the code better and better and better.
Chet and I actually fiddled with this a couple of different ways. I ll spare you our false starts. What we finally decided was that our TextModel wanted to think of the text as an array of lines, and that it would be fed the lines by the Form and have the lines taken back by the Form when processing was done. We realized that every time we called the model, we d have to give it the lines, and although that is grossly inefficient, we had no measurement that showed it was even noticeable in the real world. So we decided to live with it. This gets changed, for a while, a long time from now ”in Chapter 22, The Delegate from Troy.