Tuesday, August 11, 2009

Nesting implicit styles in WPF

All I wanted to do was define a style at Page level to control the font size of Label controls, and then define other styles for parts of the page where Label controls need to be further customised.

e.g. set font size to 8pt at the top-level, and for some parts of the page, set each label to a specific width.

I Google-d around and thought the Style BasedOn attribute should do it for me.

Alas, it appeared not to.

But then I noticed a major bug in the VS.NET 2008 XAML designer : it was not properly applying style changes!

If I changed the text in a Label control, the XAML designer would reflect that, but if I changed relevant styles, the XAML designer would often miss it.

And that's where I realised : BasedOn IS the key, it's just that the VS.NET XAML designer is so pathetic that you have to close and re-open any XAML document you are editing in order to see the effect of nested style changes.

And of course, to make matters worse, VS.NET is famous for its idiotically slow load times for XAML files in large projects that contain lots of XAML files. So, hello lots more time being wasted now that we're forced to close and re-open XAML files just to get the designer to refresh properly...

Clarity Consulting wrote a nice little piece showing how to use BasedOn with nested implicit styles. The missing piece of the puzzle is simply the need to close and re-open the XAML designer each time you make a change. Ugggh. But at least it eventually gets to the desired effect...

Saturday, June 27, 2009

Flash AS3 Dictionary - bliss!

I came in on ActionScript at version 3, and with a strong javascript and .NET background.

Compared to javascript (which I quite like), I think ActionScript is even better. (They both have major issues, but I still quite like them, even if I hate the Flash software development tools which are "crappy as"...)

Sometimes you need to iterate a set of ActionScript object instances, and keep a record of some piece of data for each object instance.

In javascript it's easy - just add a new dynamic data field to each object instance.

But ActionScript adds the concept of "sealed" classes, which prevent the dynamic addition of new data fields.

So we're stuffed?

Well, there is a solution. Only one, but it works very well.

It's the new ActionScript 3 Dictionary.

It is an associative array keyed not by a string but by an object instance.

I use Dictionary objects all the time in other languages, so I was hoping ActionScript might have one, and I finally went looking for it, and found it yesterday.

Here are two articles I felt did a great job of introducing this powerful Dictionary object :

Viva la Dictionary!

Microsoft Silverlight stumbles at the gate

I have in the past predicted that Adobe Flash will lose out to Microsoft Silverlight.

But Microsoft keeps slipping up in one key area : ubiquity.

Silverlight was supposedly a technology that would run everywhere - including on mobile devices.

But Microsoft can't even get Silverlight running on their own Windows Mobile platform, let alone any other mobile devices.

On the other hand, Flash has Flash Lite, which is already on millions of handheld devices worldwide.

Yes, the Microsoft development tools actually work reliably, and yes, the Flash development tools are riddled with bugs, poorly documented, and priced uncompetitively.

But with the meteoric rise of handheld devices, and the lack of Silverlight support for any handheld devices (despite announcements over the past two years or so that "it's coming"), Microsoft is giving Adobe a massive breather.

A breather that may cost Microsoft years in their attempt to dominate this particular market.

If Adobe would make their tools and documentation at least as good as Microsoft's, then they could justify their price structure, and leave few incentives for anyone to use Silverlight.

But on the other hand, if Adobe continues to prove incompetent in QC for software development tools and documentation, and Microsoft finally gets their act together with the long-promised and I'm-growing-tired-of-waiting-for "Silverlight for mobile", then my original prediction stands, and Silverlight will move out of the realm of predominantly line-of-business apps, more and more into the mainstream, until the days of Adobe's dominance are a distant memory like the Commodore 64.

Thursday, June 18, 2009

JetStart - the end of Start Menu clutter

JetStart is awesome!

It's rare that I'm yelling in excitement just reading about a product, or tripping over myself in my eagerness to tell the world about an amazing piece of software when I've only used it for two minutes, but such is the privileged case with JetStart.

As a programmer, I have dozens of tools & utilities installed over the years, and navigating my Start Menu is a nightmare. Painus Maximum, as my wife likes to say.

