« first day (973 days earlier)      last day (2058 days later) » 

2:56 PM
@VladD Извини, что вчера резко ушел. Блок питания каратнул в меня. Сгорел нахрен. Придется новый тянуть, сейчас на подпидке с чужого блока.
@VladD Ну а в какой момент генерировать это событие?
 
A K
3:09 PM
@Bretbas коротнул. проверочное слово - короткое замыкание
 
@AK Это два слова)
 
A K
@Bretbas точно, это dword )
 
 
4 hours later…
7:37 PM
@АндрейNOP Угу, но они генерируются как дочерний элемент какого-то другого элемента, верно?
@Bretbas Ого! Дай бог чтобы ничего не сгорело
@Bretbas Ну, хм. В тот момент, когда становится известно, что CanExecute станет другим.
Там в принципе есть и другие пути, если не получается сгенерировать
Например, InvalidateRequerySuggested
 
@VladD авот такая задача. допустим я пишу чат где может быть много пользователей разбитых на каналы. по таймеру происходит heartbeat и можно послать сообещние в канал, а то и вообще всем. Также коннекты добавляются и удаляются
и вопрос в том какие структуры использовать
я использовал
ConcurrentDictionary<"канал", ConcurrentDictionary<id:long, Client>>
но итерация ведь в нем блокирующая, а доставать с каждого "канала" dic.Values не хочется ибо LOH
 
@vitidev Мне не нравится Concurrent-контейнеры тем, что в них отсутствует семантика. Ну да ладно.
А почему бы получить список ключей, материализовать его, и обходить?
Раз у вас всё равно Concurrent-контейнер, и семантика «snapshot на точно определённый момент» отсутствует.
 
ну я так и сделал. но так я теряю время на доставание каждого элемента вместо простого перебора
снапшот в этой задаче и не нужен - если клиент отвалился то отвалился ничего страшного
 
@vitidev Ну да. А иначе вы заблокируте его на всё время
То есть непонятно, что вас не устраивает
 
7:53 PM
var tasks = new List<Task>(_clientCount);
foreach (var channel in _channels.Keys)
{
if (_channels.TryGetValue(channel, out var clientMap))
foreach (var clientId in clientMap.Keys)
if (clientMap.TryGetValue(clientId, out var client))
if (client.IsConnected)
tasks.Add(func(client));
}

await Task.WhenAll(tasks).ConfigureAwait(false);
да блин. где отступы
@VladD ну так задача из разряда где оптимизация важна.
вторая проблема. как избавиться от
await Task.WhenAll(tasks).ConfigureAwait(false);
потому что это требует рождения
var tasks = new List<Task>(over9999);
 
@vitidev А как можно читать один элемент без блокировки? Не пойму.
То есть какой семантики вы хотите?
WhenAll принимает IEnumerable? А если нет, пишется в две строчки циклом
foreach (var t in nonMaterialTasks) await t.ConfigureAwait(false);
@vitidev У вас не должно быть строк, не начинающихся с 4 пробелов. Включая пустые.
 
при отправке сообщение в канал по факту идет простой перебор клиентов и отправка данных. Если не бегать по ключу то можно например навскидку LinkedList вроде тоже подходит. Перебор и так понятен, а если клиент умер то помечается он и при повторном переборе (heartbeat же) при проходе по связанному списку можно удалить такие просто перешивая связи
может еще какие варианты есть
не понял про таски
впервые в жизни встречаю задачу где связанный список может пригодиться )))
 
@vitidev А почему проблема бегать по ключу? Опишите, что именно вы хотите.
 
8:12 PM
я хочу периодически полностью пробегать всех пользователей и слать им данные. Проблемы которые вижу я
1 на каждом канале нужно получать массив Keys (а это лок)
2 далее нужно делать поиск по ключу (что дает какую то потерю времени)
(не делаю dic.Values (меморитрафик и LOH))
3 что будет со словарем если его заполнить на миллион а потом 99% вычистить по ключу. отдаст ли он память (серверный GC сам по себе ахтунг, а если еще и словарь память не будет отдавать....)
4 собственно var tasks = new List<Task>(over9999); что грозит LOH
да и массив long-ов Keys всего ничего нужно и снова привет LOH
напомню текущую структуру

ConcurrentDictionary<"канал", ConcurrentDictionary<id:long, Client>>
 
9:15 PM
@VladD это хороший вопрос. А где их надо считать? Вот если у меня какое-то дерево вопросов/ответов (как в исходном вопросе), то мне эти координаты не интересны по идее и в бизнес-логике их быть не должно. Значит над классами-блоками должна быть обертка с координатами в GUI, т.е. эта обёртка должна быть во View? Или все же в VM?
@VladD, вот как бы вы реализовали это:
 
@АндрейNOP я не очень понимаю вашу проблему. По идее это должен быть контрол который внутри себя имеет метод типа Measure/Rearrange который и разместит вложенные блоки где надо по вьюмодели. Вложенный блок это тоже контрол, который знает свою позицию относительно родителя. На вьюмодели всего лишь биндинг. Ну а зная координаты всех элементов этот базовый контролможет начертить что надо по базовым вершинам. или может спросить у вложенных элементов где их точки сцепления. вьюмодель координаты не зна
 
@АндрейNOP По идее, какой-нибудь HierarchicalDataTemplate?
Это ж дерево
 
В бизнес-логике пара классов: Вопрос, содержащий текст и коллекцию ответов; Ответ, содержащий текст и ссылку на вопрос
@VladD а получится? Проблема в том, что ссылки на вложенные вопросы хранятся не в вопросе, а в промежуточном классе - ответе
Я пробовал, но так и не понял как сделать
Т.е. у меня в блоке-вопросе есть заголовок и ItemsControl со списком ответов и вот вложенные вопросы цепляются как раз к этим ответам
 
глянул я Task.WhenAll. он внутри себя все равно делает массив тасков. И для того чтобы не бегать по массиву постоянно он использует легковесную подписку Task.AddCompletionAction которую таска сама дернет по завершению и этот метод internal. а-а-а-а
 
9:33 PM
@VladD т.е. в качестве ItemsSource передавать ему список ответов надо будет, а выводить уже к каждому ответу связанный вопрос? Как тогда быть с самым первым уровнем, начинается-то все с вопросов, а не ответов
 
@АндрейNOP но ведь задача VM и состоит в том чтобы подготовить данные для отбражения. Если что то хранится в неподходящем месте, то в VM должна быть реструктурированная структура где все в нужно месте, то есть свое "логическое" дерево. И она должна знать как правильно применить изменения к себе
 
@vitidev ага, т.е все что связано с координатами рассчитывать во View?
@vitidev предлагаете превратить дерево в плоский список вопросов?
Тогда надо будет просто отдельно хранить глубину каждого вопроса
 
@АндрейNOP неподходящая струкутура превращается в "визуальную". далее эту "визуальную" просто рисуем. Неважно как у вас расположены оригинальные данные, если вы можете сделать из него альтернативное дерево где все как надо.
а далее только проблема отрисовки.
 
@АндрейNOP Ну, у вас есть Item и его потомки
 
то есть не стоит пытаться научить вид как ему рисовать что у вас есть за структура. Нужно дать ему нужную. ведь именно этим VM и занимается.
У вас дети ссылаются на родителей? - сделайте в VM дерево где дети (ответы) вложены в вопросы (или как оно там надо) и дальше кормите виду
хотя в вашем случае без канваса не обойтись
 
9:43 PM
можно наверняка пропихнуть туда что угодно
@vitidev А горизонтальной stackpanel не хватит?
расчёт координат вручную — утомительная работа
 
@vitidev я тоже так хотел сделать, если с блоками все просто, то не понятно как потом быть с соединяющими линиями. Хотя. Можно так же иметь отдельный плоский список ответов и с помощью него рисовать линии...
 
@VladD блоки размещать да, но линии как рисовать
 
@vitidev Ну если передать в дочерний ItemsSource элемент привязки, то рисовать линии просто
там у меня был пример сверху
@АндрейNOP Поскольку внутренний темплейт лежит как visual child внешнего, можно передать ссылку на начало линии хоть через ресурсы
 
@VladD чет не решается задача легковесного Task.WhenAll. AddCompletionAction (который и нужен для этого) недоступен.А значит если у нас миллион задач то...до старта задачи counter++, а в задаче сделать ContinueWith(counter--) то есть плюс миллион задач продолжений (
 
В общем так. Иерархическая структура пусть остаётся где-то в модели. Из нее я делаю в VM 2 плоских коллекции: вопросы (со вложенными ответами) и ответы (со ссылкой на вопрос-родитель и на связанный вопрос). Потом по списку вопросов я рисую блоки, а по списку ответов линии (координаты линий определяю по списку вопросов с помощью ItemContainerGenerator.ContainerFromItem())
 
9:54 PM
@АндрейNOP не понимаю почему бы просто не сделать полное дерево как оно дожно быть в итоге
 
@VladD там у автора ещё блоки перетаскиваемые, но это уже другой вопрос
@vitidev где его сделать?
Вы же сами пишете:
 
@АндрейNOP в VM. это его задача - подхотовить удобоваринмую структуру для вида. в данном случае логическое дерево вопросов ответов
 
12 mins ago, by vitidev
то есть не стоит пытаться научить вид как ему рисовать что у вас есть за структура. Нужно дать ему нужную. ведь именно этим VM и занимается.
У вас дети ссылаются на родителей? - сделайте в VM дерево где дети (ответы) вложены в вопросы (или как оно там надо) и дальше кормите виду
хотя в вашем случае без канваса не обойтись
@vitidev ну так как раз удобнее 2 плоских коллекции, думаю
Ладно, всем спасибо за обсуждение, пора спать. Завтра или послезавтра попробую ещё раз реализовать все это.
 
посмотрите на свой рисунок. видите там основные элементы? вложенные элементы? вот для этих элементов и делаете классы и сооружаете из данных такое же
далее просто отдаете контролу умеющему рисовать иерархии. TreeView скушает и так, но для вашей задачи придется замудрить свой контрол где просто по другому будут элементы.
конечно вы можете сделать контрол умеющий скушать 2 списка. то есть узкозаточенный, но лучше все таки работать с чистым деревом в иерархии ведь потом можно менять изначальные структуры и поправить VM куда проще будет
потому что этот узкозаточенный контрол будет делать ту же работу по сути - из 2х списков сооружать точно такое же дерево, какое сооружал бы слой вьюмодели. Так лучше уж пусть это делает вьюмодель, а вид займется только координатами
 
@vitidev ну так пробовал же. Выше же описывал, что с HierarchicalDataTemplate не понятно как действовать, ибо в в вопросе коллекция не вопросов, а ответов, а ссылки на вопросы уже лежат в ответах
 
10:01 PM
@АндрейNOP повторюсь. если ваша структура не подходит для HierarchicalDataTemplate , то сделайте специальную структуру дерево для HierarchicalDataTemplate
пример
из базы достаем данные 3х таблиц - это плоские списки
потом в цикле соединяем их и получаем дерево
в ЛЮБОМ случае кто то будет преобразовывать "неправильную" структуру (например 2 списка) в "правильную" (как у вас на скрине). Этого не избежать. чтобы получить то что на скрине - придется данные сделать в такую иерархию
и делать это должна VM (хотя может кто угодно - и вид, и вм и хелперы какие нибудь и конвертеры)..ну или конвертер, но лучше VM если она изменяемая
также можно сделать LIve-структуру. которая внешне удобное дерево, а внутри себя уже хранит как ей хочется
внешне удобное == внешне правильное
 
10:39 PM
@VladD http://paste.org.ru/?srd5yd
структура ConcurrentDictionary<string, LinkedList<ServerSentClient>> _channels
но меня смущает культяпка
а магию foreach (var t in nonMaterialTasks) await t.ConfigureAwait(false);
я чет не понял как ее и куда
 
11:29 PM
может нужно делать private volatile bool _taskAddingFinished;
ну не локи точно
 

« first day (973 days earlier)      last day (2058 days later) »