2011-07-16 9 views
1

WebカメラからLocalStorageへの一連のイメージをキャプチャするSilverLightアウトオブブラウザアプリケーションがあります。次に、Zipファイルを介してLocalStorageからそれらをユーザーが指定した場所にエクスポートしたいとします。SilverLightブラウザアプリケーションの長期保存プロセスの進捗状況を表示

これまでのところ、すべての方法がメインのUIスレッドで行われていて、追加の方法は必要ありません。

しかし、十分な大きさの一連のファイルでは、zipファイルの作成にかなりの時間がかかるため、バックグラウンドワーカースレッドなどでこの処理を行い、その進行状況をユーザーに報告します。

私の問題はこれです:

私がしようとすると、メインUIスレッド上ですべてを行う場合は、保存が完了するまで、プログレスバーが更新されません。

バックグラウンドワーカーでSaveFileDialogを開こうとすると、バックグラウンドスレッドとして機能せず、 "Not User Initiated"と見なされます。

SaveFileDialogで開いたStreamを、バックグラウンドワーカーの代理人の一員としてメソッドに渡しても、それは常にCanWrite == falseに変更され、もう使用できません。

SilverLightで大きなファイルを保存して進行状況を報告するという簡単な例がありますか?

答えて

1

Silverlightでのファイル処理の具体的な知識はありませんが、WPFアプリケーションのワーカースレッドで長いタスクに使用するパターンは次のとおりです。迅速なテストSilverlightプロジェクトでうまくいくようです。

私はスレッド間でストリームを渡そうとしません。代わりに、バックグラウンドタスクが必要とするパラメータのセットを試し、オブジェクトを作成してスレッドに渡します。バックグラウンドスレッドがファイルを開くようにします。あなたが宣言するかもしれない、zip化するファイルとに郵便番号を入れて出力場所を検索するためのフォルダを必要とするのであれば:

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()方法は、データを取得し、それに取り組むことができます:UIオブジェクト(この場合はprogressBar1)にアクセスしようとするが、デリゲートを実行するために、ディスパッチャオブジェクトを使用することによってどのように行われるか

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オブジェクトがUIスレッドによってのみ更新されることを保証するという問題を扱います。タスクの各断片が完了した後、プログレスバーが確実に更新されるようにする必要があります。


編集: OPのコメントに基づいて、およびいくつかの更なる掘削が行われた、私は、Silverlightのセキュリティサンドボックスは、デスクトップWPFアプリケーションで課されていないファイルへのアクセスに制限を課していることがわかります。

Isolated Storage以外のファイルシステムに書き込むには、実際に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ファイル全体を削除して、ユーザーのマイピクチャフォルダのフォルダに直接画像を書き込むことができます。 –

関連する問題