Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.75/40: Рейтинг темы: голосов - 40, средняя оценка - 4.75
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923

Синхронизация асинхронного заполения списка и CancellationToken

06.10.2021, 14:07. Показов 8755. Ответов 95
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Открываю GUI страницу со списком картинок.
Проблема: из-за того, что картинки весят много -- какое-то время, допустим 2 секунды, страница просто пустая, а после резко заполняется всем списком.

Желаемый результат: хотелось бы, чтобы при открывании страницы элементы постепенно подгружались.

Решение 1: решил сделать само заполнение асинхронным (просьба сначала досмотреть все 3 решения)
C#
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
        protected async Task UpdateAll()
        {
            var devices = await devicesRepository.GetDevices(currentDevice == null ? Root : currentDevice.Id);
 
            await Task.Run(() =>
            {
                if (devices != null)
                {
                    var filterDevices = devices.FindAll(d => !d.IsArchived);
 
                    //remove old items
                    foreach (var oldItem in Devices)
                    {
                        if (filterDevices.Find(x => x.Id == oldItem.Id) == null)
                            Devices.Remove(oldItem);
                    }
 
                    //add or change new items
                    foreach (var newItem in filterDevices)
                    {
                        var elm = Devices.FirstOrDefault(x => x.Id == newItem.Id);
                        if (elm != null)
                        {
                            if (!newItem.Equals(elm))
                                elm = newItem;
                        }
                        else
                        {
                            Devices.Add(newItem);
                        }
                    }
                }
                else
                {
                    Devices.Clear();
                }
            });
 
            await UpdateContextMenu();
        }
Это решило мою проблему, но так я оставляю код потоконебезопасным.
Решение 2: добавил локировку
C#
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
        protected async Task UpdateAll()
        {
            var devices = await devicesRepository.GetDevices(currentDevice == null ? Root : currentDevice.Id);
 
            await Task.Run(() =>
            {
                lock (((ICollection)Devices).SyncRoot)
                {
                    if (devices != null)
                    {
                        var filterDevices = devices.FindAll(d => !d.IsArchived);
 
                        //remove old items
                        foreach (var oldItem in Devices)
                        {
                                if (filterDevices.Find(x => x.Id == oldItem.Id) == null)
                                Devices.Remove(oldItem);
                        }
 
                        //add or change new items
                        foreach (var newItem in filterDevices)
                        {
                            var elm = Devices.FirstOrDefault(x => x.Id == newItem.Id);
                            if (elm != null)
                            {
                                if (!newItem.Equals(elm))
                                    elm = newItem;
                            }
                            else
                            {
                                Devices.Add(newItem);
                            }
                        }
                    }
                    else
                    {
                        Devices.Clear();
                    }
                }
            });
 
            await UpdateContextMenu();
        }
Сильно сомневаюсь что такой подход можно назвать "потокобезопасным"
Далее я подумал, что если я выйду из страницы и резко зайду обратно -- у меня перепутаются все элементы и, весьма вероятно, продублируются или ещё чего похуже.
Решение 3: я подумал, что во время закрытия страницы будет уместным сделать cancelTokenSource.Cancel();
C#
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
        private static CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
        private CancellationToken token = cancelTokenSource.Token;
        protected async Task UpdateAll()
        {
            await UpdateAllTest();
        }
 
 
        protected async Task UpdateAllTest()
        {
            var devices = await devicesRepository.GetDevices(currentDevice == null ? Root : currentDevice.Id);
 
            await Task.Run(() =>
            {
                lock (((ICollection)Devices).SyncRoot)
                {
                    if (devices != null)
                    {
                        var filterDevices = devices.FindAll(d => !d.IsArchived);
 
                        //remove old items
                        foreach (var oldItem in Devices)
                        {
                            if (token.IsCancellationRequested)
                                return;
 
                                if (filterDevices.Find(x => x.Id == oldItem.Id) == null)
                                Devices.Remove(oldItem);
                        }
 
                        //add or change new items
                        foreach (var newItem in filterDevices)
                        {
                            if (token.IsCancellationRequested)
                                return;
 
                            var elm = Devices.FirstOrDefault(x => x.Id == newItem.Id);
                            if (elm != null)
                            {
                                if (!newItem.Equals(elm))
                                    elm = newItem;
                            }
                            else
                            {
                                Devices.Add(newItem);
                            }
                        }
                    }
                    else
                    {
                        Devices.Clear();
                    }
                }
                cancelTokenSource.Cancel();
            });
 
            await UpdateContextMenu();
        }
