0

I am having this error again: The calling thread cannot access this object because a different thread owns it.

Here is my code:

 public void InitiateSignalAnalysisPlot()
        {
            if (_nActiveChannel > 0)    // timeDomainPlotter init
            {
                _dataX = new List<double[]>();
                _dataY = new List<double[]>();

                _dataX3 = new List<List<double[]>>();
                _dataY3 = new List<List<double[]>>();

                double[] dataXOneCh = new double[1];
                double[] dataYOneCh = new double[1];

                dataXOneCh[0] = 0;
                dataYOneCh[0] = 0;

                CirclePointMarker pm = new CirclePointMarker { Size = 5, Fill = Brushes.Transparent };

                for (int i = 0; i < _nActiveChannel; i++)
                {
                    if (_nActiveStatsOneChannel > 0)
                    {
                        for (int j = 0; j < _nActiveStatsOneChannel; j++)
                        {
                            _dataX.Add(dataXOneCh);    // data x-y mapping init
                            _dataY.Add(dataYOneCh);

                            EnumerableDataSource<double> xOneCh = new EnumerableDataSource<double>(dataXOneCh);
                            EnumerableDataSource<double> yOneCh = new EnumerableDataSource<double>(dataYOneCh);

                            xOneCh.SetXMapping(xVal => xVal);
                            yOneCh.SetXMapping(yVal => yVal);

                            CompositeDataSource dsOneCh = new CompositeDataSource(xOneCh, yOneCh);

                            Action InitiatePlotter = delegate()
                            {
                                LineAndMarker<MarkerPointsGraph> lam = timeDomainPlotter.AddLineGraph(dsOneCh,
                                                                                       new Pen(pm.Fill, 2),
                                                                                       pm,
                                                                                       new PenDescription("C" + Convert.ToString(i) + "S" + Convert.ToString(j)));
                            };

                            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, InitiatePlotter);
                        }

                        _dataX3.Add(_dataX);
                        _dataY3.Add(_dataY);
                    }
                }

                timeDomainPlotter.FitToView();
            }
            else
            {
                return;
            }
        }

The error occurs at "this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, InitiatePlotter);" This is a piece of code behind a WPF window called by the main window thread. I am confused that I have used dispatcher.invoke() to void this multithread conflicting, why I am still getting this error? If I put this piece of code int he constructor of the window being called, it works, but I just don't want to do that way. What change can I make to I avoid this error? Thanks.

More information that might help : The timeDomainPlotter is in wpf window B, which is initiated (WindowB _windowB = new WindowB(); ) in window A; The code above, InitiateSignalAnalysisPlot(), is also in window B, but InitiateSignalAnalysisPlot() gets called in window A, something like _windowB,InitiateSignalAnalysisPlot();

If I don't Dispatcher.Invoke() it, there will also be an exception, which is The calling thread must be STA, because many UI components require this., happening at

LineAndMarker<MarkerPointsGraph> lam = timeDomainPlotter.AddLineGraph(dsOneCh,
                                                                                       new Pen(pm.Fill, 2),
                                                                                       pm,
                                                                                       new PenDescription("C" + Convert.ToString(i) + "S" + Convert.ToString(j)));
Nick Tsui
  • 524
  • 2
  • 9
  • 29
  • Maybe check if you need to invoke it at all with Dispatcher.CheckAccess() – Benny Feb 22 '13 at 15:03
  • When I typed Dispatcher, there was no CheckAccess() method popping up automatically..... – Nick Tsui Feb 22 '13 at 15:22
  • It is there; for some reason Microsoft decided to set Dispatcher.CheckAccess() and Dispatcher.VerifyAccess() to not show up in intellisense (the popup list of properties/methods/etc). If you just go ahead and type it anyway, it will compile. That said, CheckAccess() here won't actually tell you anything you don't already know. – Chris Feb 22 '13 at 15:28
  • Yup, the Dispatcher.CheckAccess() returns false. What does that mean? – Nick Tsui Feb 22 '13 at 15:30
  • It means that when you call Dispatcher.CheckAccess(), that call is running on the 'wrong' thread, i.e. a thread other than the one the Dispatcher is managing. But you already knew that, since that's why you're getting the exception. The CheckAccess() method is just a way of checking in advance rather than finding out when the exception happens. It's not new information and doesn't help you at all. – Chris Feb 22 '13 at 15:35
  • Any idea how I should change this to make it work? – Nick Tsui Feb 22 '13 at 15:37

1 Answers1

1

Where do you create timeDomainPlotter?

Controls created on different threads have different Dispatchers. My guess is that you're hitting this error because you're invoking your delegate via 'this.Dispatcher', but the control(s) you're touching within that delegate were created on a different thread and thus have a different dispatcher to 'this'.

If it's on a different thread, maybe you could set up a delegate for the creation and call that delegate via this.Dispatcher, then the control will be created on the same thread that you're later trying to access it on.

Chris
  • 4,661
  • 1
  • 23
  • 25
  • timeDomainPlotter was a control I dragged from toolbox onto a wpf window form, the form that gets called by the main window. The piece of code I posted is in the C# code behind the wpf form where the timeDomainPlotter is attached on. – Nick Tsui Feb 22 '13 at 15:27
  • Simplify this a little bit: timeDomainPlotter is a control tool on wpf form B. Form B is initiated (declared) in form A, and the piece of code above in my post is in form B, but the function (InitiateSignalAnalysisPlot()) gets called in form A. – Nick Tsui Feb 22 '13 at 15:34
  • Just to clarify a few things then. You have your main WPF window, which we'll call window A; that window opens another WPF window, which we'll call window B; the timeDomainPlotter control is in window B; and the InitiateSignalAnalysisPlot() method you gave us is in the codebehind for window B? If all that's correct, I'm not sure where the problem is... – Chris Feb 22 '13 at 15:37
  • Yes, that is correct, but the InitiateSignalAnalysisPlot() gets called in window A. something like _windowB.InitiateSignalAnalysisPlot(); where _windowB is declared in window A – Nick Tsui Feb 22 '13 at 15:40