- PVSM.RU - https://www.pvsm.ru -

Стильная Авалония

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

Стильная Авалония - 1

Для чего же нужны стили в фреймворке авалония?

  1. Стили дают большую свободу при кастомизации элементов;
  2. Позволяют не дублировать описания элементов;
  3. Разделяют саму разметку и ее дизайн.

Пара примеров

Для лучшего понимания стилей сначала обратимся к примеру:

Закругленная кнопка (нечто, похожее на убунту гном)
Для этого создадим в стандартном шаблоне (как создать шаблон [1]) простенькую разметку из стек панели и пары кнопок.

  <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>

Стильная Авалония - 2

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

<Style Selector="Button /template/ ContentPresenter">
            <Setter Property="CornerRadius" Value="10" />
        </Style>

Стильная Авалония - 3

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

Стильная Авалония - 4

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

  <Style Selector="Button:pointerover /template/ ContentPresenter">
            <Setter Property="BorderBrush" Value="#FFDD4812" />
        </Style>

Стильная Авалония - 5

Так гораздо лучше.

А что, если я хочу применить стили только к конкретным кнопкам?

Добавим к шаблону еще одну кнопку и пропишем кнопкам, которые хотим «украсить», атрибут 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>

Стильная Авалония - 6

Весь код окна

<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>

Еще один интересный пример стилизации

Стандартный чекбокс выглядит вот так:

Стильная Авалония - 7

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

Стильная Авалония - 8

Немного магии

<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>

Большее разделение

С усложнением кода мы уже не хотим держать стили внутри разметки окна, а предпочли бы их вынести в отдельный файл:

Стильная Авалония - 9

Для этого создадим директорию 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 новых файла в проект:

Стильная Авалония - 10

В 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>

Еще немного полезного

Обязательно ознакомтесь с официальным туториалом авалонии по стилям (тык [2])
Базовые представления о том, как написать стиль для того, или иного элемента вы можете получить здесь (тык [3])
А если у вас нет временижелания составлять свой стиль, то вы можете воспользоваться этим замечательным генератором стилей (тык [4])

Стильная Авалония - 11

Хотелось бы сказать спасибо ForNeVeR [5] kekekeks [6] worldbeater [7]

И отметить, что поддержку по c# можно найти здесь [8], а по авалонии здесь [9].

Автор: Larymar

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/c-2/332826

Ссылки в тексте:

[1] как создать шаблон: https://habr.com/ru/post/469703/

[2] тык: https://avaloniaui.net/docs/styles/

[3] тык: https://github.com/AvaloniaUI/Avalonia/tree/master/src/Avalonia.Themes.Default

[4] тык: https://github.com/wieslawsoltes/ThemeEditor

[5] ForNeVeR: https://habr.com/ru/users/fornever/

[6] kekekeks: https://habr.com/ru/users/kekekeks/

[7] worldbeater: https://habr.com/ru/users/worldbeater/

[8] здесь: https://t.me/DotNetRuChat

[9] здесь: https://t.me/Avalonia

[10] Источник: https://habr.com/ru/post/471046/?utm_source=habrahabr&utm_medium=rss&utm_campaign=471046