[Программирование, .NET, Разработка под MacOS, Разработка под Windows] От WPF к Авалонии
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
WPF — любимый сообществом фреймворк для десктопной разработки, однако в то время как дотнет и вся его экосистема уже давно кроссплатформенные, WPF работает только под Windows. Сообщество решило эту проблему и теперь у нас есть Авалония — фреймворк, во многом очень похожий на WPF, но работающий на разных платформах. Под катом мы разберем отличия Авалонии от WPF. Что нужно знать людям, переходящим с WPF на Авалонию? В чем преимущества нового фреймворка, а в чем его недостатки по сравнению с WPF?
СтилиНа первый взгляд, стили в Авалонии выглядят точно также, как и в WPF — они задаются в блоке Styles с помощью селекторов и сеттеров. Первые выбирают набор блоков, к которым применяются стили, вторые — задают непосредственно стили. Давайте сравним два одинаковых стиля в WPF и Авалонии:
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontSize" Value="24"/>
</Style>
<Style Selector="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontSize" Value="24"/>
</Style>
Как видите, в данном фрагменте различается только объявление тега Style — в WPF для выбора целевого блока используется параметр TargetType, а в Авалонии - Selector. Однако селекторы в Авалонии куда мощнее, чем TargetType в WPF. Больше всего они напоминают селекторы из CSS — с классами, псевдоклассами и кастомными обращениями. Например, вот так мы можем задать размер шрифта для всех текстовых блоков с классом h1
<Styles>
<Style Selector="TextBlock.h1">
<Setter Property="FontSize" Value="24"/>
</Style>
</Styles>
<TextBlock Classes="h1">Header</TextBlock>
Псевдоклассы позволяют нам выбирать элементы в определенном состоянии — когда они в фокусе, когда на них наведена мышь, когда чекбокс выбран и так далее. В WPF подобное реализовывалось через триггеры (стиль изменялся, когда активировалось некоторое событие), однако подход через псевдоклассы выглядит более удобным и современным.
<Styles>
<Style Selector="Button:pointerover">
<Setter Property="Button.Foreground" Value="Red"/>
</Style>
</Styles>
<Button>I will have red text when hovered.</Button>
И, конечно же, селекторы в Авалонии позволяют гибко выбирать целевые контролы для стилей — через цепочки дочерних элементов, по совпадению нескольких классов, по шаблонам и по значениям определенных свойств. Опять же, это очень похоже на селекторы в CSS. Например, вот так мы можем выбрать кнопку, являющуюся прямым наследником элемента с классом block, имеющую значение свойства IsDefault = true:
.block > Button[IsDefault=true]
Полный список доступных селекторов и их описания вы можете найти в документации Авалонии.Обновленный синтаксис XAMLКак и в случае со стилями, синтаксис XAML не слишком сильно отличается от WPF. Объявление контролов, параметры, биндинги — все выглядит по-прежнему. Однако некоторые отличия все же есть — синтаксис стал более емким и понятным, а где-то добавились новые возможности. Посмотрим на изменения по порядку.Начнем с упрощений в синтаксисе. Самый простой пример такого упрощения — это объявление строк и столбцов в Grid. Классическое, привычное с WPF объявление будет выглядеть следующим образом:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="32"></RowDefinition>
</Grid.RowDefinitions>
</Grid>
Этот код будет отлично работать и в Авалонии, однако, помимо полного варианта объявления, добавился и сокращенный.
<Grid RowDefinitions="*,Auto,32,"/>
Упростилось и подключение зависимостей в XAML файлах. Теперь clr-namespace можно заменить на using. Такое изменение позволяет сделать подключение сторонних библиотек короче и читаемее.Было: xmlns:styles="clr-namespace:Material.Styles;assembly=Material.Styles"Стало: xmlns:styles="using=Material.Styles"Другое любопытное изменение — это вынесение DataTemplates и Styles в отдельные теги. Раньше они размещались внутри Resources.
<UserControl xmlns:viewmodels="clr-namespace:MyApp.ViewModels;assembly=MyApp">
<UserControl.DataTemplates>
<DataTemplate DataType="viewmodels:FooViewModel">
<Border Background="Red" CornerRadius="8">
<TextBox Text="{Binding Name}"/>
</Border>
</DataTemplate>
</UserControl.DataTemplates>
<UserControl.Styles>
<Style Selector="ContentControl.Red">
<Setter Property="Background" Value="Red"/>
</Style>
</UserControl.Styles>
<UserControl>
Важные изменения произошли и в биндингах. Авалония позволяет связывать между собой элементы разметки, прибегая только к свойствам XAML. Достаточно обратиться к источнику зависимости, используя # и имя элемента. Например, вот такой код привяжет значение поля other к значению поля source.
<TextBox Name="source"/>
<!-- Binds to the Text property of the "source" control -->
<TextBlock Name=”other” Text="{Binding #source.Text}"/>
Конструкция $parent позволяет обращаться к родительским компонентам.
<Border Tag="Hello World!">
<TextBlock Text="{Binding $parent.Tag}"/>
</Border>
Кстати, такое обращение поддерживает индексирование. Иначе говоря, конструкция $parent[1] позволит вам обратиться к родителю родителя вашего компонента. А конструкция $parent[0] эквивалентна $parent. Помимо индексов здесь также можно использовать обращение по типу. $parent[Border] позволит вам обратиться к первому предку с типом Border. А еще такое обращение можно совместить с индексированием.
<Border Tag="Hello World!">
<Border>
<Decorator>
<TextBlock Text="{Binding $parent[Border;1].Tag}"/>
</Decorator>
</Border>
</Border>
В WPF аналогичную функцию выполняет свойство RelativeSource, однако RelativeSource завязано на визуальном дереве элементов, а не на логическом. Подробнее почитать о разнице вы можете в этой статье.Небольшие изменения также коснулись конвертеров. Один из самых популярных конвертеров, логическое отрицание, был реализован в виде синтаксиса в XAML коде.
<StackPanel>
<TextBox Name="input" IsEnabled="{Binding AllowInput}"/>
<TextBlock IsVisible="{Binding !AllowInput}">Sorry, no can do!</TextBlock>
</StackPanel>
Кстати, этот конвертер использует метод Convert.ToBoolean для преобразования значений, что позволяет писать код такого вида:
<Panel>
<ListBox Items="{Binding Items}"/>
<TextBlock IsVisible="{Binding !Items.Count}">No results found</TextBlock>
</Panel>
А еще конвертер поддерживает множественное использование, что позволяет преобразовывать не-булевские значения в boolean с помощью двойного отрицания.
<Panel>
<ListBox Items="{Binding Items}" IsVisible="{Binding !!Items.Count}"/>
</Panel>
Я бы не рекомендовал использовать такой трюк, однако множественное применение конвертеров может пригодиться, когда в Авалонии реализуют синтаксическую поддержку для других конвертеров. Теоретически вы можете сделать это сами, но на практике это достаточно сложно и никак не документировано.Помимо синтаксической поддержки, Авалония дает пользователю несколько дефолтных конвертеров. Для них не реализован никакой специфический XAML синтаксис, так что они используются как обычные конвертеры.
<TextBlock Text="{Binding MyText}" IsVisible="{Binding MyText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
И последняя возможность, которую хочется упомянуть, относится к проблемам кроссплатформенности. Видели вот это меню в macOS?
Подобные элементы — это вечная головная боль кроссплатформенных приложений. На маках такое меню есть, а на винде — нет. А в Linux есть, но не везде, только в некоторых оконных менеджерах. Для работы с такими меню в девятой версии Авалонии реализовали компонент NativeMenu. По умолчанию, даже без добавления NativeMenu в приложение, Авалония будет генерировать меню с базовыми пунктами — как раз они и представлены на скриншоте. А для добавления новых пунктов как раз и используется NativeMenu.
<Application>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="About MyApp" Command="{Binding AboutCommand}" />
</NativeMenu>
</NativeMenu.Menu>
</Application>
Декларативный UI via F#Несмотря на все улучшения и упрощения для XAML, многим он кажется громоздким и избыточным, поэтому все большую популярность набирают разнообразные декларативные DSL. Сообщество Авалонии разработало отличную библиотеку Avalonia.FuncUI, позволяющую вам писать UI на Авалонии в декларативном стиле. Получающийся код напоминает реализацию UI с помощью Elm или Jetpack Compose.
module Counter =
type CounterState = {
count : int
}
let init = {
count = 0
}
type Msg =
| Increment
| Decrement
let update (msg: Msg) (state: CounterState) : CounterState =
match msg with
| Increment -> { state with count = state.count + 1 }
| Decrement -> { state with count = state.count - 1 }
let view (state: CounterState) (dispatch): IView =
DockPanel.create [
DockPanel.children [
Button.create [
Button.onClick (fun _ -> dispatch Increment)
Button.content "click to increment"
]
Button.create [
Button.onClick (fun _ -> dispatch Decrement)
Button.content "click to decrement"
]
TextBlock.create [
TextBlock.dock Dock.Top
TextBlock.text (sprintf "the count is %i" state.count)
]
]
]
Такая стилистика пока не стала чем-то общепринятым — кому-то привычнее XAML, а кто-то считает FuncUI громоздким по сравнению с конкурентами. В любом случае, это интересная опция, которая для многих может быть более удобной и понятной. НедостаткиПерейдем к самому интересному — а что же не так с Авалонией в сравнении с WPF?Если смотреть на функциональность, то Авалония не только приобрела новые фичи, но и потеряла некоторые возможности WPF. Например, в Авалонии из коробки отсутствуют триггеры (обсуждение этой фичи можно найти в репозитории Авалонии, а пока триггеры можно использовать с помощью пакета AvaloniaBehaviors), не работают биндинги через стили и так далее. Другая проблема — это экосистема. Так как Авалония куда моложе WPF и имеет значительно меньшую аудиторию, вокруг Авалонии пока не выстроилась богатая экосистема со множеством стилей и кастомных контролов. Да и гигантских платных UI фреймворков вроде DevExpress пока не появилось. Аналогичные сложности и с инструментами разработки — они есть, и поддержка становится все лучше, однако пока что отстает по качеству от WPF.Ну и самая заметная проблема, о которой говорят многие — это отсутствие гарантий. Авалония — это инструмент, создаваемый исключительно сообществом, что не слишком-то привычно для .NET разработчиков. За ним не стоит Microsoft или какая-то другая крупная компания. В этих условиях многим не хочется рисковать, надеясь на open source продукт — кто знает, вдруг завтра мейнтейнер потеряет интерес, и разработка встанет? Однако это же дает вам возможность заметно влиять на развитие Авалонии, исправляя существующие проблемы и предлагая новые фичи.ЗаключениеПодводя итог можно сказать, что Авалония — это осовремененная версия WPF. Синтаксис чуть полегче, стили современнее, да и в целом фреймворк подталкивает к использованию современных подходов вроде реактивного программирования и декларативного DSL. Компенсация за это — типичный набор проблем молодого опенсорсного инструмента. Кое-какие фичи не реализованы, экосистема бедновата, да и качественная поддержка в будущем не гарантирована. Так или иначе, это несет и преимущества в виде возможности заметно влиять на будущее Авалонии.Если вам нравится этот фреймворк — не стесняйтесь активно участвовать в его разработке. Пишите предложения в репозитории, участвуйте в дискуссиях, правьте найденные баги и общайтесь с сообществом в телеграме Авалонии. И, конечно же, подписывайтесь на наш блог на Хабре — мы уже готовим следующую статью про Авалонию. А на сегодня все, оставайтесь на связи.
===========
Источник:
habr.com
===========
Похожие новости:
- [Python, Программирование, Машинное обучение] Подбор гиперпараметров ML-модели с помощью HYPEROPT
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] 5 подходов к стилизации React-компонентов на примере одного приложения
- [Информационная безопасность, PHP, Программирование] Защита от уязвимости Dependency Confusion в PHP с помощью Composer (перевод)
- [JavaScript, Программирование, Учебный процесс в IT] Мои рассуждения на тему Как учиться программировать на JavaScript
- [Python, Программирование] Разбираемся с not в Python (перевод)
- [Программирование, .NET, ASP, C#] Что из себя представляет класс Startup и Program.cs в ASP.NET Core (перевод)
- [Проектирование и рефакторинг, C#, Разработка под Windows] Проектирование на C# глазами первокурсника -> NotePad++ №6
- [Программирование, Функциональное программирование] Сильные стороны функционального программирования
- [Анализ и проектирование систем, .NET, Проектирование и рефакторинг, Микросервисы] Взаимодействия. RPC vs REST vs MQ
- [C#] По пути в Авалонию
Теги для поиска: #_programmirovanie (Программирование), #_.net, #_razrabotka_pod_macos (Разработка под MacOS), #_razrabotka_pod_windows (Разработка под Windows), #_avalonia, #_wpf, #_desktop, #_crossplatform, #_avaloniaui, #_.net, #_blog_kompanii_kontur (
Блог компании Контур
), #_programmirovanie (
Программирование
), #_.net, #_razrabotka_pod_macos (
Разработка под MacOS
), #_razrabotka_pod_windows (
Разработка под Windows
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 13:26
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
WPF — любимый сообществом фреймворк для десктопной разработки, однако в то время как дотнет и вся его экосистема уже давно кроссплатформенные, WPF работает только под Windows. Сообщество решило эту проблему и теперь у нас есть Авалония — фреймворк, во многом очень похожий на WPF, но работающий на разных платформах. Под катом мы разберем отличия Авалонии от WPF. Что нужно знать людям, переходящим с WPF на Авалонию? В чем преимущества нового фреймворка, а в чем его недостатки по сравнению с WPF? СтилиНа первый взгляд, стили в Авалонии выглядят точно также, как и в WPF — они задаются в блоке Styles с помощью селекторов и сеттеров. Первые выбирают набор блоков, к которым применяются стили, вторые — задают непосредственно стили. Давайте сравним два одинаковых стиля в WPF и Авалонии: <Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="FontSize" Value="24"/> </Style> <Style Selector="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="FontSize" Value="24"/> </Style> <Styles>
<Style Selector="TextBlock.h1"> <Setter Property="FontSize" Value="24"/> </Style> </Styles> <TextBlock Classes="h1">Header</TextBlock> <Styles>
<Style Selector="Button:pointerover"> <Setter Property="Button.Foreground" Value="Red"/> </Style> </Styles> <Button>I will have red text when hovered.</Button> .block > Button[IsDefault=true]
<Grid>
<Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="32"></RowDefinition> </Grid.RowDefinitions> </Grid> <Grid RowDefinitions="*,Auto,32,"/>
<UserControl xmlns:viewmodels="clr-namespace:MyApp.ViewModels;assembly=MyApp">
<UserControl.DataTemplates> <DataTemplate DataType="viewmodels:FooViewModel"> <Border Background="Red" CornerRadius="8"> <TextBox Text="{Binding Name}"/> </Border> </DataTemplate> </UserControl.DataTemplates> <UserControl.Styles> <Style Selector="ContentControl.Red"> <Setter Property="Background" Value="Red"/> </Style> </UserControl.Styles> <UserControl> <TextBox Name="source"/>
<!-- Binds to the Text property of the "source" control --> <TextBlock Name=”other” Text="{Binding #source.Text}"/> <Border Tag="Hello World!">
<TextBlock Text="{Binding $parent.Tag}"/> </Border> <Border Tag="Hello World!">
<Border> <Decorator> <TextBlock Text="{Binding $parent[Border;1].Tag}"/> </Decorator> </Border> </Border> <StackPanel>
<TextBox Name="input" IsEnabled="{Binding AllowInput}"/> <TextBlock IsVisible="{Binding !AllowInput}">Sorry, no can do!</TextBlock> </StackPanel> <Panel>
<ListBox Items="{Binding Items}"/> <TextBlock IsVisible="{Binding !Items.Count}">No results found</TextBlock> </Panel> <Panel>
<ListBox Items="{Binding Items}" IsVisible="{Binding !!Items.Count}"/> </Panel> <TextBlock Text="{Binding MyText}" IsVisible="{Binding MyText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
Подобные элементы — это вечная головная боль кроссплатформенных приложений. На маках такое меню есть, а на винде — нет. А в Linux есть, но не везде, только в некоторых оконных менеджерах. Для работы с такими меню в девятой версии Авалонии реализовали компонент NativeMenu. По умолчанию, даже без добавления NativeMenu в приложение, Авалония будет генерировать меню с базовыми пунктами — как раз они и представлены на скриншоте. А для добавления новых пунктов как раз и используется NativeMenu. <Application>
<NativeMenu.Menu> <NativeMenu> <NativeMenuItem Header="About MyApp" Command="{Binding AboutCommand}" /> </NativeMenu> </NativeMenu.Menu> </Application> module Counter =
type CounterState = { count : int } let init = { count = 0 } type Msg = | Increment | Decrement let update (msg: Msg) (state: CounterState) : CounterState = match msg with | Increment -> { state with count = state.count + 1 } | Decrement -> { state with count = state.count - 1 } let view (state: CounterState) (dispatch): IView = DockPanel.create [ DockPanel.children [ Button.create [ Button.onClick (fun _ -> dispatch Increment) Button.content "click to increment" ] Button.create [ Button.onClick (fun _ -> dispatch Decrement) Button.content "click to decrement" ] TextBlock.create [ TextBlock.dock Dock.Top TextBlock.text (sprintf "the count is %i" state.count) ] ] ] =========== Источник: habr.com =========== Похожие новости:
Блог компании Контур ), #_programmirovanie ( Программирование ), #_.net, #_razrabotka_pod_macos ( Разработка под MacOS ), #_razrabotka_pod_windows ( Разработка под Windows ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 13:26
Часовой пояс: UTC + 5