Стили, по умолчанию, что в wpf, что в авалонии, крайне нейтральны, и далеко не всегда подходят под нужные нам задачи, и немногие начинающие разработчики дружат с ними. В этой заметке я бы хотел рассказать про основы работы со стилями и показать пару интересных примеров.

Для чего же нужны стили в фреймворке авалония?
Для лучшего понимания стилей сначала обратимся к примеру:
Закругленная кнопка (нечто, похожее на убунту гном)
Для этого создадим в стандартном шаблоне (как создать шаблон) простенькую разметку из стек панели и пары кнопок.
Теперь мы можем ручками задать кнопкам основной фон и цвет шрифта, но тогда нам придется дублировать код. Стиль поможет избежать этого повтора.
Добавим окну соответствующий стиль:

Получаем нечто похожее, но было бы неплохо скруглить края. К сожалению, как бы мы не пытались, скруглить края кнопки невозможно, но можно скруглить края шаблона, отвечающего за отображение кнопки. Для этого добавим еще один стиль:

Получилось почти похоже, однако есть проблема — при наведении на кнопку появляется какая-то серая рамка (привет от стандартного стиля).

Для этого обратимся к псевдоклассуcss :pointerover и добавим еще один стиль:

Так гораздо лучше.
А что, если я хочу применить стили только к конкретным кнопкам?
Добавим к шаблону еще одну кнопку и пропишем кнопкам, которые хотим «украсить», атрибут Classes.
А стилям укажем, что надо влиять только на определенные классы:

Стили можно использовать как в рамках окна (как мы делали в примерах, написанных выше),
так и в рамках всего приложения (тогда стиль применится во всех окнах).
Для этого нужно добавить стиль в файл App.xaml
С усложнением кода мы уже не хотим держать стили внутри разметки окна, а предпочли бы их вынести в отдельный файл:

Для этого создадим директорию Styles и поместим туда наши стили в виде xml или xaml файлов, добавив указания неймспейсов:
Добавим в проектный файл (*.csproj) новые ресурсы:
И подключим их используя тег StyleInclude
Но иногда этого недостачно, и хочется вынести стили в отдельную dll, чтобы использовать во всех своих проектах.
Для этого создадим ClassLibrary и обеспечим поддержку наших будущих файлов в качестве авалония ресурсов:
Теперь добавим уже знакомый нам Styles.xml и еще 2 новых файла в проект:

В xaml файле обязательно нужно указать неймспейсы и класс, которому он принадлежит, а так же подлючение необходимого ресурса:
А в cs файле определим, что это стиль и не более:
Добавим зависимость на нашу библиотеку и вновь подключим стиль, указав стиль как авалония ресурс, используя StyleInclude и
Обязательно ознакомтесь с официальным туториалом авалонии по стилям (тык)
Базовые представления о том, как написать стиль для того, или иного элемента вы можете получить здесь (тык)
А если у вас нет времени\желания составлять свой стиль, то вы можете воспользоваться этим замечательным генератором стилей (тык)

Хотелось бы сказать спасибо ForNeVeR kekekeks worldbeater
И отметить, что поддержку по c# можно найти здесь, а по авалонии здесь.

Для чего же нужны стили в фреймворке авалония?
- Стили дают большую свободу при кастомизации элементов;
- Позволяют не дублировать описания элементов;
- Разделяют саму разметку и ее дизайн.
Пара примеров
Для лучшего понимания стилей сначала обратимся к примеру:
Закругленная кнопка (нечто, похожее на убунту гном)
Для этого создадим в стандартном шаблоне (как создать шаблон) простенькую разметку из стек панели и пары кнопок.
<StackPanel> <Button Margin="20" Content="Btn" /> <Button Margin="20" Content="Style Btn" /> </StackPanel>
Теперь мы можем ручками задать кнопкам основной фон и цвет шрифта, но тогда нам придется дублировать код. Стиль поможет избежать этого повтора.
Добавим окну соответствующий стиль:
<Window.Styles> <Style Selector="Button"> <Setter Property="Foreground" Value="#FFFFFFFF" /> <Setter Property="BorderThickness" Value="2" /> <Setter Property="Background" Value="#FFDD4812" /> <Setter Property="BorderBrush" Value="#FFFFFFFF" /> </Style> </Window.Styles>

Получаем нечто похожее, но было бы неплохо скруглить края. К сожалению, как бы мы не пытались, скруглить края кнопки невозможно, но можно скруглить края шаблона, отвечающего за отображение кнопки. Для этого добавим еще один стиль:
<Style Selector="Button /template/ ContentPresenter"> <Setter Property="CornerRadius" Value="10" /> </Style>

Получилось почти похоже, однако есть проблема — при наведении на кнопку появляется какая-то серая рамка (привет от стандартного стиля).

Для этого обратимся к псевдоклассу
<Style Selector="Button:pointerover /template/ ContentPresenter"> <Setter Property="BorderBrush" Value="#FFDD4812" /> </Style>

Так гораздо лучше.
А что, если я хочу применить стили только к конкретным кнопкам?
Добавим к шаблону еще одну кнопку и пропишем кнопкам, которые хотим «украсить», атрибут Classes.
<StackPanel> <Button Margin="20" Content="Btn" /> <Button Margin="20" Classes="btn" Content="Style Btn" /> <Button Margin="20" Classes="btn" Content="Style Btn" /> </StackPanel>
А стилям укажем, что надо влиять только на определенные классы:
<Style Selector="Button.btn /template/ ContentPresenter"> <Setter Property="CornerRadius" Value="10" /> </Style> <Style Selector="Button.btn"> <Setter Property="Foreground" Value="#FFFFFFFF" /> <Setter Property="BorderThickness" Value="2" /> <Setter Property="Background" Value="#FFDD4812" /> <Setter Property="BorderBrush" Value="#FFFFFFFF" /> </Style> <Style Selector="Button:pointerover.btn /template/ ContentPresenter"> <Setter Property="BorderBrush" Value="#FFDD4812" /> </Style>

Весь код окна
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:Wind1.ViewModels;assembly=Wind1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Wind1.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" Title="Wind1"> <Window.Styles> <Style Selector="Button.btn /template/ ContentPresenter"> <Setter Property="CornerRadius" Value="10" /> </Style> <Style Selector="Button.btn"> <Setter Property="Foreground" Value="#FFFFFFFF" /> <Setter Property="BorderThickness" Value="2" /> <Setter Property="Background" Value="#FFDD4812" /> <Setter Property="BorderBrush" Value="#FFFFFFFF" /> </Style> <Style Selector="Button:pointerover.btn /template/ ContentPresenter"> <Setter Property="BorderBrush" Value="#FFDD4812" /> </Style> </Window.Styles> <StackPanel> <Button Margin="20" Content="Btn" /> <Button Margin="20" Classes="btn" Content="Style Btn" /> <Button Margin="20" Classes="btn" Content="Style Btn" /> </StackPanel> </Window>
Еще один интересный пример стилизации
Стандартный чекбокс выглядит вот так:

Чуть улучшенный похож на андроидный (немного)


Чуть улучшенный похож на андроидный (немного)

Немного магии
<Window.Styles> <Style Selector="CheckBox.uberbox"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid> <Border Background="#b0b0b0" Padding="5" BorderBrush="#303030" CornerRadius="5"> <Grid> <Grid Classes="unchecked" ColumnDefinitions=" Auto, Auto"> <Border Width="20" Height="20" Background="Blue" CornerRadius="5" /> <TextBlock FontWeight="Bold" Margin="5,0,0,0" Grid.Column="1">0FF </TextBlock> </Grid> <Grid Classes="checked" ColumnDefinitions=" Auto, Auto"> <Border Grid.Column="1" Width="20" Height="20" Background="Red" CornerRadius="5" /> <TextBlock FontWeight="Bold" Margin="0,0,5,0"> ON </TextBlock> </Grid> </Grid> </Border> <Border Classes="fade" Background="White" CornerRadius="5" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style Selector="CheckBox.uberbox /template/ Grid.checked"> <Setter Property="Opacity" Value="0" /> </Style> <Style Selector="CheckBox.uberbox:checked /template/ Grid.checked"> <Setter Property="Opacity" Value="1" /> </Style> <Style Selector="CheckBox.uberbox:checked /template/ Grid.unchecked"> <Setter Property="Opacity" Value="0" /> </Style> <Style Selector="CheckBox.uberbox /template/ Border.fade"> <Setter Property="Opacity" Value="0" /> </Style> <Style Selector="CheckBox.uberbox:pointerover /template/ Border.fade"> <Setter Property="Opacity" Value="0.2" /> </Style> </Window.Styles> <StackPanel> <CheckBox Classes="uberbox" Margin="10" /> </StackPanel>
Где использовать стили
Стили можно использовать как в рамках окна (как мы делали в примерах, написанных выше),
так и в рамках всего приложения (тогда стиль применится во всех окнах).
Для этого нужно добавить стиль в файл App.xaml
<Application.Styles> <StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/> <Style Selector="Button"> <Setter Property="Background" Value="Blue"></Setter> </Style> </Application.Styles>
Большее разделение
С усложнением кода мы уже не хотим держать стили внутри разметки окна, а предпочли бы их вынести в отдельный файл:

Для этого создадим директорию Styles и поместим туда наши стили в виде xml или xaml файлов, добавив указания неймспейсов:
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard"> <Style Selector="Button /template/ ContentPresenter"> <Setter Property="CornerRadius" Value="10" /> </Style> <Style Selector="Button"> <Setter Property="Foreground" Value="#FFFFFFFF" /> <Setter Property="BorderThickness" Value="2" /> <Setter Property="Background" Value="#FFDD4812" /> <Setter Property="BorderBrush" Value="#FFFFFFFF" /> </Style> <Style Selector="Button:pointerover /template/ ContentPresenter"> <Setter Property="BorderBrush" Value="#FFDD4812" /> </Style> </Styles>
Добавим в проектный файл (*.csproj) новые ресурсы:
<AvaloniaResource Include="Styles\**" />
И подключим их используя тег StyleInclude
<Window.Styles> <StyleInclude Source="/Styles/Style.xml"/> </Window.Styles>
Но иногда этого недостачно, и хочется вынести стили в отдельную dll, чтобы использовать во всех своих проектах.
Для этого создадим ClassLibrary и обеспечим поддержку наших будущих файлов в качестве авалония ресурсов:
<ItemGroup> <AvaloniaResource Include="**\*.xaml"> <SubType>Designer</SubType> </AvaloniaResource> </ItemGroup> <ItemGroup> <AvaloniaResource Include="**\*.xml"> <SubType>Designer</SubType> </AvaloniaResource> </ItemGroup>
Теперь добавим уже знакомый нам Styles.xml и еще 2 новых файла в проект:

В xaml файле обязательно нужно указать неймспейсы и класс, которому он принадлежит, а так же подлючение необходимого ресурса:
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ClassLibrary1.DarkCustom"> <StyleInclude Source="avares://ClassLibrary1/Style.xml"/> </Styles>
А в cs файле определим, что это стиль и не более:
namespace ClassLibrary1 { public class DarkCustom:Styles { } }
Добавим зависимость на нашу библиотеку и вновь подключим стиль, указав стиль как авалония ресурс, используя StyleInclude и
<Window.Styles> <StyleInclude Source="avares://ClassLibrary1/DarkCustom.xaml"/> </Window.Styles>
Еще немного полезного
Обязательно ознакомтесь с официальным туториалом авалонии по стилям (тык)
Базовые представления о том, как написать стиль для того, или иного элемента вы можете получить здесь (тык)
А если у вас нет времени\желания составлять свой стиль, то вы можете воспользоваться этим замечательным генератором стилей (тык)

Хотелось бы сказать спасибо ForNeVeR kekekeks worldbeater
И отметить, что поддержку по c# можно найти здесь, а по авалонии здесь.
