Lately it seems that I’m been doing a lot of posts referring to “a customer”. Often they are different customers, but it really sounds impersonal, so in this one I’m going to name names and point fingers – in a friendly way, of course.
Last week Nicolas emailed me to get some advice on the Visual Studio 2008 Forms designer and the Compact Framework. Specifically he wanted to know if it’s possible to get a custom TabControl to be designable. My assumption is that either he’s inheriting from the stock version or they’ve created a fully custom control inheriting from ContainerControl – I didn’t ask because in either case the answer is simple: it’s not going to work in the designer.
I told him that it won’t work, but in retrospect I feel I’ve short-changed him a bit. As a developer, I like to hear a bit more than an “abandon all hope, ye who sail here for there be sea monsters” kind of response. Why doesn’t it work? More importantly, what are my options for a workaround?
In this case it’s interesting to note that even if he could get the designer to work for this control, I’d recommend that he not do it. And they why to that recommendation is far more interesting.
So, Nicolas, here’s the longer answer to your question.
First, you have to understand that the Studio Designer is very, very brittle. Any little quirkiness tends to send it into fits, and once broke you often spend large amounts of time unloading things, resetting the toolbox, restarting Studio or even restarting the PC. This is a huge time drain, so avoiding situations that break the designer is the first order of business.
Getting the designer working for a CF component is even worse. CF controls often make use of things that the desktop doesn’t even have, which the designer really hates. You also have to build the Controls for both versions of the CF (for Nicolas this is important since, at least last time I was with his team, they had versions of the application targeting CF 2.0 and CF 3.5). A control built against CF 3.5 will never show up in the designer of a CF 2.0 project. There’s also a major bug in the designer that limits CF 3.5 controls that I’ve written about before.
For designer support you also have to maintain an XMTA file and often end up having condition compiler statements which really make the code less readable. Workarounds for most of these issues exist. You can create separate set of “designer” assemblies that provide only stuff for the designer and minimal actual control logic. The problem with this is that you then have to maintain these things, which sucks up developer time that should be spent actually solving your business problem.
You can’t create a desktop assembly and use it for the designer because the designer will then suck in the full .NET framework as a reference and attempt to deploy that to the device when you want to debug.
So if the designer is so brittle and worthless, what’s a developer to do? Well, my general attitude is to provide “support” only for basic Controls, and by “support” I mean the inherent capability of the designer to show a box with the location and bounds of your control. No rendering. No styling. No collection editing.
Really the designer’s primary use for me is to aid in basic layout. I need to put a Control on a Form, set it’s location and Size and that’s it anyway. Anything else is done via code, and there’s nothing wrong with this. Embrace it as how you must work and your life becomes much simpler.
That’s all well and good for a simple Control, but what about a container like Nicolas is after? His team would like to be able to drop on a Tab control and design each individual Tab, right? So what are they to do?
Well, I think they’re looking at the problem wrong to begin with. I don’t blame them, people have been looking at this wrong for some time, and the simple existence of the TabControl tend to push people to look at it wrong. In general, my recommendation is to not use the TabControl in the first place.
First of all, it’s 2011. That ass-looking TabControl would have been ok back in 1995 (if the devices had existed then) since it looks just like the ass-looking Windows 95 interface.
It’s was an ok solution in 2000 when these devices were new and people thought of them as just “mini PCs” so extending the desktop paradigm to the device was what we did. Yes, we wished we could do a little more to make it pretty by adding icons and custom drawing, but it worked and users really didn’t expect anything more.
But it’s 2011. Users don’t use a stylus if they can avoid it. They know an elegant UI when they see one because they’ve been using a smartphone. Just because they have no choice in the app they use (this is an LOB app, so the user is locked in) is no excuse to not deliver something that is actually nice to use. The TabControl does not meet that. It’s tiny, it scrolls weird, and it’s ugly with no options to make it non-ugly. Plus it’s Tab motif. Name the last mobile app you used on a phone that used tabs. That’s what I thought. Abandon the piece of crap.
So what would I use? Obviously this will be subjective, as it’s what I would personally do given a blank slate. Nicolas is trying to put something into an already-existing, very large code base, so his mileage may vary, but I’m betting it won’t be too bad, and implementing this might actually do a lot toward getting other gains they really need like better transition time between views.
I’d start using the OpenNETCF IoC project. I’d split each of the existing “tabs” into individual SmartParts, which are now fully designable since they’re just UserControls. So there you are – the designer requirement is solved. I’d then place on the Form a pair of DeckWorkspaces. One would display the “selected” view and the other would replace the “tabs” of old with buttons or clickable images that would be used to select the current view. It would look something like this in the designer for the Form:
And then the SmartPart that goes into the bottom workspace might be something like this in the designer (well it would probably be a bit different, but you get the idea):
See, the designer works. It meets the business requirement that it provides a “tab-like” capability where the user selects an item across the bottom and the upper view changes. But now it’s not just usable with a stylus but it’s also likely to be usable with a finger (gasp!) and aesthetically it doesn’t make my want to poke my own eyes out. It’s a win-win. Plus now you can lazy-load the views *on demand* rather than loading up every damned control on every tab when the Form is brought up, so the user is going to be pleasantly surprised there too. Oh, and now it’s easy to change out “tabs” based on user rights or workflow and probably other benefits that I’m not thinking of.
Occasionally we’ve got to break out of the “what we know” and the “what we’ve always done” routine and look out at the horizon. By doing so we can often make some simple changes and make things easier for both the developer and the user, and that is how we make progress.