So often I find myself saying "I wish I could just type a few letters and see every Start Menu entry that matches". It would be so much quicker to start IZArc or PDF Creator or any of my other occassionally-used tools if I didn't have to pore over an entire screen covered by my sprawling Start Menu.

JetStart is my dream come true. Its integration into the Windows experience is neat and inobtrusive.

And it's fast.

Press the Start key, then start typing. Instant response!

Now THIS is good software. Yeah baby!

Top kudos to the guys at codesector.com who made it.

And no, its free, and I'm not getting any kickbacks for raving about it. I reckon you'll rave too if you're a power user like me with an overbloated Start menu. Give it a shot - what've you got to lose? :o)

Tuesday, June 9, 2009

Adobe Subscription Manager hiccups and workarounds

Adobe has released Adobe Creative Suite CS4 Design Edition on a Subscription basis to the Australian market only. It's an experiment, presumably, to determine whether it's worth doing on a worldwide basis.

It has a few unique glitches I had to fight with myself, so for the benefit of those who come after...

-

1) There is ABSOLUTELY NO STANDARD WAY to install the Subscription Edition if you have an expired trial version installed at the same time.

For example, I had a trial version of Flash.

The Subscription Edition installer said "oh - you already have Flash installed, so I don't need to install it again". But the problem is, the Flash that is installed with the Subscription Edition is a slightly different version of Flash that knows how to accept subscription-based license keys and otherwise interoperate with the Adobe Subscription Manager. The Flash trial, in contrast, will never recognise the Adobe Subscription Manager, even if your subscription is fully paid.

i.e. you're forced to uninstall everything, then re-install using the Subscription Edition DVDs.

A pain, but at least it works...

-

2) If your subscription expires, and you want to renew it, Adobe documentation says you need to use the Adobe Subscription Manager which, supposedly, is installed on your computer.

The problem is, there is no link to the Adobe Subscription Manager. Anywhere.

Even doing an exhaustive search of "C:\Program Files\Adobe" (including subfolders) failed to find it, using the wildcarded search term "*sub*.exe", and when that failed, the wildcarded search term "*man*.exe".

So I called Adobe tech support.

I note that they have a special phone queue just for Subscription Edition customers.

Hmmm - smacks of there being a lot of other people experiencing problems...

... but to their credit, I was speaking to a human within about 30 seconds! I was very impressed.

They wanted to know my customer number, which took me a while to dig out, but when finally they had linked me to my order, they were ready to answer any questions I might have.

I asked how to find the Subscription Manager. The woman on the other end found the answer very quickly - they must have a good search tool for their internal help docs, or else it must be a very common question (or both) - and it lives in C:\Program Files\Common Files\Adobe\Adobe Subscription Manager CS4 and is called AdobeSubscriptionManager.exe. Hurrah!

So I double-clicked.

And nothing happened.

Something fishy going on here...

I opened Task Manager and saw a program called ADOBES~1.EXE. Ah! I remembered seeing that earlier in the day. Suddenly it dawned on me - the Adobe Subscription Manager is probably supposed to be launched automatically, but at least in my case, it failed to ever show a UI, and got stuck running in the background.

But because there was one stuck instance of Adobe Subscription Manager running in the background, it prevented any new instances from starting.

Easy fix - I killed ADOBES~1.EXE using Task Manager, and double-clicked AdobeSubscriptionManager.exe again.

Waiting...

And after several seconds, huzzah! There it was.

I thanked the Adobe technician and proceeded to reactivate my subscription.

-

So there you have it, ladies & gentlemen - some little known issues with Adobe Subscription Manager, and corresponding workarounds.

Wednesday, May 20, 2009

Using Adobe BridgeTalk synchronously

So let's face it : writing synchronous code is a lot easier than writing asynchronous code. I can write asynchronous code easily enough, but it looks so much more cluttered, and/or takes so many more lines of code. I'm a big believer in simplicity.

So, if you want to whip up a simple script, and it doesn't need to win design awards, then I suggest you check out xbytor's cool little trick for using BridgeTalk synchronously. (Search on that page for "Send a synchronous message".)

Nice one, xbytor.

