我想在後臺線程中加載文件,同時在UI中顯示進度條。看起來BinaryFormatter.Deserialize
函數以及ProgressBar
的更新需要在STA線程上運行。我使用的是第三方物流庫到T askScheduler.FromCurrentSynchronizationContext()
傳遞到裝載任務,但這似乎給progressbar
更新和文件加載安排到相同線程,讓他們並行進行,而不是連續的。如何在.NET 4的後臺線程中使用二進制格式化器進行反序列化?
我試過將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);
}
}
}
綁定沒有任何元帥到UI線程。在非UI線程中更改屬性並引發INPC事件與從該線程觸及UIElement一樣糟糕。 – zmb
@zmb想打動你的心思?旋轉一個樣本並自己嘗試。不在我的辦公室或我會告訴你他的規格。 – Will
啊 - 看起來你是正確的(從.NET 3.5開始)。我認爲我所說的對於3.5之前的Silverlight,.NET以及集合和'INotifyCollectionChanged'仍然是正確的。 – zmb