aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Core/SynchronizedObservableCollection.cs
blob: e4deec540ec429e9ca2eb0c7fd3b35c68197c2b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;

namespace Tango.Core
{
    public static class SynchronizedObservableCollectionConfig
    {
        public static bool DisableSynchronization { get; set; }
    }

    public class SynchronizedObservableCollection<T> : ObservableCollection<T>
    {
        private object _sync_lock = new object();
        private object _modify_lock = new object();
        private SynchronizedObservableCollectionDispatcher _dispatcher;

        public bool DisableSynchronization { get; set; } = SynchronizedObservableCollectionConfig.DisableSynchronization;

        public SynchronizedObservableCollection() : base()
        {
            if (!DisableSynchronization)
            {
                _dispatcher = new SynchronizedObservableCollectionDispatcher();
                BindingOperations.EnableCollectionSynchronization(this, _modify_lock);
            }
        }

        public SynchronizedObservableCollection(IEnumerable<T> collection) : base(collection)
        {
            if (!DisableSynchronization)
            {
                _dispatcher = new SynchronizedObservableCollectionDispatcher();
                BindingOperations.EnableCollectionSynchronization(this, _modify_lock);
            }
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (!DisableSynchronization)
            {
                lock (_modify_lock)
                {
                    _dispatcher.Invoke(() =>
                    {
                        base.OnCollectionChanged(e);
                    });
                }
            }
            else
            {
                base.OnCollectionChanged(e);
            }
        }

        protected override void InsertItem(int index, T item)
        {
            if (!DisableSynchronization)
            {
                lock (_modify_lock)
                {
                    base.InsertItem(index, item);
                }
            }
            else
            {
                base.InsertItem(index, item);
            }
        }

        protected override void RemoveItem(int index)
        {
            if (!DisableSynchronization)
            {
                lock (_modify_lock)
                {
                    base.RemoveItem(index);
                }
            }
            else
            {
                base.RemoveItem(index);
            }
        }

        protected override void ClearItems()
        {
            if (!DisableSynchronization)
            {
                lock (_modify_lock)
                {
                    base.ClearItems();
                }
            }
            else
            {
                base.ClearItems();
            }
        }
    }

    internal class SynchronizedObservableCollectionDispatcher
    {
        internal Dispatcher Dispatcher { get; set; }

        internal SynchronizedObservableCollectionDispatcher()
        {
            if (Application.Current != null)
            {
                Dispatcher = Application.Current.Dispatcher;
            }
        }

        internal void Invoke(Action action)
        {
            if (Dispatcher != null)
            {
                Dispatcher.Invoke(action);
            }
            else
            {
                action();
            }
        }
    }
}