And in case that forum goes down, here's a copy of the most pertinent bit. (See the original thread for more questions, answers and examples.)

First, some utility code :

// Send a synchronous message. The result is returned.
// If a result doesn't come back in 'timeout' seconds, undefined is returned.
BridgeTalk.prototype.sendSynch = function(timeout) {
var self = this;
self.onResult = function(res) {
this.result = res.body;
this.complete = true;
}
self.complete = false;

self.send();

if (timeout) {
for (var i = 0; i < timeout; i++) {
BridgeTalk.pump(); // process any outstanding messages
if (!self.complete) {
$.sleep(1000);
} else {
break;
}
}
}

var res = self.result;
self.result = self.complete = self.onResult = undefined;
return res;
};
// for typos, provide an alias
BridgeTalk.prototype.sendSync = BridgeTalk.prototype.sendSynch;

And now an example of how to use it :

function test() {
var bridgeApp = "bridge-1.0";

if (!BridgeTalk.isRunning(bridgeApp)) {
BridgeTalk.launch(bridgeApp);
}

var bt = new BridgeTalk();
bt.target = bridgeApp;
bt.body = "new Date().toString()";
var res = bt.sendSynch(10);
alert(res);
};

test();

Once again, mega kudos to xbytor. Some coding purists might gag at the internal polling loop, but remember, we're not talking about production scripts released to thousands of users worldwide - we're talking about helping every developer be more productive by writing their own scripts more easily.

Adobe BridgeTalk woes

As just another look at how mind-numbingly idiotic a large proportion of Adobe APIs are, consider this attempt to use BridgeTalk :

var bt = new BridgeTalk();
bt.send();
alert('The message was sent successfully.');

We haven't specified a recipient, and we haven't specified an actual message.

But run the code, and guess what? Apparently, the message was sent successfully.

Especially for such a poorly-documented class as BridgeTalk is, developers rely on meaningful error messages (including input validation error messages) to figure out what's going wrong and how on God's beautiful green earth we're supposed to use the thing.

My original script looked more like this :

function BridgeTalkResultHandler(result)
{
alert('Hurrah! The callback came!' + result.body);
}
var bt = new BridgeTalk();
bt.targetApp = 'illustrator';
bt.body = 'alert("hello");';
bt.onResult = BridgeTalkResultHandler;
bt.send();
alert('The message was sent successfully.');

Translation : get Illustrator to show a message. Just an elementary test.

But plug this into the ExtendScript ToolKit and run it, and all you get is meaningless nonsense.

'The message was sent successfully' is given every time you run it, but Illustrator doesn't budge.

Well, thought I, perhaps Illustrator refuses to interact with the user (e.g. with the alert method) under some circumstances. So I changed the script to app.activeDocument.close(), and I left a document open in Illustrator, so I could see if something happened. Still nothing.

I removed the onResult handler to see if somehow that was causing the problem. Nothing changed.

And I stripped out more and more things, until I got to the code at the start of this article.

The behaviour is identical, for every version of the script.

In other words, BridgeTalk is doing absolutely nothing - not even any validation.

I even tried crazy things like :

bt.targetApp = 'illustraaaaaaaaaaaator';

... but there wasn't any complaint about the non-existent target.

Examples of BridgeTalk are not as plentiful as one might wish for, but my original code looks very much like the few examples I found.

All I can say is : this is typical of Adobe APIs. Poorly documented, counter-intuitive, and requiring wasteful trial-and-error to master.

If it was open-source, or some cheapo product, I'd excuse it. But when they want to charge thousands for their suite of products, you expect a LOT better than this.



Got it working - bt.target is the correct property name, not bt.targetApp. I'm not sure whether I read a bad example, or whether I misread an example, but in either case, my thesis stands - Adobe APIs are a dog to work with except only when everything is working perfectly. A helpful input validation error message, such as 'target property is required', would have saved me valuable time! C'mon Adobe, you know you can do better than this... What's worst is that Microsoft is now actually pretty good at making meaningful error messages (something they were hopeless at ten years ago) - so it's possible to have a moderately-self-documenting API, and that means Adobe has dropped the ball.