问题
So finally i managed to create a working BackgroundWorker.
I used the ReportProgress method to updated UI elements in this way:
bw.ReportProgress(1, node);
bw.ReportProgress(2, connection);
bw.ReportProgress(3);
bw.ReportProgress(4, system);
Where the connection is a model Object, this is my progress method:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 1) //update nodes
{
this.Network.Nodes.Add((NodeViewModel)e.UserState);
}
if (e.ProgressPercentage == 2) //update connections
{
this.Network.Connections.Add((ConnectionViewModel)e.UserState);
}
if (e.ProgressPercentage == 3)
{
this.Network.Connections.Clear();
this.Network.Nodes.Clear();
}
if (e.ProgressPercentage == 4)
{
MainNet.Systems.Add((Common.Model.System)e.UserState);
}
}
I have multiple objects to update so I used the percentage as a filter.
I'm getting different results every time i run the code, as if some of the data is not rendered correctly in the UI
The correct form of UI:
Not correct:
回答1:
If you need to synchronize your worker(s) to avoid reentrancy or a race, there are several different ways. You can try an approach like this...
private static void ManageBackgroundWorkers()
{
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
BackgroundWorker backgroundWorker2 = new BackgroundWorker();
BackgroundWorker backgroundWorker3 = new BackgroundWorker();
backgroundWorker1.DoWork += (s, a) =>
{
/* do stuff*/
};
backgroundWorker2.DoWork += (s, a) =>
{
/* do some more stuff*/
};
backgroundWorker3.DoWork += (s, a) =>
{
/* do even more different stuff*/
};
backgroundWorker1.RunWorkerCompleted += (s, a) =>
{
//this.Network.Nodes.Add((NodeViewModel)e.UserState);
backgroundWorker2.RunWorkerAsync();
};
backgroundWorker2.RunWorkerCompleted += (s, a) =>
{
//this.Network.Connections.Add((ConnectionViewModel)e.UserState);
backgroundWorker3.RunWorkerAsync()
};
backgroundWorker3.RunWorkerCompleted += (s, a) =>
{
// finish remaining tasks here
};
/* start the queue */
backgroundWorker1.RunWorkerAsync();
}
Each worker signals a completion and its event handler simply starts the next worker in the series. It is not a massive difference in what you have, but it repackages the steps that you were using the 'Percentage' property for. Percentage is really a bad proxy for state anyway. Refactoring your code should take about 5 minutes.
An alternative method is to instrument the callback with an ManualResetEvent that signals each time it is called. And the ManualResetEven is waited upon in the worker after each call to the ReportProgress handler. Messier, less modular, but indeed workable.
来源:https://stackoverflow.com/questions/23548685/wpf-mvvm-backgroundworker-ui-displaying-different-results