Когда мы встречаем новый язык, мы пишем «Hello world», а когда встречаем новый UI, то создаем блокнот. Здесь же я хочу показать простейший пример дружбы с корссплатформенным GUI Framework AvaloniaUI.



В первую очередь установим необходимый шаблон.

Для этого сохраняем этот репозиторий на свой машине.

Открываем консоль и пишем:

dotnet new --install [путь до скачанного шаблона]

И создадим стартовый проект:

dotnet new avalonia.mvvm -o Notebook

Добавим простенькую разметку как в wpf в файле MainWindow.xaml.

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Notebook.ViewModels;assembly=Notebook"
        Icon="resm:Notebook.Assets.avalonia-logo.ico"
        Title="Notebook">
    <!--Биндим горячие клавиши-->
    <Window.KeyBindings>
        <KeyBinding Gesture="Ctrl+O" Command="{Binding Open}" />
        <KeyBinding Gesture="Ctrl+S" Command="{Binding Save}" />
    </Window.KeyBindings>
    <Design.DataContext>
        <vm:MainWindowViewModel />
    </Design.DataContext>
    <!--Стандартная разметочка гридом-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <!--Менюшечка-->
        <Menu Grid.Row="0" Grid.Column="0">
            <MenuItem Header="File">
                <MenuItem Header="Open" Command="{Binding Open}" />
                <MenuItem Header="Save As" Command="{Binding Save}" />
            </MenuItem>
        </Menu>
        <!--Основное текстовое поле-->
        <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding Data}"
                 AcceptsReturn="True" />
    </Grid>
</Window>

C mvvm тут все чуть по-другому, так как по дефолту используется ReactiveUI.

Так что в файле MainWindowViewModel.cs добавим:

 private string _data;

        public string Data
        {
            get => _data;
            set => this.RaiseAndSetIfChanged(ref _data, value);
        }


А вот в отличии от дефолта wpf, авалония позволяет биндить комманды напрямую к методам.
И так же стоит отметить, что файловые диалоги в данном фреймворке только асинхронные.
Тогда открытие документа будет выглядеть вот так:
 public async Task Open()
        {
            var dialog = new OpenFileDialog();
            string[] result = null;
            dialog.Filters.Add(new FileDialogFilter() {Name = "Text", Extensions = {"txt"}});
            result = await dialog.ShowAsync();
            if (result != null)
            {
                Data = File.ReadAllText(result.First());
            }
        }

А вот так сохранение:

 public async Task Save()
        {
            var dialog = new SaveFileDialog();
            dialog.Filters.Add(new FileDialogFilter() 
         
            {Name = "Text", Extensions = {"txt"}});
            var result = await dialog.ShowAsync(new MainWindow());
            if (result != null)
            {
                File.WriteAllText(result, Data);
            }
        }

Для того, что бы приложение запускалось на Линуксе придется добавить еще одну зависимость: Avalonia.Skia.Linux.Natives.

Но к сожалению не все сборки смогут отобразить наше окно. Ubuntu ( в том числе и Mate) отлично справляется как на большой (x64) архитектуре, так и на arm, а вот Raspbian явно подводит.


P.S.

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

