2011-07-16 39 views
1

我有一個SilverLight瀏覽器外的應用程序,它捕捉從WebCam到LocalStorage的一系列圖像。然後我希望通過Zip文件將它們從LocalStorage中導出到用戶指定的位置。在SilverLight中顯示長時間運行保存過程的瀏覽器應用程序的進度

到目前爲止,如果一切都發生在主UI線程上,而沒有其他方法,那麼這麼微不足道。

但是,對於足夠大的一系列文件,創建zip文件需要相當長的時間,所以我希望在後臺工作線程或類似情況下發生這種情況,並向用戶報告進度。

我的問題是這樣的:

如果我嘗試做的主UI線程上的所有內容,進度欄不更新,直到保存完成。

試圖在後臺打開SaveFileDialog Worker將不會工作,因爲它是後臺線程,並且也會被視爲「未啓動用戶」。

無論我如何將SaveFileDialog中打開的流傳遞給作爲後臺工作者委託的一部分的方法,它總是更改爲CanWrite == false,我無法再使用它了。

有沒有人有一個簡單的例子,在SilverLight中保存大文件和報告進度?

回答

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 
} 

注意如何任何企圖訪問UI對象(progressBar1在這種情況下)是通過使用分派對象運行的委託完成的。此調度程序處理確保UI對象僅由UI線程更新的問題。這應該確保在任務的每個片段完成後更新進度欄。


編輯:基於業務方案的意見,並且已經做了一些進一步深挖,我看到Silverlight的安全沙箱中規定未在桌面WPF應用程序強加文件訪問限制。

寫入獨立存儲之外的文件系統確實需要Silverlight應用程序運行時纔會提升。這可以配置爲項目屬性的一部分 - 在屬性的Silverlight選項卡上有一個「啓用瀏覽器不運行」複選框,一旦啓用了下面的「瀏覽器設置不足」按鈕,它允許您打開一個進一步的選項對話框具有「在瀏覽器外運行時需要提高信任」複選框。我沒有對它進行測試,但是這個選項聽起來好像不會在瀏覽器中獲得提升的信任 - 所以檢查代碼中的安全錯誤並處理較低的信任情況(如果發生的話)可能是有意義的。

啓用該設置後,您似乎可以使用普通流訪問用戶庫中的文件,但不能訪問文件系統中的其他文件。默認情況下,OpenFileDialogSaveFileDialog類會返回問題中隱含的流,但如果您願意,它們都允許您訪問文件名而不是流。當打開一個文件的文件名是

myOpenFileDialog.File.FullName 

下隱藏和保存你似乎能夠使用

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); 
     } 
    } 
} 

而且,讓你倆的文件訪問,並在backgrond文件的處理正確地更新進度條。

+0

我想我將不得不考慮使用提升權限運行SL應用程序。問題是SL'SaveFileDialog'沒有提供我可以訪問的路徑,只有用戶指定的流 - 否則我甚至不會使用ZIP(它實際上只是所有圖像的容器)只需將文件直接寫入路徑即可。我相信,如果我提升,我可以不受懲罰地訪問用戶庫文件夾。 –

+0

乾杯 - 我原本避開高架跑步,但在這種情況下,這似乎是愚蠢的。然而,運行提升後,我可以完全取消整個zip文件,只需將圖像直接寫入用戶My Pictures文件夾的文件夾即可。 –

相關問題