我正在尝试在后台线程中加载文件,同时在 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);
}
}
}