wm5

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.

Coding on the xv6700

As it turns out, my phone was not developer locked as I had assumed from some of the sites I found. It was mostly a matter of getting VS.NET 2k5 to install its code on the phone. Not that that went without problems, and I gather I still need to figure out how rapiconfig enters into this.

I created a demo on VS.NET 2k5, deployed it to the phone and it failed without any useful error. However the program was over there, so I ran it manually. Problem with my version of .NET Compact Framework, i.e. i only had 1.1 and needed 2.0 for what Visual Studio built. I searched for a while how to target 1.1 from VS.NET 2k5 and found references claiming that I could choose at project creation. However I found no such option when I tried a new project. I think have a release candidate of 2k5 on my home machine, so maybe it’s supposed to be there and just not in my version. I will check on that tomorrow with my work machine, which has the official release on it.

So i fired up VS.NET 2k3. This one wouldn’t connect to my phone. Played around with the settings for a while, but no go. So I hand deployed the build and voila, first test running on the phone.

Good. But I don’t want to target 1.1 or use VS.NET 2k3, if i can avoid it. Can I upgrade my phone? I downloaded the .NET CF 2.o redistributable. It didn’t want to install. It complained about another version being on my machine.. Grrr.. I don’t care what my machine has, I want it on my phone! But I uninstalled the CF 2.0 I had, then re-installed the new one and it promptly upgraded my phone.

After the phone reboot, the phone no longer came up on my machine when i plugged it in. But that was just an artifact of the install, a rebbot fixed that. In the meantime, I fired up the binary I had previously built for 2.0 and now it worked as well. We’ve got a platform to play with!

By arne on | .net, geek | A comment?
Tags: