WPF mvvm backgroundworker UI displaying different

2019-09-04 20:19发布

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:

This is the correct form of UI

Not correct:

This is not correct

1条回答
狗以群分
2楼-- · 2019-09-04 20:59

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.

查看更多
登录 后发表回答