简体   繁体   中英

Multithreading with events in WPF

UPDATE: As mentioned in the comments section the problem was solved, but I do not understand why my way of implementation was wrong.

I have this situation:

I have a device which can be triggered with an event in my WPF project. This event pulls Data from my device at a polling rate of 1ms. I want to process the data in different threads.

My approach was, to start a backgroundworker which registers the device event (I read events run on the thread they are called from). In the device event itself the data is saved to an object, which is declared in my form. After that the labels in the WPF form a are refreshed with a Invoke Method.

This happens until someone presses cancel on a button in my form, which unregisters the device event and stops the thread.

Here is some code I use:

Declaration in my Main Window:

 public partial class MainWindow : Window
    {

        private BackgroundWorker worker = new BackgroundWorker();
        private MeasureObject mObject = new MeasureObject();
    ... }

This is my initialization:

public MainWindow()
        {
            InitializeComponent();
            this.worker.WorkerSupportsCancellation = true;
            this.worker.DoWork += worker_DoWork;
            this.worker.RunWorkerCompleted += worker_RunWorkerCompleted;


        }

If this button is press i run my background worker:

  private void btnStartMeasure_Click(object sender, RoutedEventArgs e)
        {

            this.worker.RunWorkerAsync();

        }

Here I register my event for the device. It should now run on my worker thread. I tried to declare the event itself here too, but it did not work, so I placed it in my main windows.

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {

            this.myController.ControlCenter.Diagnostics.NewDiagPacketArrived += new EventHandler<NewDiagPacketArrivedEventArgs>(Diagnostics_NewDiagPacketArrived);
            // run all background tasks here
        }

This is not needed and empty. The worker is only cancelled if the user sets it on cancel.

        private void worker_RunWorkerCompleted(object sender,
                                               RunWorkerCompletedEventArgs e)
        {

        }

This event is triggered in my Window and calls two functions, it should run on the backgroundworker if I am correct.

private void Diagnostics_NewDiagPacketArrived(object sender, NewDiagPacketArrivedEventArgs e)
        {


            try
            {

                Measure(e);
                this.Dispatcher.BeginInvoke( new Action(() => { SetStates(e); }),System.Windows.Threading.DispatcherPriority.Input);

            }
            catch
            {

            }
        } 

Measure gets the e Object from the device and saves it to a Dataobject i created

 private void Measure(NewDiagPacketArrivedEventArgs e)
        {
            lock(this.mObject)
            {
                this.mObject.ID = this.list.Count;
                ....

               this.list.Add(this.mObject);


            }
   }

SetStates refreshed the GUI

private void SetStates(NewDiagPacketArrivedEventArgs e)
        {



            lock(this.mObject)
            {

                this.lblID.Content = this.mObject.ID;


            }

        }

The problem with my code is if I cancel the event and the thread with this code:

private void btnStopMeasure_Click(object sender, RoutedEventArgs e)
        {


            this.myController.ControlCenter.Diagnostics.NewDiagPacketArrived -= Diagnostics_NewDiagPacketArrived;
            this.worker.CancelAsync();

        }

And try to get the list where I added my objects, all objects have the same ID's and values. It seems like as soon as I unregister the event or press the stop measure button, all mObjects in my list get overwritten with the mObject at the time when I unregister the event.

so my list looks like this:

list[0].ID = 1
list[1].ID = 1
list[2].ID = 1

rather than this:

list[0].ID = 1
list[1].ID = 2
list[2].ID = 3

Maybe you can help?

Your problem is that you are not creating a new instance of the mObject - you only create one of them here:

private MeasureObject mObject = new MeasureObject();

Your code then adds the SAME object to the list, and updates that. You need to make a new object each time and put it in the list.

this.mObject.ID = this.list.Count;
                ....

               this.list.Add(this.mObject);

Currently your list is a list of the same object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM