Skip to content

WM5 Multiline Textbox draw bug Hack

I know I'm not the only .NET developer for Smartphone. But it sure seemed that way when I tried to find a solution for a .NETCF 1.0 bug with multiline textboxes, hardly an uncommon Control, IMHO. After trying a number of different hacks, I finally have constructed one that seems to solve all problems. But what is this problem first of all?

The Bug: Multiline Textbox will not properly paint its background on Windows Media 5 devices under .NET Compact Framework 1.0

When the textbox is drawn, it will paint the back on any area that contains text, but leave any empty areas unpainted, i.e. showing whatever was previously on the screen. This is aggravated by the fact that T9 textinput will often partially obscure the Textbox and once the T9 pop-up disappears the Textbox won't repaint the dirty areas. The closest thing to an official recognition of this bug that I could find was a post on the MSDN Forums that said it was known and to switch to .NETCF 2.0. Now, I would love to switch to 2.0, since Windows.Forms on 1.0 of .NETCF is missing a lot. Unfortunately all current Smartphones ship with 1.0. I could require users to upgrade their phones. But even if i just plug the ARM .cab out of MS's redistributable, that's still a 6MB install, not insignficant for loading over the phone network nor for the memory available on the device. And all that so they can run a 500KB app? Right. That path is not an option.

The Solution: "Wipe" the textbox with an overlay on refresh

I initially hacked around the bug by first drawing the background and using a timer to draw the textbox itself a moment later. While this worked initially, it added a complication in having to hide the textbox to refresh it. Hiding it made it loose focus, so I had to catch that and refocus it. This in turn does screwy things with T9 text entry modes on most phones I tested.

The solution that does work without any sideeffects that i've found is simply to overlay the textbox with a background colored panel for a moment. Once the panel is removed, the Textbox repaints itself and any area not repainted because of the bug is left with the color of the overlay/. This does not affect focus, so it can be done at any time.

Let's assume you have TextBox _textBox_ and a Panel _wiper_ of equal size and placed overlapping in the form, as well as a disabled Timer _timer_ running at the shortest allowable interval. Finally you have a bool _wipe_ to indicate whether we've performed the wipe. With this setup the logic for "wiping" the TextBox clean is as follows:

private void Wipe()
{
  wiper.Visible = true;
  wiper.BringToFront();
  timer.Enabled = true;
  wipe = true;
}

private void timer_Tick(object sender, EventArgs e)
{
  if (wipe)
  {
    wiper.Visible = false;
    timer.Enabled = false;
  }
}

That solves the problem of painting the areas the TextBox forgets. We can call Wipe() on Refresh() or pretty much any time we know we obscured the control. Wouldn't it be useful if Invalidate was virtual in 1.0 as well? ho hum. Unfortunately it's completely up to you to know when your TextBox is Invalidated and needs a wipe-down.

If you are handling the UI, that's manageable, but what about those T9 pop-ups? For all your program knows there is no such thing. Even if you derived a class off of TextBox and overrode its OnPaint(), you'd still never see a paint message, because the actual textbox painting caused by the T9 pop-up appears to happen at the OS level, below .NET. To detect a T9 pop-up, or let's say, to infer that it's happening, you have to watch both the KeyDown and KeyPress events. As soon a s the T9 pop-up happens you won't be seeing your characters come through as KeyPresses anymore. Instead you will see KeyDown events being fired with a KeyCode of ProcessKey. The next time you see a KeyPress event, it's all the keys of the completed word being spewn into the TextBox. Therefore, if you see a keypress come in after a ProcessKey, you know a T9 pop-up just closed and it's a good time to wipe down your code>TextBox. Given a flag bool _inT9_, the code would look look this:

void textBox_KeyPress(object sender, KeyPressEventArgs e)
{
  if (inT9)
  {
    Wipe();
    inT9 = false;
  }
}

void textBox_KeyDown(object sender, KeyEventArgs e)
{
  if (e.KeyCode == Keys.ProcessKey)
  {
    inT9 = true;
  }
}

At the end of the day this is all fairly elaborate just to use a standard multi-line code>TextBox, but I have not found another way to do it on a stock Smartphone under .NETCF. I'd be glad to be proven wrong, but in the meantime, at least this is an option.