UIにプログレスバーを表示しながら、バックグラウンドスレッドでファイルを読み込もうとしています。BinaryFormatter.Deserialize
関数と更新ProgressBar
はSTAスレッドで実行する必要があるようです。TPLライブラリを使用してTをロードタスクに渡しますが、これにより、更新とファイルのロードが同じaskScheduler.FromCurrentSynchronizationContext()
スレッドにスケジュールされるため、並列ではなくシリアルに実行されるようです。 progressbar
TaskScheduler.Default
代わりにパスを試みましたLoadModelTask
が、これにより、BinaryFormatter.Deserialize
呼び出しでSTAエラーが発生します。
UIスレッドをフリーズする必要のないバックグラウンドでWPFオブジェクトをロードする別の方法はありますか?
私のコード:
private void openFile()
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.DefaultExt = FILE_EXTENSION;
dialog.Filter = "MFlow Documents|*.mpex;*.mpxc;*.mpoc";
Nullable<bool> result = dialog.ShowDialog();
if (result == true)
{
string filename = dialog.FileName;
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
CancellationTokenSource source=new CancellationTokenSource();
CancellationToken token = source.Token;
feedbackWindow = new FeedbackWindow();
feedbackWindow.ProgressBar.IsIndeterminate = true;
feedbackWindow.ProgressLabel.Content = "Opening " + filename;
feedbackWindow.Show();
Task<Model> loadModelTask=
Task.Factory.StartNew<Model>(() => LoadModel(filename),
token, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
loadModelTask.ContinueWith(task => AfterLoadModel(task), scheduler);
}
}
private static Model LoadModel(string filename)
{
Model returnModel;
string extension = filename.Split('.')[filename.Split('.').Length - 1];
Stream stream = File.Open(filename, FileMode.Open);
using (var gZipStream = new GZipStream(stream, CompressionMode.Decompress))
{
BinaryFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
var test = formatter.Deserialize(gZipStream);
returnModel = (Model)formatter.Deserialize(gZipStream);
gZipStream.Close();
stream.Close();
}
}
return returnModel;
}
private void AfterLoadModel(Task<Model> task)
{
try
{
task.Wait();
switch (task.Status)
{
case TaskStatus.RanToCompletion:
ModelResult = task.Result;
feedbackWindow.Close();
break;
default:
break;
}
}
catch (AggregateException ex)
{
// For demonstration purposes, show the OCE message.
foreach (Exception v in ex.InnerExceptions)
{
Debug.WriteLine("msg: " + v.Message);
}
}
}