在SilverLight浏览器外应用程序中显示长时间运行的保存进程的进度
我有一个小小的SilverLight浏览器应用程序,它可以从网络摄像头到本地存储捕获一系列图像。然后,我希望通过Zip文件将它们从本地存储导出到用户指定的位置 到目前为止,如果所有事情都发生在主UI线程上,而没有其他方法,那么这是很平常的 但是,对于足够大的文件系列,zip文件的创建需要相当长的时间,因此我希望在后台工作线程或类似线程上执行此操作,并向用户报告进度 我的问题是: 如果我尝试在主UI线程上执行所有操作,则在保存完成之前,ProgressBar不会更新 尝试在后台工作线程上打开SaveFileDialog将不起作用,因为它是一个后台线程,也将被视为“非用户启动” 无论我如何将在SaveFileDialog中打开的流作为后台工作程序委托的一部分传递给该方法,它总是更改为在SilverLight浏览器外应用程序中显示长时间运行的保存进程的进度,silverlight,progress-bar,savefiledialog,Silverlight,Progress Bar,Savefiledialog,我有一个小小的SilverLight浏览器应用程序,它可以从网络摄像头到本地存储捕获一系列图像。然后,我希望通过Zip文件将它们从本地存储导出到用户指定的位置 到目前为止,如果所有事情都发生在主UI线程上,而没有其他方法,那么这是很平常的 但是,对于足够大的文件系列,zip文件的创建需要相当长的时间,因此我希望在后台工作线程或类似线程上执行此操作,并向用户报告进度 我的问题是: 如果我尝试在主UI线程上执行所有操作,则在保存完成之前,ProgressBar不会更新 尝试在后台工作线程上打开Sav
CanWrite==false
,我不能再使用它了
有没有人能举一个简单的例子,在SilverLight中保存一个大文件并报告进度?我不能说自己对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
}
为了节省时间,您似乎可以使用
mySaveFileDialog.SafeFileName
相反
因此,以下代码可以在提升的浏览器外应用程序中工作:
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);
}
}
}
这为您提供了文件访问和正确更新的进度条,用于处理后台文件。我不能声称对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
}
为了节省时间,您似乎可以使用
mySaveFileDialog.SafeFileName
相反
因此,以下代码可以在提升的浏览器外应用程序中工作:
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);
}
}
}
这为您提供了文件访问和正确更新的进度条,用于处理后台文件。我想我必须考虑使用提升的权限运行SL应用程序。问题是SL
SaveFileDialog
没有提供我可以访问的路径,只有用户指定的流——否则我甚至不会使用ZIP(它实际上只是所有图像的容器),我只会将文件直接写入路径。我相信,如果我被提升,我可以访问用户库文件夹而不受惩罚。为此,我欢呼——我本来不想运行提升,但在这种情况下,这似乎是愚蠢的。不过,运行提升版后,我可以完全删除整个zip文件,只需将图像直接写入“用户我的图片”文件夹中。我想我必须考虑使用提升版权限运行SL应用程序。问题是SLSaveFileDialog
没有提供我可以访问的路径,只有用户指定的流——否则我甚至不会使用ZIP(它实际上只是所有图像的容器),我只会将文件直接写入路径。我相信,如果我被提升,我可以访问用户库文件夹而不受惩罚。为此,我欢呼——我本来不想运行提升,但在这种情况下,这似乎是愚蠢的。不过,运行提升版后,我可以完全删除整个zip文件,只需将图像直接写入一个文件夹,即用户我的图片文件夹。