Когда закрываю страницу делаю:
C#
1
2
3
4
5
        public override void Deactivate()
        {
            base.Deactivate();
            cancelTokenSource.Cancel();
        }
Ужасный код, я понимаю. Ищу помощи тут.

Добавлено через 9 минут
Также хотел упомянуть следущий момент:
C#
1
2
3
4
await Task.Run(() =>
{
    lock (((ICollection)Devices).SyncRoot)
    //..
тут мне кажется я вообще полную чушь написал.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
06.10.2021, 14:07
Ответы с готовыми решениями:

BlockingCollection<T>, Add(T item, CancellationToken cancellationToken);
Возник вопрос в механизме метода Add() BlockingCollection. В реализации BlockingCollection есть возможность добавить как элемент...

Зачем нужен CancellationToken?
у CancellationTokenSource есть тот-же свойство IsCancellationRequested, и метод Cancel вызывается у CancellationTokenSource. Зачем они...

Не происходит отмена задачи (CancellationToken)
wpf создаю private CancellationTokenSource cts = new CancellationTokenSource(); на команде кнопки вперед реализую: private...

95
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 18:28  [ТС]
Студворк — интернет-сервис помощи студентам
Элд Хасп, сделал небольшой тест, предварительно увеличив количество элементов, чтобы уменьшить время погрешности.

Суммарное количество элементов -- 256
Начало - 18:19:47
Конец - 18:19:58

То есть страница открылась, но 10 секунд страница пустая.

За одну секунду -- 22 элемента

XML
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
[0:] 09/10/2021 18:19:47    Start...
[0:] 09/10/2021 18:19:47    var devices = Task.Run(async() => await devicesRepository.GetDevices(id)).Result;
[0:] 09/10/2021 18:19:47    lock (((ICollection)Devices).SyncRoot)
[0:] 09/10/2021 18:19:47    {
[0:] 09/10/2021 18:19:47        if (filterDevices.Count != 0)
[0:] 09/10/2021 18:19:47        {
[0:] 09/10/2021 18:19:47            Task.Run(async () => await Device.InvokeOnMainThreadAsync(() =>
[0:] 09/10/2021 18:19:47            {
[0:] 09/10/2021 18:19:47            }));
[0:] 09/10/2021 18:19:47        }
[0:] 09/10/2021 18:19:47    }
[0:] 09/10/2021 18:19:47                foreach (var newItem in filterDevices.Values)
[0:] 09/10/2021 18:19:47                {
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:47                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:48                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:49                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:50                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:51                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:52                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:53                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:54                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:55                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:56                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:57                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                    Devices.Add(newItem);
[0:] 09/10/2021 18:19:58                }
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
09.10.2021, 18:48
limeniye, это означает, что долго происходит создание представления одного элемента.
На один элемент требуется порядка 50мс - это много, конечно.

Чтобы сделать поэлементный показ в представлении, то нужно каждый элемент добавлять в отдельной задаче:
C#
48
49
50
51
52
53
54
55
56
57
                    //add new items
                    if (filterDevices.Count != 0)
                     foreach (var newItem in filterDevices.Values)
                     {
                            if (token.IsCancellationRequested)
                            return;
 
                            var item = newItem;
                            Device.InvokeOnMainThread(() => Devices.Add(newItem));
                     }
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 18:56  [ТС]
Элд Хасп, я запутался. Все остальное было InvokeOnMainThreadAsync, через Task
Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices[index] = newDevice));

Почему сейчас синхронно?

Device.InvokeOnMainThread(() => Devices.Add(newItem));
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
09.10.2021, 19:15
Цитата Сообщение от limeniye Посмотреть сообщение
Почему сейчас синхронно?
Описка - нужно InvokeOnMainThreadAsync.

BeginInvokeOnMainThread - ставит задачу в очередь.
InvokeOnMainThreadAsync - ставит в очередь и ожидает её выполнения.

