KondzioSSJ4
KondzioSSJ4

Reputation: 260

WPF - Threads and change variable

I have application with 1 simple thread:

 public partial class MainWindow : Window
    {    

        Thread historyThread = null;

        Window historyWindow = null;

        public MainWindow()
        {
            //...
        }

        #region EVENTS Magazyn
        private void btn_K_FinalizujZakup_Click(object sender, RoutedEventArgs e)
        {
            if (dg_Klient.Items.Count > 0)
            {
//Problem with 'Finalizuj' Method
                new Historia.Wpis(MainWindowViewModel.klient).Finalizuj(viewModel.historiaWindow_ViewModel.historiaZakupow);
                MainWindowViewModel.klient = new Klient.Klient();
                dg_Klient.ItemsSource = MainWindowViewModel.klient;
            }
        }

        #region History Thread
        private void btn_K_HistoriaOpen_Click(object sender, RoutedEventArgs e)
        {
            //if(historyThread != null){
            //    historyThread.Abort();
            //    historyThread = null;
            //}
            historyThread = new Thread(new ThreadStart(History_ThreadStart));
            historyThread.SetApartmentState(ApartmentState.STA);
            historyThread.IsBackground = true;
            historyThread.Start();
        }

        private void History_ThreadStart()
        {
            historyWindow = new HistoryWindow(viewModel.historiaWindow_ViewModel);
            historyWindow.Show();
            historyWindow.Activate();
            System.Windows.Threading.Dispatcher.Run();

        }
        #endregion // History Thread
        //...
    }

and 'Wpis' Class look like:

public class Wpis
{
    private DateTime date;
    public DateTime Date // normal get/ set

    private ObservableCollection<Produkt> listaZakupow;
    public ObservableCollection<Produkt> ListaZakupow // normal get/set

    public Wpis(ObservableCollection<Produkt> listaZakupow)
    {
        date = DateTime.Now;
        this.listaZakupow = listaZakupow;
    }

    public void Finalizuj(Historia historia)
    {
        //NOT! - Thread Safe

        // EXCEPTION!
        // NotSupportedException
        // This type of CollectionView does not support changes SourceCollection collection from a thread other than the Dispatcher.
        historia.Add(this);            
    }

    private void DoDispatchedAction(Action action)
    {
        if (currentDispatcher.CheckAccess())
        {
            action.Invoke();
        }
        else
        {
            currentDispatcher.Invoke(DispatcherPriority.DataBind, action);
        }
    }

}

And when I don't run thread (historyThread) I can normal do method 'Finalizuj' many times but when I run Thread I can't add anything to list (can't run method - 'Finalizuj') And VS show me exception about:

NonSupportedException was unhandled
This type of CollectionView does not support changes SourceCollection collection from a thread other than the Dispatcher.

I dont really know what i do wrong. What i need to add to my project?

In short: In main Thread - I have object_1 (typeof: ObservableCollection) In second Thread - I want add anothrer object (typeof: Wpis : ObservableCollection) to object_1 but I get the abovementioned exception

Upvotes: 1

Views: 1048

Answers (1)

tier1
tier1

Reputation: 6433

The Exception is telling you exactly what you need to do. You cannot modify the UI from a different thread. I'm assuming that your Observable collection is bound somewhere in your XAML.

You will need to obtain a reference to your MainWindow class so you can access the Dispatcher thread.

public static MainWindow Current { get; private set; }

        public MainWindow()
        {
            Current = this;
            //...
        }

Then use the Dispatcher thread to modify your collection:

        MainWindow.Current.Dispatcher.Invoke((Action)(() =>
        {
            historia.Add(this);
        }));

Upvotes: 1

Related Questions