Русский
Русский
English
Статистика
Реклама

Авалония для самых маленьких

В свежем превью Rider, помимо прочего, появилась поддержка Авалонии. Авалония это самый крупный .NET фреймворк для разработки кроссплатформенного UI, и его поддержка в IDE отличный повод наконец разобраться, как писать десктопные приложения для любых платформ.

В этой статье я на примере простой задачи по реализации калькулятора покажу:

  • как управлять разметкой,
  • как связывать функциональность с компонентами,
  • как управлять стилями.



Подготовка


Для работы я использовал:


Единственным обязательным инструментов в этом списке является сам дотнет. Остальное можете выбирать сами: любимую операционную систему и IDE (например, тот же Rider).
Для инициализации проекта мы воспользуемся шаблонами .NET приложений для Авалонии. Для этого нам потребуется клонировать репозиторий с шаблонами, а затем установить скачанные шаблоны:

git clone https://github.com/AvaloniaUI/avalonia-dotnet-templates.gitdotnet new --install /path/avalonia-dotnet-templates/

Типы проектов Авалонии
Типы проектов

Теперь, когда шаблоны установлены, мы можем создать новый проект на основе MVVM шаблона Авалонии:

dotnet new avalonia.mvvm -o ACalc

Перейдем в директорию проекта и обновим все версии пакетов на самые новые (на момент написания статьи):

dotnet add package Avalonia --version 0.10.0-preview6dotnet add package Avalonia.Desktop --version 0.10.0-preview6dotnet add package Avalonia.ReactiveUI --version 0.10.0-preview6

Давайте внимательнее посмотрим на структуру проекта, сгенерированную шаблоном:

image

  • В папке Assets хранятся ресурсы, используемые нами в данном проекте. На текущий момент там лежит лого Авалонии, использующееся в качестве иконки приложения.
  • В папку Model мы будем складывать все общие модели, используемые в нашем приложении. На текущий момент она пуста.
  • Папка ViewModels предназначена для хранения логики, которая будет использоваться в каждом из окон. Прямо сейчас в этой папке хранится ViewModel главного окна и базовый класс для всех ViewModel.
  • В папке Views хранится разметка окон (а также code behind файл, в который хоть и можно положить логику, но лучше для этих целей использовать ViewModel). На текущий момент у нас есть только главное окно.
  • App.xaml общий конфиг приложения. Несмотря на то, что он и выглядит как еще одно окно, на самом деле, этот файл служит для задания общих настроек приложения.
  • ViewLocator нам в этот раз не пригодится, так как он используется для создания кастомных контролов. Подробнее о нем можно почитать в документации Авалонии.

Запустим наше приложение командой dotnet run.



Теперь все готово для разработки.

Разметка


Начнем с создания базовой разметки. Перейдем в файл Views/MainWindow.xaml там будет храниться разметка главного окна нашего калькулятора.



В данный момент наша разметка состоит из базовых параметров окна (размеров, иконки и заголовка) и одного блока с текстом. Давайте заменим этот блок с текстом на Grid, который будет служить скелетом нашей разметки. Этот контрол разложит все элементы по порядку, один за другим.

Итак, заменим TextBlock на пустой Grid:

<Grid></Grid>

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

<Grid>    <Grid.RowDefinitions>        <RowDefinition Height="auto"></RowDefinition>        <RowDefinition Height="auto"></RowDefinition>        <RowDefinition Height="*"></RowDefinition>    </Grid.RowDefinitions></Grid>

Теперь заполним разметку основными компонентами добавим строку меню, базовый экран и вложенный Grid для блока клавиш:

<Grid>    <Grid.RowDefinitions>        <RowDefinition Height="auto"></RowDefinition>        <RowDefinition Height="auto"></RowDefinition>        <RowDefinition Height="*"></RowDefinition>    </Grid.RowDefinitions>    <!--строка меню-->    <Menu>    </Menu>    <!--Импровизированный экран нашего калькулятора-->    <TextBlock>    </TextBlock>    <!--Grid для клавиш-->    <Grid></Grid></Grid>