Это Xamarin - я его не знаю. Но по аналогии с другими подобными методами.

Ожидание не влияет на лаги GUI поскольку весь метод выполняется в отдельной задаче на пуле потоков.

Для BeginInvokeOnMainThread, в общем случае, мы создаём 256 отдельных задач и все их ставим в очередь на исполнение, но мы не можем гарантированно знать в каком порядке они будут выполнены.
В результате можем получить иной порядок чем в коллекции filterDevices.Values.

В с методом InvokeOnMainThreadAsync мы добавляем один элемент, ждём пока завершится его добавление, потом добавляем следующий.

Добавлено через 3 минуты
Точно не гарантирую, что так будет работать - как уже писал, не знаю Xamarin.
Но ожидаю вот такой работы.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 19:31  [ТС]
Элд Хасп, страница открывается без лагов, но когда начинает отрисовывать элементы -- залагивает, пока не отобразятся. Тем не менее по отладке результат лучше.

XML
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
[0:] 09/10/2021 19:24:15    Start...
[0:] 09/10/2021 19:24:15    var devices = Task.Run(async() => await devicesRepository.GetDevices(id)).Result;
[0:] 09/10/2021 19:24:15    lock (((ICollection)Devices).SyncRoot)
[0:] 09/10/2021 19:24:15    {
[0:] 09/10/2021 19:24:15        if (filterDevices.Count != 0)
[0:] 09/10/2021 19:24:15        {
[0:] 09/10/2021 19:24:15            Task.Run(async () => await Device.InvokeOnMainThreadAsync(() =>
[0:] 09/10/2021 19:24:15            {
[0:] 09/10/2021 19:24:15            }));
[0:] 09/10/2021 19:24:15        }
[0:] 09/10/2021 19:24:15    }
[0:] 09/10/2021 19:24:15                foreach (var newItem in filterDevices.Values)
[0:] 09/10/2021 19:24:15                {
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
 
 
...
 
 
 Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 09/10/2021 19:24:15                }
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
09.10.2021, 20:00
Цитата Сообщение от limeniye Посмотреть сообщение
страница открывается без лагов, но когда начинает отрисовывать элементы -- залагивает, пока не отобразятся.
С этим ничего не поделаешь - не хватает быстродействия устройства.
Надо разбираться уже с оптимизацией создания представления для одного элемента коллекции.

Так как одновременно все элементы Devices в GUI не требуется представлять, то кроме оптимизации представления элемента, желательно ещё использовать виртуализацию.
Но вот как её реализовать на Xamarin я без понятия.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 20:07  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
С этим ничего не поделаешь - не хватает быстродействия устройства.
Касательно быстродействия -- согласен, нужно будет поработать над оптимизацией, безусловно.

Но мне удалось прогружать элементы асинхронно, если я использую следующую запись https://www.cyberforum.ru/csha... st15753916

При ней страница открывается без лагов и отрисовывает первый элемент, потом второй... потом ползунок справа страницы(для скроллинга) начинает уменьшаться, ибо элементов в списке становится больше.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
09.10.2021, 21:01
Цитата Сообщение от limeniye Посмотреть сообщение
Но мне удалось прогружать элементы асинхронно, если я использую следующую запись
Какого типа там Devices ?
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 21:22  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Какого типа там Devices ?
Там было AsyncObservableCollection
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
09.10.2021, 21:45
Цитата Сообщение от limeniye Посмотреть сообщение
Там было AsyncObservableCollection
Но если это моя реализация, то там используется Диспетчер.
А в Xamarin его вроде нет.

Добавлено через 2 минуты
limeniye, может вы эту реализацию используете?
https://gist.github.com/thomaslevesque/10023516
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
09.10.2021, 22:06  [ТС]
Элд Хасп, я начал в этом сомневаться
C#
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
    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
 
        public AsyncObservableCollection()
        {
        }
 
        public AsyncObservableCollection(IEnumerable<T> list)
            : base(list)
        {
        }
 
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the CollectionChanged event on the current thread
                RaiseCollectionChanged(e);
            }
            else
            {
                // Raises the CollectionChanged event on the creator thread
                _synchronizationContext.Send(RaiseCollectionChanged, e);
            }
        }
 
        private void RaiseCollectionChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
        }
 
        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the PropertyChanged event on the current thread
                RaisePropertyChanged(e);
            }
            else
            {
                // Raises the PropertyChanged event on the creator thread
                _synchronizationContext.Send(RaisePropertyChanged, e);
            }
        }
 
        private void RaisePropertyChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnPropertyChanged((PropertyChangedEventArgs)param);
        }
    }
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
10.10.2021, 00:18
Цитата Сообщение от limeniye Посмотреть сообщение
я начал в этом сомневаться
Это не моя реализация.
Моя реализация кривая, делалась для изучения, а не практического применения.
Поэтому я хотел от неё избавиться.

Эта нормальная реализация.
Можно даже сократить её (для WPF точно, а для Xamarin проверьте сами).
Методы OnPropertyChanged и RaisePropertyChanged (два последних в коде) - не нужны.
Их можно удалить.
0
1531 / 534 / 127
Регистрация: 09.01.2018
Сообщений: 1,719
10.10.2021, 00:31
limeniye, у вас этот метод что возвращает devicesRepository.GetDevices?
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
10.10.2021, 01:39  [ТС]
Цитата Сообщение от escoult Посмотреть сообщение
limeniye, у вас этот метод что возвращает devicesRepository.GetDevices?
Во-первых, я не думаю что "devicesRepository" -- это репозиторий, он так называется, но на мой взгляд это просто модель, которая берёт данные из репозитория и через маппер преобразовывает модели во вьюмодели (треш какой-то).
На выходе -- это тот же тип, что и у списка Devices, а Devices -- это DeviceViewModel.

Не по теме:


Вообще, если прям вдаваться в подробности, то он возвращает тип DeviceModel, но по коду это не модель, а ViewModel'ь, так как реализует INotifyPropertyChanged интерфейc.
Все ViewModel'и в проекте именнуются как просто Model'и.
Чтобы все было понятнее и не было путаницы, я на ходу переименовываю типы.




Цитата Сообщение от Элд Хасп Посмотреть сообщение
Эта нормальная реализация.
Можно даже сократить её (для WPF точно, а для Xamarin проверьте сами).
Методы OnPropertyChanged и RaisePropertyChanged (два последних в коде) - не нужны.
Их можно удалить.
Я то удалил, но теперь между ObservableCollection и AsyncObservableCollection всё равно нет никакой разницы.
Использую ObservableCollection.


Я провёл много запусков и заметил очень странное поведение программы.
(для теста убрал картинки, просто отображение прямоугольных элементов с текстом)
Периодически случаются такие моменты, что список открывается за 1 секунду.
Чаще всего такое случается, когда я деплою приложение и открываю список в первый раз.

То есть страница открывается, как обычно, без остановок, гладко, потом фриз на 1 секунду и сразу появляются 256 элементов.
Но в большинстве случаев страница открывается и 7-12 секунд ничего не происходит, а потом отображаются все элементы.

Я теперь в полном замешательстве.
Откуда ноги растут -- не понимаю.

Такое ощущение, что девайс способен обработать и отобразить такое количество информации, но при каких-то особых условиях.


Но самое странное, что мне удалось зафиксировать поведение отладчика, которое меня вообще полностью вводит в ступор.

