我不能声称在 Silverlight 中处理文件的任何具体知识,但这是我将用于 WPF 应用程序中工作线程上的长任务的模式。在快速测试 Silverlight 项目中似乎可以正常工作。
我会避免尝试在线程之间传递流。相反,请计算出您的后台任务所需的参数集并创建一个对象以将它们传递给您的线程。让后台线程打开文件。因此,如果您需要一个文件夹来搜索要压缩的文件以及将压缩文件放入的输出位置,您可以声明:
class TaskStartupInfo
{
public string SourceFolder { get; set; }
public string TargetFile { get; set; }
}
然后你可以创建这个类的一个实例,并将它传递给你的后台任务:
private void startTaskButton_Click(object sender, RoutedEventArgs e)
{
TaskStartupInfo tsi = new TaskStartupInfo()
{
SourceFolder = @"C:\Some\Folder\",
TargetFile = @"C:\AnotherFolder\data.zip"
};
ThreadPool.QueueUserWorkItem(o => longRunningProcess(tsi));
}
在您的情况下,路径可以来自您在主 UI 线程上运行的 SaveFileDialog - 因为该线程不会与运行大部分工作相关联。然后,您的longRunningProcess()
方法可以获取数据并使用它:
private void longRunningProcess(object o)
{
TaskStartupInfo tsi = o as TaskStartupInfo;
int taskLength = calculateTaskLength()
// open any files required
this.Dispatcher.BeginInvoke(() => { progressBar1.Value = 0; progressBar1.Maximum = taskLength; });
for (int i = 0; i < taskLength; i++ )
{
doSomethingSlow();
this.Dispatcher.BeginInvoke(() => progressBar1.Value += 1);
}
// close / dispose files
}
请注意,任何访问 UI 对象(progressBar1
在本例中)的尝试都是通过使用 Dispatcher 对象运行委托来完成的。此调度程序处理确保 UI 对象仅由 UI 线程更新的问题。这应该确保您的进度条在任务的每个片段完成后更新。
编辑:根据 OP 的评论,并进行了一些进一步的挖掘,我看到 Silverlight 的安全沙箱对桌面 WPF 应用程序中未强加的文件访问施加了限制。
写入独立存储之外的文件系统确实需要运行 Silverlight 应用程序。这可以配置为项目属性的一部分 - 在属性的 Silverlight 选项卡上有一个“启用浏览器不足”复选框,一旦启用,它下面的“浏览器设置不足”按钮允许您打开一个更多选项对话框,其中包含“在浏览器外运行时需要提升信任”复选框。我还没有测试过,但这个选项听起来肯定不会在浏览器中获得更高的信任——因此检查代码中的安全错误并在发生信任度较低的情况时处理它可能是有意义的。
启用该设置后,您似乎可以使用普通流访问用户库中的文件,但不能访问文件系统上的其他位置。默认情况下,OpenFileDialog
和SaveFileDialog
类返回问题中暗示的流,但如果您愿意,它们都允许您访问文件名而不是流。打开文件时,文件名隐藏在
myOpenFileDialog.File.FullName
并且为了节省您似乎可以使用
mySaveFileDialog.SafeFileName
反而。
因此,以下代码可以在提升的 Out-of-Browser 应用程序中运行:
private void start_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() != true)
{
return;
}
TaskStartupInfo tsi = new TaskStartupInfo()
{
SourceFolder = @"C:\Users\MyUser\Documents\Information",
TargetFile = sfd.SafeFileName
};
ThreadPool.QueueUserWorkItem(o => longRunningProcess(tsi));
}
private void longRunningProcess(object o)
{
TaskStartupInfo tsi = o as TaskStartupInfo;
var files = Directory.EnumerateFiles(tsi.SourceFolder);
int taskLength = files.Count();
this.Dispatcher.BeginInvoke(() => { progressBar1.Value = 0; progressBar1.Maximum = taskLength; });
using (StreamWriter fs = new StreamWriter(tsi.TargetFile))
{
foreach(string file in files)
{
fs.WriteLine(file);
doSomethingSlow();
this.Dispatcher.BeginInvoke(() => progressBar1.Value += 1);
}
}
}
这为您提供了文件访问权限和正确更新的进度条,用于处理背景中的文件。