3

I have code example below. I want to use BackGroundWorker but I have an error.

Let me explain the code;

  • GridData property is the source of the DataGrid on the view.
  • I have a button which saves Excel data to db, it is bound with SaveExcel:ICommand class.
  • When I press this button it calls SaveExcel method in the viewmodel.
  • In SaveExcel method after saving excel I want to refresh grid data so I set GridData property with datatable.
  • When I set this property, PropertyChanged event is called which was delegated in SaveGrid:ICommand class.(this class is bound with another button)
  • Here, CanExecuteChanged method gives me error, "The calling thread cannot access this object because a different thread owns it".

How can I fix this?

Any help appreciated.

            public class MainViewModel
            {
                public DataTable GridData{get;set;}

                public void SaveExcel()
                {
                    .
                    .
                    .
                    RefreshGridData();
                }

                public void RefreshGridData()
                {
                    .
                    .
                    .
                    GridData = <selectedGridData>;
                }

                private void bgw_DoWork(object sender, DoWorkEventArgs e)
                {
                    SaveExcel();
                }
            }


            public class SaveExcel : ICommand
            {
                private MainViewModel viewModel;
                public SaveExcel(MainViewModel viewModel)
                {
                    this.viewModel = viewModel;
                    viewModel.PropertyChanged += (s, e) =>
                    {
                        if (CanExecuteChanged != null &&
                            (e.PropertyName == "SelectedA" || e.PropertyName == "SelectedB"))
                        {
                            CanExecuteChanged(this, new EventArgs());
                        }
                    };
                }

                public bool CanExecute(object parameter)
                {
                    return (viewModel.SelectedA != null && viewModel.SelectedB != null);
                }

                public event EventHandler CanExecuteChanged;

                public void Execute(object parameter)
                {
                    viewModel.bgw.RunWorkerAsync();
                }
            }


            public class SaveGrid : ICommand
            {
                private MainViewModel viewModel;
                public SaveGrid(MainViewModel viewModel)
                { 
                    this.viewModel = viewModel;
                    viewModel.PropertyChanged += (s, e) =>
                    {
                        if (CanExecuteChanged != null && e.PropertyName == "GridData")
                        {
                            CanExecuteChanged(this, new EventArgs());
                        }
                    };
                }

                public bool CanExecute(object parameter)
                {
                    return (viewModel.GridData.Rows.Count > 0);
                }

                public event EventHandler CanExecuteChanged;

                .
                .
                .
                .

            }
baris usanmaz
  • 839
  • 1
  • 13
  • 31

1 Answers1

4

You need to invoke the refresh on the UI thread, in WPF you can do that with a call to Dispatcher.Invoke at the appropriate place in your code. E.g

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => RefreshGridData()));
NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61