Отображение элементов через 7 секунд после открытия страницы
XML
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
[Choreographer] Frame time is 0.171389 ms in the future!  Check that graphics HAL is generating vsync timestamps using the correct timebase.
[Choreographer] Frame time is 0.22901 ms in the future!  Check that graphics HAL is generating vsync timestamps using the correct timebase.
[Choreographer] Frame time is 0.166232 ms in the future!  Check that graphics HAL is generating vsync timestamps using the correct timebase.
[.c4mobileclien] Explicit concurrent copying GC freed 18645(1273KB) AllocSpace objects, 3(60KB) LOS objects, 49% free, 4420KB/8840KB, paused 25us total 12.757ms
Thread started: <Thread Pool> #42
[0:] 10/10/2021 00:59:31    Start...
[0:] 10/10/2021 00:59:31    var devices = Task.Run(async() => await devicesRepository.GetDevices(id)).Result;
[0:] 10/10/2021 00:59:32    lock (((ICollection)Devices).SyncRoot)
[0:] 10/10/2021 00:59:32    {
[0:] 10/10/2021 00:59:32        if (filterDevices.Count != 0)
[0:] 10/10/2021 00:59:32        {
[0:] 10/10/2021 00:59:32            Task.Run(async () => await Device.InvokeOnMainThreadAsync(() =>
[0:] 10/10/2021 00:59:32            {
[0:] 10/10/2021 00:59:32            }));
[0:] 10/10/2021 00:59:32        }
[0:] 10/10/2021 00:59:32                foreach (var newItem in filterDevices.Values)
[0:] 10/10/2021 00:59:32    }
[0:] 10/10/2021 00:59:32                {
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
 
    ... середина списка такая же. Вырезал для экономии места.
 
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                }
[.c4mobileclien] Explicit concurrent copying GC freed 1917(573KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4390KB/8780KB, paused 27us total 12.573ms
[Choreographer] Skipped 214 frames!  The application may be doing too much work on its main thread.
А вот так выглядит прогрузка списка за одну секунду, после повторного Deploy'я.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[0:] 10/10/2021 01:09:16    Start...
[0:] 10/10/2021 01:09:16    var devices = Task.Run(async() => await devicesRepository.GetDevices(id)).Result;
[0:] 10/10/2021 01:09:17    lock (((ICollection)Devices).SyncRoot)
[0:] 10/10/2021 01:09:17    {
[0:] 10/10/2021 01:09:17        if (filterDevices.Count != 0)
[0:] 10/10/2021 01:09:17        {
[0:] 10/10/2021 01:09:17            Task.Run(async () => await Device.InvokeOnMainThreadAsync(() =>
[0:] 10/10/2021 01:09:17            {
[0:] 10/10/2021 01:09:17            }));
[0:] 10/10/2021 01:09:17        }
[0:] 10/10/2021 01:09:17    }
[.c4mobileclien] Explicit concurrent copying GC freed 2686(437KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4172KB/8344KB, paused 27us total 14.657ms
[.c4mobileclien] Explicit concurrent copying GC freed 164(36KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4167KB/8334KB, paused 57us total 17.397ms
[Choreographer] Skipped 42 frames!  The application may be doing too much work on its main thread.
Тут даже нет строк по типу
XML
1
2
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));
[0:] 10/10/2021 00:59:32                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));

Также, в качестве элемента "Прямоугольник" я использую Frame (то же самое что и Border в WPF).
И в случае, где элементы появились после 7 секунд пишет
[Choreographer] Skipped 214 frames! The application may be doing too much work on its main thread.
А в случае, где прогрузило за 1 секунду пишет
[Choreographer] Skipped 42 frames! The application may be doing too much work on its main thread.
Что это значит? -- не понятно.

Добавлено через 13 минут
Цитата Сообщение от limeniye Посмотреть сообщение
На выходе -- это тот же тип, что и у списка Devices, а Devices -- это DeviceViewModel.
Task<List<DeviceViewModel>>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
10.10.2021, 01:57
Цитата Сообщение от limeniye Посмотреть сообщение
Я то удалил, но теперь между ObservableCollection и AsyncObservableCollection всё равно нет никакой разницы.
Использую ObservableCollection.
Неа!
Там существенный момент - это маршалинг события CollectionChanged в основной поток.
Но существенно для этого типа, что экземпляр AsyncObservableCollection обязательно! должен создаваться в основном потоке.
Иначе не произойдёт захват контекста синхронизации.
Если VM с этой коллекцией у вас создаётся синхронным кодом в App или Code Behind любого UI элемента (в том числе Окна, UserConrol, Page)? то всё будет Ок.

Вот код который должен быть:
C#
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
    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        // Захват контекста синхронизации при первом обращении к классу
        private static readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
 
        public AsyncObservableCollection()
        { }
 
        public AsyncObservableCollection(IEnumerable<T> list)
            : base(list)
        { }
 
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the CollectionChanged event on the current thread
                base.OnCollectionChanged(e);
            }
            else
            {
                // Вот это и есть единственная строчка, которая важна 
                // Она осуществляет маршалинг CollectionChanged в поток контекста синхронизации
                // Raises the CollectionChanged event on the creator thread
                _synchronizationContext.Send(() => base.OnCollectionChanged(e));
            }
        }
 
    }
