WPF DataGrid Multithreading Crash
===

I have a View with a `DataGrid` in it.
A ViewModel as `DataContext` where i can access a `DataTable` in a background object.
The background object has to work with the `DataTable` and keep it updated.
The user has also be allowed to make changes to that `DataTable`.

If i create a copy of the `DataTable` it stops crashing but the user is obviousely not working on the data.

If i leave access open for the user the program crashed inevitabely.

Here is a short program that will crash:

app.cs

    public partial class App : Application
    {
        public App()
        {
            SomeBackgroundThing background = new SomeBackgroundThing();
            MainWindowViewModel viewmodel = new MainWindowViewModel(background);
            MainWindowView view = new MainWindowView(viewmodel);
            view.Show();
        }
    }

main xaml

    <Window x:Class="NullPointerDataGrid.MainWindowView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid Name="datagrid" ItemsSource="{Binding Path=table, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
        </Grid>
    </Window>

and the program code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    using System.Data;
    using System.Diagnostics;
    using System.Timers;
    using System.ComponentModel;

    namespace NullPointerDataGrid
    {
        public partial class MainWindowView : Window
        {
            public MainWindowView(MainWindowViewModel model)
            {
                DataContext = model;
                InitializeComponent();
                datagrid.Loaded += new RoutedEventHandler(ScrollToBottom);
                datagrid.AutoGeneratedColumns += new EventHandler(StarSizeLastRow);
 
            }

                                                            void ScrollToBottom(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("TableGrid_ScrollToBottom");
            if (datagrid.Items.Count > 0)
            {
                var border = VisualTreeHelper.GetChild(datagrid, 0) as Decorator;
                if (border != null)
                {
                    var scroll = border.Child as ScrollViewer;
                    if (scroll != null) scroll.ScrollToEnd();
                }
            }

        }

                                            void StarSizeLastRow(object sender, EventArgs e)
        {
            Debug.WriteLine("TableGrid_StarSizeLastColumn");
            try
            {
                datagrid.Columns[datagrid.Columns.Count - 1].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            }
            catch { }
        }

        }

                                                                                                                                        public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private SomeBackgroundThing thing;
        public DataTable table
        {
            get
            {
                lock (thing.table)
                {
                    //DataTable wpfcopy = thing.table.Copy();
                    return thing.table;
                };
            }
            set
            {
                Debug.Write("This never happens");
            }
        }

        public MainWindowViewModel(SomeBackgroundThing thing)
        {
            this.thing = thing;
            thing.Changed += new EventHandler(thing_Changed);
        }

        void thing_Changed(object sender, EventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("table"));
            }
        }

        
    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    public class SomeBackgroundThing : IDisposable
    {
        public DataTable table;
        private DataTable tablecopy;
        private System.Timers.Timer timer, slowrowchanger;

        public event EventHandler Changed = new EventHandler((o, e) => { ;});
        protected void CallChanged(object sender, EventArgs e)
        {
            Changed(sender, e);
        }

        public SomeBackgroundThing()
        {
            CreateTable();
            UpdateB(this, null);
            tablecopy = table.Copy();
            InitAndStartTimer(1);
        }

        #region timer

        private void UpdateA()
        {
            Boolean haschanged = false;
            DataTable newcopy = table.Copy(); ;
            if (newcopy.Rows.Count != tablecopy.Rows.Count)
            {
                Debug.WriteLine("Different ammount of rows");
                haschanged = true;
            }
            else if (newcopy.Columns.Count != tablecopy.Columns.Count)
            {
                Debug.WriteLine("Different ammount of columns");
                haschanged = true;
            }
            else
            {
                for (int i = 0; i < newcopy.Rows.Count; i++)
                {
                    for (int j = 0; j < newcopy.Columns.Count; j++)
                    {
                        if (newcopy.Rows[i][j].ToString() != tablecopy.Rows[i][j].ToString())
                        {
                            Debug.WriteLine(String.Format(
                                "Element [{0}/{1}]: {2} is different from {3}",
                                i, j, newcopy.Rows[i][j], tablecopy.Rows[i][j]
                                ));
                            haschanged = true;
                        }
                        if (haschanged) break;
                    }
                    if (haschanged) break;
                }
            }
            if (haschanged)
            {
                tablecopy = newcopy;
            }
        }

        private void InitAndStartTimer(int interval)
        {
            timer = new System.Timers.Timer();
            timer.Interval = interval;
            timer.AutoReset = true;
            timer.Elapsed += new ElapsedEventHandler((s, e) =>
            {
                UpdateA();
            });
            timer.Enabled = true;

            slowrowchanger = new System.Timers.Timer();
            slowrowchanger.Interval = 3000;
            slowrowchanger.AutoReset = true;
            slowrowchanger.Elapsed += new ElapsedEventHandler((s, e) =>
            {
                UpdateB(null, null);
            });
            slowrowchanger.Enabled = true;

        }

        public void Dispose()
        {
            timer.Enabled = false;
            slowrowchanger.Enabled = false;
            timer.Dispose();
            slowrowchanger.Dispose();
        }

        #endregion

        #region editlastrow

        void UpdateB(object sender, EventArgs e)
        {
            Random rnd = new Random();
            List<String> cells = new List<string>{
                    "The SAME", 
                    rnd.Next(0,100).ToString(), 
                    rnd.ToString(), 
                    rnd.NextDouble().ToString()};
            lock (table)
            {
                OverwriteOrAppendLastRow(ref table, cells);
                table.AcceptChanges();
            }
            CallChanged(this, null);
        }

        private void OverwriteOrAppendLastRow(ref DataTable table, List<string> newrow)
        {
            if (table.Rows.Count == 0) CreteEmptyRow(ref table);
            if (newrow[0].ToString() != table.Rows[table.Rows.Count - 1][0].ToString())
            {
                Debug.WriteLine(String.Format("Creating row because '{0}' is different from '{1}'", newrow[0], table.Rows[table.Rows.Count - 1][0]));
                CreteEmptyRow(ref table);
            }
            OverwriteLastRow(ref table, newrow);
        }

        private void OverwriteLastRow(ref DataTable table, List<string> newrow)
        {
            for (int i = 0; i < newrow.Count() && i < table.Columns.Count; i++)
            {
                table.Rows[table.Rows.Count - 1][i] = newrow[i];
            }
        }

        private void CreteEmptyRow(ref DataTable table)
        {
            table.Rows.Add(new String[table.Columns.Count]);
        }

        #endregion

        private void CreateTable()
        {
            table = new DataTable();
            table.Columns.Add("FirstCell", typeof(String));
            table.Columns.Add("BananaCell", typeof(String));
            table.Columns.Add("CherryCell", typeof(String));
            table.Columns.Add("Blue", typeof(String));
            Random rnd = new Random();
            for (int i = 0; i < 145; i++)
            {
                table.Rows.Add(new String[]{
                    rnd.Next().ToString(), 
                    rnd.Next(0,i+1).ToString(), 
                    rnd.ToString(), 
                    rnd.NextDouble().ToString()});
            }
        }
    
    }

    }

How can i stop this multithread crashing?
