Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > WPF и Silverlight > Почему Canvas так долго думает


Автор: ivanfain 19.3.2012, 16:53
Я вот думал, WPF несказанно крут, DirectX и всякой такое. Но реально я хочу разместить несколько тысяч ячеек и это занимает несколько секунд. Ячейка - это просто UserControl, на Canvas. UserControl не сложный, текстовое поле TextBlock и Border. Результат должен быть на подобии листа Excel. Но вот всё это не реально долго. Как оптимизировать? Реально ли сделать отрисовку нескольких тысяч ячеек меньш секунды. Excel ведь это умеет, да и не на WPF он написан.
Спасибо.

Автор: Stas123 19.3.2012, 19:37
Подумайте, может стоит использовать паттерн "Приспособленец"(Flyweight).

Автор: ivanfain 19.3.2012, 19:47
А как его использовать? Каждая ячейка имеет уникальные координаты, поэтому трудно обойтись одним объектом.

Автор: exBlender 19.3.2012, 22:01
Цитата(ivanfain @ 19.3.2012,  12:47)
А как его использовать? Каждая ячейка имеет уникальные координаты, поэтому трудно обойтись одним объектом.

А для чего каждой ячейке иметь уникальные координаты и быть посаженной на Canvas, eсли все это должно быть похожим на таблицу? Почему не использовать DataGrid или, хотя бы, просто Grid?

Автор: ivanfain 19.3.2012, 23:01
Цитата(exBlender @  19.3.2012,  22:01 Найти цитируемый пост)
 Почему не использовать DataGrid или, хотя бы, просто Grid? 

Потому что это будет не стандартная таблице. Не знаю как насчёт DataGrid но через обычный Grid это сделать можно. Вы утверждаете что скорость отрисовки будет больше?

Автор: SergeyLoginov 20.3.2012, 16:52
WPF очень медленно отрисовывает большое количество визуальных элементов. Но в Вашем случае можно использовать виртуализацию данных. В частности, существует виртуализированный http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx, в котором рендерятся только видимые на экране элементы. В DataGrid, кстати, тоже реализована виртуализация. 

Автор: erm0l0v 21.3.2012, 08:51
Используйте DataGrid. Canvas не для этого предназначен.

И как вам вообще пришла в голову мысль использовать Canvas? Элементы ведь можно по координатам размещать и в Grid.

В общем попробуйте реализовать задачу с использованием DataGrid. Это будет самый оптимальный способ. В крайнем случае через Grid.

Автор: ivanfain 21.3.2012, 23:47
Цитата(SergeyLoginov @  20.3.2012,  16:52 Найти цитируемый пост)
 В частности, существует виртуализированный Canvas, в котором рендерятся только видимые на экране элементы.

Спасибо, но это контрол я знаю
Цитата(erm0l0v @  21.3.2012,  08:51 Найти цитируемый пост)
Используйте DataGrid. Canvas не для этого предназначен.

DataGrid не подойдёт. Мне нужны головы таблицы со всех сторон. Переделал на Grid, так как Canvas потом использовать не удобно. Но при переходе на Grid производительность ещё снизилась. Что же делать?

Автор: erm0l0v 22.3.2012, 09:05
Цитата(ivanfain @ 21.3.2012,  23:47)
Мне нужны головы таблицы со всех сторон.

Я такого не делал но уверен почти на 100 процентов что это возможно сделать по средствам стилей. В WPF стилями можно изменить вообще все.

По поводу что делать поставьте профайлер памяти и вы сможете увидеть какие классы занимают больше всего места. На первый взгляд копать нужно в сторону большого количества UserControl.

Кроме того возможно неправильно настроен ScrollViewer. Возможно в приложении ошибка которую вы не ведите из-за пустого catch.

И все таки ради теста попробуйте отобразить данные в DataGrid если будет работать так же долго то проблема не в визуальном отображении. У меня таблица из 100к строк и примерно 15 столбцов строится очень быстро, меньше секунды и учетом того что данные еще тянутся из базы и некоторые поля таблицы вычисляются.

Автор: ivanfain 22.3.2012, 09:48
Цитата(erm0l0v @  22.3.2012,  09:05 Найти цитируемый пост)
По поводу что делать поставьте профайлер памяти и вы сможете увидеть какие классы занимают больше всего места.

Дело не в памяти, а в процессорном времени
Цитата(erm0l0v @  22.3.2012,  09:05 Найти цитируемый пост)
На первый взгляд копать нужно в сторону большого количества UserControl.

Там и теряется перформанс. 

Цитата(erm0l0v @  22.3.2012,  09:05 Найти цитируемый пост)
Я такого не делал но уверен почти на 100 процентов что это возможно сделать по средствам стилей.

Если вы покажете как переопределить стиль DataGrid чтобы он выглядел так, как это показано на изображении. С возможность в добавлять и убирать головы(как сверху так и слева), а следоватьльно и менять количество ячеек, буду вам очень признателен. Если же это просто разговоры - тогда плохо.
http://xmages.net/i/3430841

Автор: erm0l0v 23.3.2012, 09:34
Теперь понятно почему вы решили использовать Canvas))
Только может быть Canvas работал бы быстрее если вы не добавляли контролы а рисовали таблицу примитивами, но это конечно жестоко.

По поводу DataGrid для отображения заголовков в левой части можно использовать группировки, но правда меня разочаровала скорость работы группировки в DataGrid в WPF особенно по сравнению с Silverlight.

По поводу группировки заголовков сверху и объединенных ячеек справа я пока ничего не могу придумать((( если что нибудь придет на ум отпишусь...

Вроде есть компоненты для отображения таблиц Excel в WPF (я нашел только платные) и есть компоненты в Windows Forms вы принципе можете использовать компоненты из WF в WPF но опять же скорость работы WinFormsHost меня разочаровала.

Автор: ivanfain 23.3.2012, 13:49
Цитата(erm0l0v @  23.3.2012,  09:34 Найти цитируемый пост)
Теперь понятно почему вы решили использовать Canvas))

Теперь перешёл на Grid, потому как Canvas не адекватно отрисовывается. Для него почему-то не работает нормально SxrolViwer. Портировать на Grid было делом 15 минут.
Меня смущает то, что я добавляю элементы в коллекцию в цикле
Код

forech(var l in list)
{
     myPanel.Children.Add(new UserControl1(){Any="Any"});
}

Может как-то нужно остановить отрисовку прежде чем начать добавлять? Но боюсь WPF это и так делает. Скорее всего он останавливает отрисовку пока не будут добавлены все элементы.

Автор: erm0l0v 23.3.2012, 16:06
Сейчас для теста вывел таблицу 10000 на 5 ждал 10 секунд.

По идеи

Код

 myPanel.Visibility = System.Windows.Visibility.Collapsed; 


должна остановить отрисовку, но в моем примере это не помогло (или помогло но незначительно).

Автор: exBlender 23.3.2012, 22:20
А зачем там вообще UserControl-ы? С такой графикой можно просто назначать Background для TextBlock-ов.

Автор: ivanfain 26.3.2012, 20:40
Там логика в UserControl-ах содержится. Её конечно можно вынести отдельно, но будет ли профит? Хотя бы 10% производительности получу? Сомневаюсь.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)