Отдельно остановимся на расположении клавиш в сетке.
Для начала нужно описать количество строк и столбцов в нашем Grid. А после разложить кнопки по соответствующим им строкам и столбцам, указав их координаты.

<Grid>    <Grid.RowDefinitions>        <RowDefinition></RowDefinition>        <RowDefinition></RowDefinition>        <RowDefinition></RowDefinition>        <RowDefinition></RowDefinition>        <RowDefinition></RowDefinition>    </Grid.RowDefinitions>    <Grid.ColumnDefinitions>        <ColumnDefinition></ColumnDefinition>         <ColumnDefinition></ColumnDefinition>         <ColumnDefinition></ColumnDefinition>         <ColumnDefinition></ColumnDefinition>         <ColumnDefinition></ColumnDefinition>    </Grid.ColumnDefinitions>    <Button Grid.Row="0" Grid.Column="0">1</Button></Grid>

Стоит отметить, что элементы внутри Grid могут занимать несколько ячеек. Для этого используются параметры ColumnSpan и RowSpan:

 <Button Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="2">=</Button>

Остальные кнопки добавляются аналогично, поэтому готовую разметку можно посмотреть сразу в репозитории проекта.

Последнее, что нам осталось сделать это задать параметры окна. Установим стартовые и минимальные размеры окна (они задаются в корневом элементе Window).

MinHeight="300"MinWidth="250"Height="300"Width="250"

После добавления всех элементов разметки наше окно калькулятора будет выглядеть так:



Основной функционал


С разметкой закончили, пора реализовать логику!

Начнем с добавления в папку Models нового Enum, который описывает возможные операции:

public enum Operation{    Add,    Subtract,    Multiply,    Divide,    Result}

Теперь перейдем в класс ViewModel/MainWindowViewModel. Здесь будет храниться основная функциональность нашего приложения.

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

private double _firstValue;private double _secondValue;private Operation _operation = Operation.Add;

Теперь реализуем основные методы:

  • AddNumber добавляет новую цифру к числу.
  • ExecuteOperation выполняет одну из операций, описанных в енаме Operation.
  • RemoveLastNumber удаляет последнюю введенную цифру.
  • ClearScreen очищает экран калькулятора.

Не будем останавливаться на реализации этих методов, в этом нет никакой специфики для Авалонии (реализацию вы можете посмотреть в репозитории проекта). Единственное, что нас интересует это то, что помимо перечисленных выше приватных полей, эти методы также оперируют публичным свойством ShownValue. О нем чуть позже.

Связывание


Теперь, когда у нас готовы и разметка, и логика, пора связать их друг с другом.
В Авалонию по умолчанию включен Reactive UI это фреймворк, предназначенный как раз для связывания View и Model при использовании MVVM. Подробнее о нем вы сможете прочитать на официальном сайте и в документации Авалонии. Конкретно сейчас нас интересует возможность фреймворка обновлять View при изменении данных.

Для хранения актуального значения, выводимого на экране, реализуем свойство ShownValue:

public double ShownValue{    get => _secondValue;    set => this.RaiseAndSetIfChanged(ref _secondValue, value);}

Получаемое из этого свойства значение будет выводиться на дисплее нашего калькулятора, а метод RaiseAndSetIfChanged позаботится о вызове уведомления при изменении значения свойства.

Привяжем это свойство к созданному на этапе разметки текстовому полю:

<TextBlock Grid.Row="1" Text="{Binding ShownValue}" />

Благодаря директиве Binding и методу RaiseAndSetIfChanged значение свойства Text в этом поле будет обновляться при каждом изменении значения свойства ShownValue.

Теперь добавим в MainWindowViewModel еще три публичных свойства для команд. Команды являются обертками вокруг функций, которые будут вызываться определенными действиями на UI.

public ReactiveCommand<int, Unit> AddNumberCommand { get; }public ReactiveCommand<Unit, Unit> RemoveLastNumberCommand { get; }public ReactiveCommand<Operation, Unit> ExecuteOperationCommand { get; }

Команды нужно инициализировать в конструкторе класса, связав их с соответствующими методами:

