public Task ClearOnUIThread() => DispatcherTest.Run(async() =>
        {
            var _dispatcher = Dispatcher.GetForCurrentThread();

            var countFromThreadPool = -1;

            var source = new ObservableCollection <int>
            {
                1,
                2
            };

            var moc = new MarshalingObservableCollection(source);

            // Call Clear from a threadpool thread
            await Task.Run(() =>
            {
                source.Clear();
                countFromThreadPool = moc.Count;
            });

            // Check the result on the main thread
            var onMainThreadCount = await _dispatcher.DispatchAsync <int>(() => moc.Count);

            Assert.That(countFromThreadPool, Is.EqualTo(2), "Count should be pre-clear");
            Assert.That(onMainThreadCount, Is.EqualTo(0), "Count should be zero because the Clear has been processed");
        });
        public Task AddOffUIThread() => DispatcherTest.Run(async() =>
        {
            var _dispatcher = Dispatcher.GetForCurrentThread();

            int insertCount         = 0;
            var countFromThreadPool = -1;

            var source = new ObservableCollection <int>();
            var moc    = new MarshalingObservableCollection(source);

            moc.CollectionChanged += (sender, args) =>
            {
                if (args.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    insertCount += 1;
                }
            };

            // Add an item from a threadpool thread
            await Task.Run(() =>
            {
                source.Add(1);
                countFromThreadPool = moc.Count;
            });

            // Check the result on the main thread
            var onMainThreadCount = await _dispatcher.DispatchAsync <int>(() =>
            {
                return(moc.Count);
            });

            Assert.That(countFromThreadPool, Is.EqualTo(0), "Count should be zero because the update on the UI thread hasn't run yet");
            Assert.That(onMainThreadCount, Is.EqualTo(1), "Count should be 1 because the UI thread has updated");
            Assert.That(insertCount, Is.EqualTo(1), "The CollectionChanged event should have fired with an Add exactly 1 time");
        });
        public async Task ClearAndAddOffUIThread()
        {
            var countFromThreadPool = -1;

            var source = new ObservableCollection <int>
            {
                1,
                2
            };

            var moc = new MarshalingObservableCollection(source);

            // Call Clear from a threadpool thread
            await Task.Run(() =>
            {
                source.Clear();
                source.Add(4);
                countFromThreadPool = moc.Count;
            });

            // Check the result on the main thread
            var onMainThreadCount = await Device.InvokeOnMainThreadAsync <int>(() => moc.Count);

            Assert.That(countFromThreadPool, Is.EqualTo(2), "Count should be pre-clear");
            Assert.That(onMainThreadCount, Is.EqualTo(1), "Should have processed a Clear and an Add");
        }
        public Task MoveOffUIThread() => DispatcherTest.Run(async() =>
        {
            var _dispatcher = Dispatcher.GetForCurrentThread();

            int itemFromThreadPool = -1;

            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            // Replace a value from a threadpool thread
            await Task.Run(() =>
            {
                source.Move(1, 0);
                itemFromThreadPool = (int)moc[0];
            });

            // Check the result on the main thread
            var onMainThreadValue = await _dispatcher.DispatchAsync(() => moc[0]);

            Assert.That(itemFromThreadPool, Is.EqualTo(1), "Should have value from before move");
            Assert.That(onMainThreadValue, Is.EqualTo(2), "Should have value from after move");
        });
        public async Task InitialItemCountsMatch()
        {
            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            Assert.That(source.Count, Is.EqualTo(moc.Count));
        }
        public Task InitialItemCountsMatch() => DispatcherTest.Run(async() =>
        {
            var _dispatcher = Dispatcher.GetForCurrentThread();

            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            Assert.That(source.Count, Is.EqualTo(moc.Count));
        });
        public async Task IndexerConsistent()
        {
            int itemFromThreadPool = -1;

            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            // Call Remove from a threadpool thread
            await Task.Run(() =>
            {
                source.Remove(1);
                itemFromThreadPool = (int)moc[1];
            });

            Assert.That(itemFromThreadPool, Is.EqualTo(2), "Should have indexer value from before remove");
        }
        public async Task MoveOffUIThread()
        {
            int itemFromThreadPool = -1;

            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            // Replace a value from a threadpool thread
            await Task.Run(() =>
            {
                source.Move(1, 0);
                itemFromThreadPool = (int)moc[0];
            });

            // Check the result on the main thread
            var onMainThreadValue = await Device.InvokeOnMainThreadAsync(() => moc[0]);

            Assert.That(itemFromThreadPool, Is.EqualTo(1), "Should have value from before move");
            Assert.That(onMainThreadValue, Is.EqualTo(2), "Should have value from after move");
        }
        public async Task RemoveOffUIThread()
        {
            var countFromThreadPool = -1;

            var source = new ObservableCollection <int> {
                1, 2
            };

            var moc = new MarshalingObservableCollection(source);

            // Call Clear from a threadpool thread
            await Task.Run(() =>
            {
                source.Remove(1);
                countFromThreadPool = moc.Count;
            });

            // Check the result on the main thread
            var onMainThreadCount = await Device.InvokeOnMainThreadAsync <int>(() => moc.Count);

            Assert.That(countFromThreadPool, Is.EqualTo(2), "Count should be pre-remove");
            Assert.That(onMainThreadCount, Is.EqualTo(1), "Remove has now processed");
        }
        public async Task MarshalingObservableCollectionCollectionChangedAdd()
        {
            tlog.Debug(tag, $"MarshalingObservableCollectionCollectionChangedAdd START");

            TaskCompletionSource <bool>         tcs       = new TaskCompletionSource <bool>(false);
            NotifyCollectionChangedEventHandler onChanged = (s, e) => { tcs.TrySetResult(true); };

            var para          = new TestModel();
            var testingTarget = new MarshalingObservableCollection(para);

            testingTarget.CollectionChanged += onChanged;

            Assert.IsNotNull(testingTarget, "should be not null");
            Assert.IsInstanceOf <MarshalingObservableCollection>(testingTarget, "should be an instance of testing target class!");

            para.Add("Test");

            var result = await tcs.Task;

            Assert.IsTrue(result, "Change event should be invoked");
            Assert.AreEqual(testingTarget.Count, 21, "should be equal.");

            tlog.Debug(tag, $"MarshalingObservableCollectionCollectionChangedAdd END (OK)");
        }