Lots of programatic solutions so far. The solution however is to simply configure the ClientBin direcotry (or whatever folder you store your XAPs in) on the server.
Assuming IIS you need to explicitly specify the the ClientBin folder Expires Immediately. This will cause the correct cache configuration headers to be sent when the XAP is retrieved. In turn the browser will attempt to retireve the XAP each time its needed but in the vast majority of cases will simply get a 304 Unmodified response and it can continue to use its cached copy.
My guess is you are seeing the classic IE heuristic problem. In the absence of any cache configuration headers IE makes up its own mind whether to even bother to re-request a resource according to its own internal algorithms. By ensuring the correct expiry headers are sent IE will honor the servers instructions.
Edit
It seems that I need to make the operation of this approach clearer. This approach does not leave the XAP resource uncached and in need of fetching everytime its needed.
By specifying the Expire Immediately feature in IIS we get these headers in the Response:-
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 22359
Content-Type: application/octet-stream
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
ETag: "fe734cb3fa9ca1:1352"
This does not prevent the XAP from being cached it merely indicates the browser may not used the cached XAP without first requesting it from the server. Note the Last-Modified and ETag headers.
A subsequent request looks like this:-
GET /clientBin/SomeApp.xap HTTP/1.1
If-Modified-Since: Tue, 21 Jul 2009 11:59:28 GMT
If-None-Match: "fe734cb3fa9ca1:135a"
Host: myhost.com
The response is:-
HTTP/1.1 304 Not Modified
Cache-Control: no-cache
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
Tag: "fe734cb3fa9ca1:135a"
This response carries no entity body, it gives the browser permission to go ahead and use the existing XAP in the cache.
If the XAP is large then it is possible that the browser will not actually cache it with the Cache-Control specified as no-cache. Hence it may actually be better to be more explicit.
Instead of using the Expires Immediately box use configure the Cache-Control header using the Custom header list. Specify:-
Cache-Control: max-age=0
This will cause the browser to cache large XAPs whilst immediately expirying them.