И с этой реализацией используйте второй код из 12 поста.

Цитата Сообщение от limeniye Посмотреть сообщение
Что это значит? -- не понятно.
Это надо глубоко с Xamarin разбираться.
Я с ним совершенно не знаком.
Поэтому только "методом тыка".
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
10.10.2021, 02:03  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вот код который должен быть:
там у Send 2 параметра: callback и object state
0
1531 / 534 / 127
Регистрация: 09.01.2018
Сообщений: 1,719
10.10.2021, 02:05
Цитата Сообщение от limeniye Посмотреть сообщение
Task<List<DeviceViewModel>>
Вот. У меня просто сложилось впечатление, что вы ожидаете пока соберется весь список, а потом он разом выводится. Так асинхронный метод ничем тут не поможет, пока данных нет нечего и выводить. Хоть одной задачей это делай, хоть десятком, их все равно придется ждать. Если бы это был IEnumerable<T>, то вы могли бы обрабатывать по одному элементу.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
10.10.2021, 02:29  [ТС]
Элд Хасп, теперь я не понял что мне нужно, а что не нужно. Нужно ли, при такой записи AsyncObservableCollection использовать локировку? Нужно ли использовать следующую запись
Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Clear()));, или же можно ограничиться обычным Devices.Clear();?

В данный момент выглядит так:
C#
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
        private Task UpdateDevicesWithCancellationTokenChecker(CancellationToken token) => Task.Run(() =>
        {
            var id = currentDevice == null ? Root : currentDevice.Id;
            
            var devices = Task.Run(async() => await devicesRepository.GetDevices(id)).Result;
 
            lock (((ICollection)Devices).SyncRoot)
            {
                if (devices.Count <= 0)
                {
                    if (token.IsCancellationRequested)
                        return;
 
                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Clear()));
                    return;
                }
                       
                var filterDevices = devices.Where(d => !d.IsArchived).ToDictionary(d => d.Id);
                if (filterDevices.Count == 0)
                {
                    if (token.IsCancellationRequested)
                        return;
 
                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Clear()));
 
                    return;
                }
 
                //remove old items and change new items
                for (int i = Devices.Count - 1; i >= 0; i--)
                {
                    var index = i;
 
                    if (token.IsCancellationRequested)
                        return;
 
                    var device = Devices[index];
                    if (filterDevices.TryGetValue(device.Id, out var newDevice))
                    {
                        Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices[index] = newDevice));
                        filterDevices.Remove(device.Id);
                    }
                    else
                    {
                        Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.RemoveAt(index)));
                    }
                }
 
                //add new items
                if (filterDevices.Count != 0)
                {
                    Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => 
                    { 
                        foreach (var newItem in filterDevices.Values)
                        {
                            if (token.IsCancellationRequested)
                                return;
 
                            Task.Run(async () => await Device.InvokeOnMainThreadAsync(() => Devices.Add(newItem)));                            
                        }
                    }));
                }
            }
           UpdateContextMenu();
        });

Цитата Сообщение от escoult Посмотреть сообщение
Если бы это был IEnumerable<T>, то вы могли бы обрабатывать по одному элементу.
Вот тут не понял. А в чём разница? Там же не yield . Почему так?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16158 / 11278 / 2891
Регистрация: 21.04.2018
Сообщений: 33,164
Записей в блоге: 2
10.10.2021, 02:39
Цитата Сообщение от limeniye Посмотреть сообщение
Там у Send 2 параметра: callback и object state
Второй разве обязательный?
Если да, то передайте null.

Добавлено через 1 минуту
Цитата Сообщение от escoult Посмотреть сообщение
У меня просто сложилось впечатление, что вы ожидаете пока соберется весь список, а потом он разом выводится
Это запрос делается почти мгновенно.
Проблема возникает при создании представлений для элементов этого списка.