public MainWindowViewModel(){    AddNumberCommand = ReactiveCommand.Create<int>(AddNumber);    ExecuteOperationCommand = ReactiveCommand.Create<Operation>(ExecuteOperation);    RemoveLastNumberCommand = ReactiveCommand.Create(RemoveLastNumber);}

Теперь обновим разметку кнопок. Например, для клавиши Backspace новая разметка будет выглядеть так:

<Button Grid.Row="3" Grid.Column="2" Command="{Binding RemoveLastNumberCommand}"></Button>

Несколько сложнее дела обстоят с номерными кнопками и кнопками операций. Для них мы должны передать в качестве параметра вводимую цифру или операцию. Для этого в корневом теге Window нам нужно добавить пространство имен System:

xmlns:s="clr-namespace:System;assembly=mscorlib"

А затем обновить разметку кнопок, добавив в них связанный метод и параметр:

<Button Grid.Row="0" Grid.Column="0" Command="{Binding AddNumberCommand}">    <Button.CommandParameter>        <s:Int32>1</s:Int32>    </Button.CommandParameter>     1</Button>

После того, как мы аналогичным образом обновим все остальные кнопки, функциональность калькулятора будет полностью готова к работе.



Стили


Итак, логика нашего калькулятора полностью реализована, но его визуальная сторона оставляет желать лучшего. Самое время поиграться со стилями!

В Авалонии есть три способа управлять стилями:

  • настроить стили внутри компонента,
  • настроить стили в рамках окна,
  • подключить пакет стилей.

Пройдемся по каждому из них.

Начнем с настройки стилей внутри конкретного компонента. Очевидный претендент на точечные изменения это экран нашего калькулятора. Давайте увеличим для него размер шрифта и перенесем текст вправо.

<TextBlock Grid.Row="1" Text="{Binding ShownValue}" TextAlignment="Right" FontSize="30" />

Теперь поиграемся со стилями в рамках окна. Здесь мы можем изменить вид всех компонентов определенного типа. Например, можно немного раздвинуть кнопки.

<Window.Styles>    <Style Selector="Button">        <Setter Property="Margin" Value="5"></Setter>     </Style></Window.Styles>

Как видите, конкретные компоненты, к которым применяется стиль, можно выбирать при помощи селектора. Больше о селекторах вы можете прочитать в документации Авалонии.

После применения изменений выше наше окно будет выглядеть так



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

dotnet add package Material.Avalonia --version 0.10.3

А теперь обновим файл App.xaml и укажем в нем используемый пакет стилей и его параметры.

<Application ...             xmlns:themes="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"             ...>    <Application.Resources>        <themes:BundledTheme BaseTheme="Dark" PrimaryColor="Purple" SecondaryColor="Amber"/>    </Application.Resources>    <Application.Styles>        <StyleInclude Source="avares://Material.Avalonia/Material.Avalonia.Templates.xaml" />    </Application.Styles></Application>

Установленный пакет обновит визуальный стиль нашего приложения, и теперь оно будет выглядеть так:



Такие же пакеты стилей можно создавать самостоятельно их можно использовать внутри вашего проекта или распространять в виде пакета на nuget. Больше информации о стилях и способах управления ими можно найти в документации.

Заключение


В этой статье мы разобрали самый простой пример использования Авалонии, но функционал этого фреймворка куда шире, и он растет с каждым днем. Помимо неоднократно упомянутой мной документации, вы также можете спросить совета в русскоязычном чате, посвященном Авалонии, или прямо здесь в комментариях.
А еще много интересного про Авалонию и .NET UI можно будет послушать на онлайн-митапе от Контура, который пройдет сегодня, в пять по Москве.

Все исходники проекта вы можете найти в репозитории на Github.

На этом все! Оставайтесь на связи, мы вернемся со статьями о более продвинутых возможностях Авалонии.
Источник: habr.com
К списку статей
Опубликовано: 26.11.2020 12:17:06
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании контур

Программирование

Net

Разработка под macos

Разработка под windows

Avalonia

Avaloniaui

Desktop

Crossplatform

Tutorial

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru