There is an article over at Fast Company about Jeff Han, the guy responsible for the Multitouch demo that spread via YouTube a couple of months ago. When I saw that video I was mesmerized. Everything looked so natural. There was no need for explanation, every gesture once seen seemed like the obvious thing to do. It’s one of those brilliant inventions that once seen seems like it should always have been around. Well, the video attached to the Fast Company article is even more hypnotizing. Just beautiful.
And I guess the best thing is that this tech is going to hit the market, considering that half the interactions of the iPhone appear to be based on this research. Curious whether Han helped Apple or Apple engineers were inspired at TED. The article mentions PIXAR as an interested party, but not Apple. I do have to give Apple the nod for idea of taking multitouch to the phone. Seeing the multitouch video, I never even considered going to a smaller screen (and neither has Han if the new video is any indication). But it’s perfect for the small screen, since that input device of all is the one that needs to be more flexible to what people want to do, and anticipate their input, since there isn’t all that much room to get interaction from.
Any way you look at it, I wish Han’s company Perceptive Pixel
all the luch and funding to make multitouch the way we interact with computers in the future.
The Visible property on Controls is a bit misleading. Aside from the fact that setting it to true, is really only an advisory setting, since it’s truth is also dependent on all its parents, there is the issue that is has nothing to do with whether it’s actually visible when the form is painted.
Simple example: You have a Control A in a panel and that panel is half off-screen (or at least half across the edge of its container. And A is in the part of the panel that’s obscured. A is going to be Visible, even though its not visible.
The interesting thing is that the paint cycle knows this, and OnPaint won’t be called on the Control. Now wouldn’t it be nice if there was a property that told you that your Visible control won’t be drawn? If there is a simple way to determine this, I haven’t found it (especially not on .NETCF 1.0).
The way I do it now is that i use RectangleToScreen on the Control and then recursively walk up the parents, get their screen rectangle and call IntersectsWith on the control’s Rectangle and each Parent. As soon as i find one that doesn’t intersect, I know the Control is not going to be drawn.
If you are working on the .NET Compact Framework 1.0 and you get an ArgumentException trying to manipulate your UI (such as adding a Control to a form), you are likely doing this operation from a thread other than you UI thread and should be using Invoke. Thanks to jonfroelich‘s post “Controls.Add ArgumentException” for putting me on the right path. With all my frustrating debugging and unexplained freezes, i’d completely forgot that the particular code branch I was looking at was initiated by a callback from a WorkerThread.
Of course the Invoke facilities of .NETCF 1.0 are pitiful, lacking the things that make this whole single-threaded UI business bearable in regular Windows.Forms. There is not InvokeRequired for one thing, nor is there BeginInvoke. And even Invoke just provides the Invoke(Delegate) signature, not the much more useful Invoke(Delegate, Object[]).
Add to that that the only valid Delegate is an EventHandler, which takes two arguments, the exclusion of Invoke(Delegate, Object[]) really is painful.
Today started simple enough. I needed more debug info from my Smartphone app than just using the debugger could give me in a reasonable fashion. My usual solution is log4net for getting a debug spew, but trying to stay as simple as possible on the .NETCF 1.0, I decided to hit up System.Diagnostics instead. More to the point, System.Diagnostics.Debug.WriteLine() and its brethren.
Except, nothing showed up in the output window. Checking whether there was a config setting, then making sure that .NETCF 1.0 supported it, I was stumped. Finally I find out that the default TraceListener is only supported by VS.NET 2k5 if you use .NETCF 2.0. Now I don’t know if you’ve looked at deploying 2.0 apps in a world where even the most modern phones still ship with 1.0, but I certainly couldn’t find a clean and simple solution. Especially not one that didn’t require being tethered and downloading 40MB from MS, just so they can run a couple hundred kilobytes of App. And it’s a pity, because I run into something every day to which the answer is “Use .NETCF 2.0″. I want to, really, I do, but deployment convenience trumps developer convenience.
Next up was writing a custom TraceListener and wanting to be as unobtrusive to my Apps operation, I built it on UDP, i.e. a UdpTraceListener. Console based prototype code was up in about 20 minutes for the UdpTraceListener and the console app for listening to the spew. Then followed a couple of hours of testing and stepping through debug and not being able to get anything to be sent from my Emulator cradled via ActiveSync.
I even thought it might be because the phone Emulator couldn’t talk to the hosting computer and moved the console app to Mono on my server. That part worked flawlessly–copy the binary call mono UdpTraceConsole.exe and it was up and running. But it also received no data.
Then finally I find a chat log with the .NETCF team that reveals that UDP is not supported over ActiveSync. Nice.
Another 20 minutes of coding and i had a TcpTraceListener up in running in my console test harness. Woot. Time to put test on the phone, so i can finally get back to real coding….
Right. That would have been nice. The same game as before. Tried all sorts of permutations and received no data. Sometimes the debugger would throw a Socket Exception, usually it wouldn’t. It made no sense. I knew that TCP worked because I use HttpWebRequest extensively. So I tried putting my console listener on port 80. Nothing. Finally, I decided to open up a port on my firewall and forward it back to my dev machine so that I could try to contact my console listener via a network address from the outside world. And that finally worked. Only theory I have right now is that the DHCP setup via ActiveSync is screwy and it just can’t see any of my local net. I’ll investigate that later, for now I’m just happy to have a working debug spew.
And here is the exceedingly simple TcpTraceListener. Note: I use '\0' to denote the end of any message so my debug messages can include linefeeds.
using System; using System.Diagnostics; using System.Net.Sockets; using System.Net; using System.Text; namespace Droog.Diagnostics { public class TcpTraceListener : TraceListener { IPEndPoint endPoint; Socket console; public TcpTraceListener(IPEndPoint consoleEndPoint) { this.endPoint = consoleEndPoint; } private Socket ConsoleSocket { get { if (console == null || !console.Connected) { console = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); console.Connect(endPoint); } return console; } } public override void Write(string message) { try { ConsoleSocket.Send(Encoding.ASCII.GetBytes(message)); } catch { // this is for a debug spew. I'd rather swallow the exceptions // than have my debug code mess with my App. } } public override void WriteLine(string message) { Write(message + "\r\n\0"); } public override void Close() { if (console != null) { if (console.Connected) { console.Close(); } console = null; } base.Close(); } } }