在浏览器应用程序外显示 SilverLight 中长时间运行的保存进程的进度
我有一个小型的 SilverLight 浏览器外应用程序,可以将一系列图像从网络摄像头捕获到本地存储。然后,我希望通过 Zip 文件将它们从 LocalStorage 导出到用户指定的位置。
到目前为止,如果一切都发生在主 UI 线程上,那么就很简单了,没有其他方法。
但是,对于足够大的文件系列,创建 zip 文件需要相当长的时间,因此我希望在后台工作线程或类似线程上进行此操作,并向用户报告进度。
我的问题是这样的:
如果我尝试在主 UI 线程上执行所有操作,则在保存完成之前 ProgressBar 不会更新。
尝试在后台工作线程上打开 SaveFileDialog 将不起作用,因为它是后台线程,并且也将被视为“不是用户启动的”。
无论我如何将 SaveFileDialog 中打开的 Stream 作为后台工作人员委托的一部分传递给该方法,它总是更改为 CanWrite == false
并且我无法再使用它。
有谁有一个在 SilverLight 中保存大文件并报告进度的简单示例吗?
I've got a little SilverLight Out-of-Browser app that captures a series of images from a WebCam to LocalStorage. I then wish to export them out of LocalStorage via a Zip file into a location specified by the user.
So far, so trivial if everything happens on the main UI thread, with no additional methods.
However, for a large enough series of files, the creation of the zip file takes considerable time, so I'd like to have this happen on a background worker thread or similar, and report the progress to the user.
My problem is this:
If I try and do everything on the main UI thread, the ProgressBar doesn't update until the save is complete.
Trying to open the SaveFileDialog on a Background Worker won't work as it's a background thread, and would also be considered "Not User Initiated".
No matter how I pass the Stream that was opened in the SaveFileDialog to the method as part of the delegate for the background worker, it's always changed to CanWrite == false
and I can't use it any more.
Does anyone have a simple example of saving a large file and reporting progress in SilverLight?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不能声称对 Silverlight 中的文件处理有任何具体的了解,但这是我在 WPF 应用程序中的工作线程上执行长时间任务时使用的模式。它在快速测试 Silverlight 项目中似乎工作正常。
我会避免尝试在线程之间传递流。相反,计算出后台任务所需的参数集并创建一个对象以将它们传递到线程。让后台线程打开文件。因此,如果您需要一个文件夹来搜索要压缩的文件以及一个将 zip 放入的输出位置,您可以声明:
然后您可以创建此类的一个实例,并将其传递到您的后台任务中:
在您的情况下,路径可以来自您在主 UI 线程上运行的 SaveFileDialog - 因为该线程不会与运行大量工作相关。然后,您的 longRunningProcess() 方法可以获取数据并使用它:
请注意如何通过使用 Dispatcher 来尝试访问 UI 对象(在本例中为
progressBar1
)对象来运行委托。该调度程序处理确保 UI 对象仅由 UI 线程更新的问题。这应该确保您的进度条在任务的每个片段完成后更新。编辑:根据OP的评论,并做了一些进一步的挖掘,我发现Silverlight的安全沙箱对文件访问施加了桌面WPF应用程序中没有施加的限制。
写入独立存储之外的文件系统确实需要提升 Silverlight 应用程序的运行权限。这可以配置为项目属性的一部分 - 属性的 Silverlight 选项卡上有一个“启用浏览器外运行”复选框,一旦启用,下面的“浏览器外设置”按钮允许您打开更多选项对话框,其中包含“在浏览器外部运行时需要提升信任”复选框。我还没有测试过它,但这个选项听起来肯定不会在浏览器内获得更高的信任 - 因此检查代码中的安全错误并在发生信任度较低的情况时进行处理可能是有意义的。
启用该设置后,您似乎可以使用普通流来访问用户库中的文件,但不能访问文件系统上的其他位置。默认情况下,
OpenFileDialog
和SaveFileDialog
类返回问题中暗示的流,但如果您愿意,它们都允许您访问文件名而不是流。打开文件时,文件名隐藏在下面并保存,您似乎可以使用
它。
因此,以下代码可以在提升的浏览器外应用程序中工作:
这为您提供了文件访问权限和正确更新的进度栏,用于在后台处理文件。
I can't claim any specific knowledge of file handling in Silverlight, but here's the pattern I'd use for a long task on a worker thread in a WPF application. It seems to work ok in a quick test Silverlight project.
I would avoid trying to pass streams between threads. Instead, work out the set of parameters your background task needs and create an object to pass them to your thread. Let the background thread open the files. So if you need a folder to search for files to zip up and an output location to put the zip into, you might declare:
Then you can create an instance of this class, and pass it into your background task:
In your case, the paths can come from a SaveFileDialog you run on the main UI thread - since that thread will not be tied up with running the bulk of the work. Your
longRunningProcess()
method can then take the data and work with it:Note how any attempt to access a UI object (
progressBar1
in this case) is done by using the Dispatcher object to run a delegate. This dispatcher deals with the issue of ensuring that the UI objects are only ever updated by the UI thread. That should ensure your progress bar updates after each fragment of the task is completed.Edit: Based on the OP's comments, and having done some further digging, I see that Silverlight's security sandbox imposes restrictions on file access that aren't imposed in a desktop WPF application.
Writing to the filesystem outside of Isolated Storage does indeed require that the Silverlight app be run elevated. This can be configured as part of the project properties - there is a checkbox for "Enable running out of browser" on the Silverlight tab of the properties, and once that's enabled the "Out of browser settings" button below it allows you to open a further options dialog which has the "Require elevated trust when running outside the browser" checkbox. I've not tested it, but that option certainly sounds like you wouldn't get elevated trust inside the browser - so it probably makes sense to check for security errors in your code and handle the lower trust situation if it occurs.
Once that setting is enabled, you seem to be able to use normal streams to access files in the user's Libraries, but not elsewhere on the filesystem. By default the
OpenFileDialog
andSaveFileDialog
classes return streams as implied in the question, but both of them do allow you access to the file name rather than the stream if you wish. When opening a file the filename is hidden underand for saving you appear to be able to use
instead.
So the following code can work in an elevated Out-of-Browser app:
And that gives you both file access and a correctly updated progress bar for the processing of the files in the backgrond.