近日,我所做的Silverlight项目有这么一个需求:点击一个控件,就像在HTML上点击一个超链接一样,由浏览器提示下载某一个文件,当然文件的Uri是已知,是通过这次点击触发的事件处理程序计算得到的。
为了实现这个目的,我试验了很多的方法,由于Silverlight只支持隔离存储区,而且它没有类似于超链接的控件,因此我必须求助于js和asp.net。在我转载的一篇文章里,那种手段的确让人眼前一亮,但是试验的结果却令我很不满意。在这里我模拟一下那种实现方法,并且给出结果。
Silverlight cs文件中代码如下:
aspx中的HTML代码如下:
aspx中js代码如下:
<script language="javascript" type="text/javascript">
function Button_onclick() {
window.open("http://www.cnblogs.com","_blank");
window.open("http://files.cnblogs.com/wodehuajianrui/BubblyStyleProject.zip", "_blank");
}
function silverlightbutton_onclick() {
if (arguments.length > 0) {
window.open(arguments[0], "_blank");
window.open(arguments[1], "_blank");
}
}
function setLinkHref() {
if (arguments.length > 0) {
open.href = arguments[0];
download.href = arguments[1];
}
}
</script>
解释一下这些代码的作用:首先,在sliverlight的xaml文件中我定义了一个button,它的事件处理代码如第一段所示,然后我在aspx页面中加入了一个div并加入了三个元素用于对比。运行效果如图所示:
首先我点击silverlight中的button,结果是打开两个页面,一个为博客园首页,另一个是指向一个file的链接,博客园首页成功打开并停留,另一个窗口自动关闭。
然后我点击aspx中的button,结果是打开两个页面,一个为博客园首页,另一个是指向一个file的链接,博客园首页成功打开并停留,另一个窗口提示文件下载。
由于点击silverlight的button同时为两个链接赋值,那两个链接也可以正常打开,指向文件的链接提示下载。
现在的问题就是,用silverlight调用js方法,这种打开文件链接的操作,会自动取消掉。即使我不从silverlight传递参数而直接调用js中的Button_click方法,结果是一样的,打开文件的新窗口会自动关闭,并不提示下载。
有意思的是,如果我们把代码稍作改动,将silverlight调用的js方法改为:
让那个文件在本窗口打开,事情就变得不一样了。如图所示:
在我允许下载之后,页面刷新,如果我再点击silverlight的button,文件下载的提示正常显示。相应的,我把aspx中button的响应代码也做修改:
运行结果如下:
并没有被浏览器拦截,而是正常提示下载。由此可见,sliverlight出于安全因素的考虑,极大地限制了它的行为。同时,这是我调用js的结果,如果我调用dom,让aspx页面向我的浏览器post一个文件,也会被拦截……本来我们用sliverlight是为了提高用户体验,但是这样页面频繁的刷新,而且还总跳出提示,让人非常的不爽。。。
我想投机取巧的方法也不是没有,微软在他的MSN space中的SkyDrive中,做了一些手脚,他的是一个aspx页,但是如果是通过Server主动将文件post过来的话,一定会被浏览器拦截的,所以微软的工程师想了一个办法,他们巧妙的应用CSS,将一个链接打扮得像一个button,连on:focus伪类都用上了,然后动态的利用js为链接的href赋值,从而当用户点击那个长得像button的链接的时候,就会直接下载文件(因为这是用户自己的get请求,所以浏览器不会拦截)。所以在silverlight上我们完全也可以使用类似的办法欺骗用户。。。。
说到这,我希望微软在开发下一个版本的silverlight时,考虑将这些限制解除,这样那样的限制实在太讨厌了,silverlight既然可以通过js来做一些事,我们何不让它就在托管的.net代码中做那些事呢?衷心希望能在方便和安全中间,找到一个万全之策!