Добавлено через 1 минуту
Цитата Сообщение от limeniye Посмотреть сообщение
Нужно ли, при такой записи AsyncObservableCollection использовать локировку?
Только если есть вероятность одновременного вызова метода UpdateDevicesWithCancellationTokenChecke r несколько раз.
Пока один вызов что-то меняет в коллекции, чтобы другой вызов ему не мешал.

Есть такая вероятность?
1
1531 / 534 / 127
Регистрация: 09.01.2018
Сообщений: 1,719
10.10.2021, 02:41
Цитата Сообщение от limeniye Посмотреть сообщение
Вот тут не понял. А в чём разница? Там же не yield . Почему так?
Нет, yield как раз и должен где-то там быть по идее. В синхронном методе или другой асинхронный возвращает IEnumerable<T>.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.10.2021, 02:41

Данные об отделах ( процент заполения )
Добрый вечер, помогите сделать запрос *Данные об отделах, у которых процент заполнения штата меньше 80* Файл снизу. Заранее спасибо :)

DataGridView1 не соблюдается условие заполения
Это окно редактирования документа в новой форме. Когда нажимаешь на button1, должна заполнится dataGridView1 согласно тому номеру который...

Почему CancellationToken не сбрасывает Token
Пытаюсь сбросить операцию ConnectAsync токеном. Но при выставлении значения 1 сек операцию не сбрасывается. В результате выполнения...

Проверка на правильность заполения полей
Как проверить форму на правильность заполнения полей...Например мне нужно проверить правильно ли у меня заполнено поле Емайл...Как это...

Отправка формы после проверки заполения reCAPTCHA
Можно ли сделать отправку формы после того, как reCAPTCHA примет статус &quot;Галочка&quot;?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
сукцессия 33. открытые вопросы от клауде
anaschu 19.07.2026
"Что накопилось за эту часть А — тринадцать правок, из которых шесть пришли из ваших вопросов и каждая оказалась реальной ошибкой, а не калибровкой: односторонний симбиоз, отсутствующий листопад,. . .
32 сукцессия
anaschu 19.07.2026
сукцессия 28‑мерное ядро стабилизировано Коллеги, фиксирую разбор инженерных правок и их изоморфную проекцию на экономику, меметику и половой отбор. Модель теперь не «подкручивает» сходимость —. . .
сукцессия 31: модель микоризы - это модель ещё нескольких явлений, социальных и экономических
anaschu 18.07.2026
Теория «Всего»: апдейт v1. 1. 2 — 28‑мерное ядро стабилизировано Коллеги, фиксирую разбор инженерных правок и их изоморфную проекцию на экономику, меметику и половой отбор. Модель теперь не. . .
сукцессия 30. Массив проверяющих друг друга моделей
anaschu 18.07.2026
Архитектура сети взаимопроверяющих моделей микоризной сукцессии (v2. 0) Развитие тензорного ОДУ-ядра и создание кросс-платформенного калибровочного полигона Уважаемые коллеги! В продолжение. . .
Грибы - это женщины, деревья - это мужчины. Анти инь янь для союза мужчины и женщины.
anaschu 18.07.2026
ГЛАВНЫЙ НАУЧНО-ФИЛОСОФСКИЙ ВЫВОД: Сексуально-Репродуктивный Капитализм против Государства Моногамии Коллеги, мы вышли на финишную прямую 20-мерного ОДУ-моделирования вековой сукцессии (ветка. . .
Текстовый слайдер с нумерацией страниц и кроссбраузерность.
russiannick 18.07.2026
Один мой друг написал текстовый слайдер с нумерацией страниц. Сегодня я расскажу как он умудрился подружить его с кроссбраузерностью. Очевидно сложно угодить с шириной каждому браузеру. Один крадет. . .
Грибы - это мемы, дерево - это человек. Применение микоризной модели к теории меметики Докинза.
anaschu 18.07.2026
Меметический изоморфизм теории «всего»: Грибная сукцессия как модель эволюции идей Докинза Базовый код системы ОДУ микоризной сукцессии описывает не просто биологию, а универсальную. . .
Грибы - это корпорации, деревья - это государства. Механизм массонского захвата власти
anaschu 18.07.2026
Макроэкономический изоморфизм теории «всего»: Грибная сукцессия как модель транснационального капитализма Базовый код системы ОДУ микоризной сукцессии описывает не просто биологию, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru