Релиз первой беты кросс-платформенного XAML UI-тулкита Avalonia
Состоялся релиз первой бета-версии Авалонии.
Avalonia — кроссплатформенный .NET UI-тулкит, вдохновлённый технологиями WPF, с полной поддержкой .NET Core 2.0, XAML, дата-биндиногов, lookless-контролов и многого другого, поставляемый под лицензией MIT. Avalonia позволяет вам писать на C# приложения под Windows, Linux и Mac OS X, возможность запуска на iOS и Android находится в экспериментальном состоянии.
В настоящий момент проект подошёл к рубежу, когда мы со спокойной совестью можем сказать, что это уже Бета-версия, тулкит не разваливается в руках, имеет приличный базовый набор контролов (см. видео), на нём создано два достаточно больших приложения с открытым исходным кодом: AvalonStudio — кроссплатформенная IDE для разработки на C# и C++ и Core2D — редактор 2D-схем и диаграмм.
Самый простой способ взять и начать пользоваться — установить наше расширение для Visual Studio или же воспользоваться шаблонами для dotnet new. Для ознакомления доступны примеры в основном репозитории.
В процессе подготовки релиза произошёл ряд важных изменений:
- Произведён переход на платформу .NET Standard 2.0
- Старый медленный XAML-парсер заменён на Portable.Xaml, что в частности позволило ускорить запуск AvalonStudio с 25 до 7 секунд (на SSD или на HDD с «горячим» файловым кэшем).
- Были удалены старые и несовместимые с .NET Core бакэнды Cairo и gtk-sharp. Вместо них теперь используется Skia (библиотека отрисовки 2D из состава Google Chrome) и собственные биндинги к GTK3.
- В связи с доступностью ReactiveUI 8 на платформе .NET Standard был произведён переход со своего форка на официальную версию.
- Был запущен сайт avaloniaui.net, на котором в дальнейшем планируется размещать статьи и документацию. Поиск и просмотр xml-документации доступен уже сейчас.
Основные фичи в релизе
Retained-режим отрисовки в отдельном потоке
Ранее мы проводили полную перерисовку окна на каждом изменении. Несмотря на простоту и надёжность данного подхода, он, мягко говоря, неэффективен. Поэтому вместо него был реализован DeferredRenderer
. Принцип работы оного состоит в преобразовании вызовов нашего API отрисовки в граф сцены окна, который затем в отдельном потоке анализируется на предмет отличий от предыдущего кадра, а затем изменившиеся части перерисовываются. Помимо снятия нагрузки с UI-потока это позволяет добавлять оптимизации посредством выделения частей окна в слои, которые кэшируются в битмапах.
Новая инфраструктура рендеринга ощутимо улучшила производительность, особенно в случаях с анимациями. Так же это дало нам возможность реализовать нормально работающий hit-testing.
Если у вас возникают проблемы при использовании новой инфраструктуры, сохранена возможность использования старой, ImmediateRenderer
будет доступен и в дальнейшем.
MonoMac-бакэнд для OS X
Ввиду того, что GTK2/GTK3 — достаточно тяжеловесные наборы библиотек (~60MB), которые для нас, по сути, не представляли собой ничего кроме прослойки над нативным Carbon API, был реализован Cocoa-бакэнд средствами специально собранного под .NET Standard MonoMac. Помимо упрощения сборки бандлов (в случае с GTK эти 60 мегабайт надо ещё суметь нормально упаковать, процесс сей неочевиден и плохо документирован) это дало возможность использования родных для OS X файловых диалогов вместо «универсальных» предоставляемых GTK
Синтаксический сахар для RelativeSource
Ранее, как и в WPF привязки к другим контролам осуществлялись через RelativeSource, который крайне многословен, например, привязка текста на свойство Tag
родительского элемента выглядит примерно так:
Новый синтаксис позволяет то же самое записать так:
Помимо $parent добавлены следующие возможности
Сокращение | Аналог |
---|---|
$self |
Mode = Self |
$parent |
Mode = FindAncestor; AncestorLevel = 1 |
$parent[Level] |
Mode = FindAncestor; AncestorLevel = Level +1 |
$parent[ns:Type] |
Mode = FindAncestor; AncestorType = ns:Type |
$parent[ns:Type; Level] |
Mode = FindAncestor; AncestorType = ns:Type; AncestorLevel = Level + 1 |
*ns:Type
— неймспейс: Тип, например Border
или local:MyControl
Drawing
Drawing
— удобное представление для векторной графики типа иконок, используемое в WPF. Библиотека изображений Visual Studio предоставляет сотни иконок в данном формате. Так же их использование улучшает производительность, поскольку все части изображения являются одним элементом visual tree
В 1117 была добавлена поддержка данного формата. Несмотря на то, что наш стандартный контрол Image
пока не умеет с ними работать, вы уже можете использовать для этого DrawingPresenter
.
StaticResource
и DynamicResource
В #1130 добавлены привычные по WPF/UWP Control.Resources
, StaticResource
и DynamicResource
.
Реализация данной возможности соответствует аналогичной функциональности в WPF/UWP настолько точно, насколько это возможно. Раннее все ресурсы были привязаны к стилям и для доступа к ним предлагалось использовать {StyleResource}
. Теперь у каждого элемента управления есть свой словарь ресурсов, которые наследуются по дереву элментов. Расширение разметки {StyleResource}
было удалено, теперь вместо него следует использовать {DynamicResource}
.
Привязка команд к методам
Думаю, у всех есть в проекте реализация ICommand, принимающая в конструкторе делегат. Чтобы не плодить лишние сущности, привязка напрямую к методам вью-модели добавлена в сам фреймворк.
public class ViewModel
{
public void ButtonClicked()
{
Console.WriteLine("Hooray!");
}
}
Календарик
Утащен в #1244 из Silverlight. Теперь можно брать и выбирать даты.
Интеграция с WPF
Поскольку системы layout-а в авалонии и WPF практически идентичны, а посредством чёрной магии можно рендерить средствами Direct2D прямо в заточенный под Direct3D 9 D3DBitmap
, была реализована полностью бесшовная интеграция для встройки контролов на авалонии в WPF-приложения. Демку можно посмотреть тут.
Что характерно, за счёт использования Direct2D при такой встройке на сложных сценах разница в производительности может достигать двух порядков в пользу Авалонии. Так что если у вас есть какой-то тормозящий контрол под WPF, может иметь смысл попробовать его портировать и встроить обратно.
Новая инфраструктура для превьювера с поддержкой .NET Core
Предыдущая версия превьювера для студии была, по сути, написана за три дня со срезанием всех возможных и невозможных углов. В результате вышла она крайне непортабельной, с привязкой к Win32 API, полному дотнету и Windows Forms. Вместо неё была придумана более умная, с общением по tcp/ip и возможностью передачи битмапов вместо прямой встройки окна в Visual Studio. Это позволило наконец-то нормально предпросматривать XAML в проектах под .NET Core и, что более важно, открыло дорогу для поддержки в других IDE, в частности, поддержка уже добавлена в AvalonStudio (видео). Ведутся работы над плагином к Visual Studio Code, но это осложнено тем, что данная IDE построена с применением передовых и прогрессивных веб-технологий, что создаёт необходимость отдельного language-server-а, своей обвязки вокруг msbuild и передачи картинок через WebSocket.
Помимо превьювера инфраструктура «удалённых» виджетов может пригодиться ещё где-нибудь, поэтому доступны для использования классы RemoteServer
и RemoteWidget
.
Иные улучшения
Полный список можно посмотреть тут, а ниже представлены интересности:
#894
Кнопки выключаются, если привязка свойства Command вернула null#1085
ДобавленFindAncestor
#1086
ReactiveUI обновлён до восьмой версии#1128
У кнопки появилось свойствоIsPressed
#1133
Для тултипа реализованыIsOpen
,Placement
,Offset
#1145
Переехали на .NET Standard 2.0#1146
Для окна реализовано свойствоShowTaskbarIcon
#1150
Реализовано API доступа к информации об экранах#1174
СожглиУбрали поддержку GTK2 and Cairo support#1175
РеализованныOrientation
иIsIndeterminate
у прогрессбара#1253
Для PageSlide-анимации реализована вертикальная ориентация#1265
Реализована поддержка трёх состояний дляToggleButton
,CheckBox
иRadioButton
(серенькое ни-да-ни-нет)#1273
Облегчили настройку логирования при настройке AppBuilder
Изменения, ломающие совместимость
Хорошая новость: мы их теперь отслеживаем и иногда даже документируем
Плохая новость: они есть
BuildAvaloniaApp
для превьювера.
Ввиду перехода с набора хаков на нормальную систему превьювер теперь ожидает получить необходимую ему информацию у самого приложения. В связи с этим необходимо реализовать соответствующий методв классе с точкой входа (обычно Program.cs
прямо рядом с Main
). Выглядит это примерно так:
static void Main(string[] args)
{
BuildAvaloniaApp().Start();
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
.LogToDebug();
Если этого не сделать, то превьювер работать не будет. Такие дела.
DataContextChanging
и DataContextChanged
Заменены на OnDataContextBeginUpdate
and OnDataContextEndUpdate
Расширения разметки Static
и Type
Заменены на x:Static
and x:Type
, нужно добавить xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
в корневой элемент XAML-файла. Ибо стандартизация.
StyleResource
StyleResource
заменен на StaticResource
и DynamicResource
, как во всех нормальных XAML-фреймворках. StaticResource
and DynamicResource
ищут в Control.Resources
и Style.Resources
.
Mouse device
Убрали одну из глобальных переменных — MouseDevice
. Теперь мышь доступна из топлевела, вызывайте GetVisualRoot
и кастуйте к IInputRoot
. А разгадка проста — глобальные переменные и service locator — зло.
var pos = (_control.GetVisualRoot() as IInputRoot)?.MouseDevice?.Position ?? default(Point);
Как начать пользоваться?
Скачать дополнение к студии и создать проект из шаблона. Ввиду отсутствия нормальной документации будет необходим опыт работы с WPF/UWP.