Комментарии (13)


  1. John_Minority
    05.02.2019 02:54

    Что это?


    1. Imbecile
      05.02.2019 03:29

      MS так и не сподобился сделать кроссплатформенный UI Framework. И Xamarin — его покупка — решила проблему отчасти, ибо не умеет в Linux. И сейчас, если хочется .NET и единый UI вообще на всём, то выбирать приходится Avalonia. Open source и очень кроссплатформено, но пока что с багами.


      1. zartarn
        05.02.2019 08:40
        +1

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


  1. samodum
    05.02.2019 03:37
    +1

    Может, надо начать с того, чтобы рассказать, что это вообще такое этот ваш AvaloniaUI, для чего он нужен и какие задачи решает?
    А то вылили на нас ушат с этим кодом и что нам с ним делать?


    1. Larymar Автор
      05.02.2019 03:40

      там вроде бы сказано

      корссплатформенным GUI Framework

      Что еще он может решать, кроме кроссплатформенного отображения окон)


  1. petuhov_k
    05.02.2019 07:09

    Классная штука, эта Avalonia, жаль, что сырая и, когда доварится, не известно.

    Сам пробовал, портировать несложное приложение с UWP. В целом заработало, даже избавился от некоторых костылей. Но, есть и бочка дёгтя. Под Android запускается только Debug версия, при этом тормозит нещадно, реакция на действия десятки секунд. Под убунтой упомянутые файловые диалоги не открываются. А разработчики, похоже, сосредоточились на iOS. Жаль.


    1. kekekeks
      05.02.2019 07:52
      +1

      С диалогами был некоторый просчёт в проектировании API, когда буквально все требовали "как в WPF", ибо "на винде работает же". В итоге по дефолту ShowDialog не принимал родительского окна, что вызывало ряд спецэффектов с линуксовыми оконными менеджерами, имеющими особое мнение о том, где и как надо показывать свежепоявившиеся окна. Особенно странностями страдает третьегномовский Mutter, который окно может не показать вообще, ибо у GTKшного файлодиалога выставлен _NET_WM_STATE_SKIP_TASKBAR. Усугублялось это тем, что тестировалось всё обычно на Ubuntu+Unity, а Compiz подобной самодеятельностью не страдает, и всё работало.


      Сейчас все диалоги в обязательном порядке требуют наличия родительского окна.


      В общем, линуксозоопарк десктопных, о ряде особенностей которых можно узнать только по багрепортам. Особый смак — когда проблемы очередного WM не проявляются при запуске оного под Xephyr (приходится запускать отдельную сессию), либо дистрибутивозависимы (приходится запускать виртуалку, а там обычно ещё и llvmpipe в качестве драйвера), либо дистрибутиво- и драйверозависимы (проще повеситься). Как optirun ломает dlsym(dlopen("libdl.so.2", RTLD_NOW), "dlsym"), что делает невозможным использование dlsym через [DllImport] — вообще отдельная история.


      Ещё имели кучу проблем с патчеными версиями GTK (привет, ElementalyOS), из-за которых ничего не работало. Сейчас, вроде, осилили бакэнд, работающий напрямую с libX11 и с GLX, стало немного полегче.


      1. petuhov_k
        05.02.2019 08:12

        Никита, Вы есть крут. Ваш комментарий тянет на отдельную статью на хабре. Но, чёрт с ними, с диалогами. Ясно, что вызов нативного окна в произвольной ОС — задача неблагодарная. Меня больше волнует Android, что с ним?


        1. kekekeks
          05.02.2019 08:24

          Примерно то же самое, что и с iOS — сделали экспериментальные бакэнды, чтобы понять, где лежат грабли, и какие вообще у платформ ограничения, после чего сосредоточились на самом фреймворке и поддержке десктопа. Вот тут я с месяц назад расписывал, чего не хватает для нормальной работы на мобилках.


          С андройдом в частности главная проблема в том, что на нём очень много low-end девайсов, а моновский AOT-компилятор под эту платформу далеко не так хорош, как под iOS. Отсюда тормоза. А если по каким-то причинам OpenGLES не заведётся, будет совсем грустно (сейчас вот он там у нас после миграции на SkiaSharp выключен, например).


          Я сейчас потихоньку делаю компилятор XAML в MSIL, что должно снять хотя бы часть проблем со временем загрузки, но в целом нормальную поддержку мобилок раньше конца года ожидать не стоит.


    1. Larymar Автор
      05.02.2019 12:38

      ну хотя бы диалоги под убунтой починили


  1. VeroLom
    05.02.2019 12:37

    Может, я не очень в теме, но что мешает использовать те же Gtk/Qt/Wx? Биндинги под шарп есть.


    1. kekekeks
      05.02.2019 18:31
      +1

      GTK уже научился в per-monitor DPI на X11? У них же иксы теперь "устарели" и все силы брошены на новый более лучший дисплейный сервер. Да и отрисовку из не-UI потока нормально не сделать.


      В целом же "мешает" ими пользоваться неимоверная боль при попытке написать что-то сложнее хелловорлда привыкнув к XAML-фреймворкам, где есть нормальная человеческая поддержка MVVM.


      Моя прошлая попытка изготовить что-то на GTK# закончилась переписыванием на C++/QtWebkit/JS (электрона в те годы не было)


  1. nevdokimof
    06.02.2019 01:42

    Avalonia — крутая штука, единственная беда — очень не хватает хорошей документации, местами вообще провалы.