Прошло уже достаточно времени с публикации моей предыдущей статьи. За это время я значительно улучшил приложение. Миграция проекта с WPF на Avalonia UI, появление версий для Windows и Linux, обновленный дизайн, работа с числами типа float, а также другие возможности появились в новой версии моего Modbus терминала.

Начнем с главного. Теперь программа работает и под Windows, и под Linux. Windows версия распространяется как обернутой в инсталлер, так и portable. А Linux версия обычным zip-архивом.

Основные нововведения:

  • Проект перенесен с WPF на AvaloniaUI.

  • Изменен дизайн.

  • Добавлен Modbus сканер.

  • Modbus: для каждой функции записи сделан свой вариант дизайна.

  • Modbus: добавлено ведение истории обмена.

  • Modbus: добавлена возможность работы с бинарными данными.

  • Modbus: добавлена возможность работы с данными типа float.

  • Исправлены ошибки версии 2.7.0.

Ссылки для скачивания вы можете найти в конце статьи. Но не спешите перематывать :) Советую сначала ознакомиться с материалом ниже.

Инструкция

Для режима работы "Без протокола", думаю, пояснения не нужны. Он работает как текстовый терминал. Просто и пока без изысков.

Из прошлой версии приложения перекочевали два способа взаимодействия с хостом: "Обычный" и "Цикличный опрос". Между ними можно переключаться во время работы. Данные на вкладках не теряются при переключении.

Важно: если переключиться в обычный режим пока идет цикличный опрос, то сам опрос прекратится.

Версия для режима "Без протокола":

"Без протокола" - Обычный режим работы
"Без протокола" - Режим цикличного опроса

Версия для режима Modbus:

Modbus - Обычный режим работы
Modbus - Режим цикличного опроса

Теперь давайте поподробнее рассмотрим обычный режим работы Modbus. В этом режиме все сводится к чтению и записи регистров.

Чтение регистров Modbus

С чтением все просто. Выбираем функцию, начальный адрес, количество регистров и нажимаем кнопку «Прочитать»

Запись регистров Modbus

С записью все интереснее. Для каждой функции предусмотрен свой вариант дизайна.

Начальным адресом для всех функций является значение из поля «Адрес».

0x05 Запись одного флага

Согласно документации на протокол, в поле данных должно находится только одно из двух значений. 0x0000 – это логический ноль, а 0xFF00 – это логическая единица. Поэтому выбираем желаемое значение и нажимаем кнопку «Записать».

0x0F Запись нескольких флагов

Похожая функция, но в отличии от предыдущей позволяет записать сразу несколько флагов. С помощью кнопки «Добавить регистр» создаем нужное количество флагов, задаем значение и нажимаем кнопку «Записать».

Слева от значений регистров у нас находятся значения смещения относительно начального адреса.

Справа находятся кнопки удаления для каждого регистра.

0x06 Запись одного регистра

С помощью этой функции мы можем записывать в 16-ти разрядные регистры.

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

0x10 Запись нескольких регистров

Управление тут аналогично функции «0x0F Запись нескольких флагов».

Из интересного у нас появляется возможность записи чисел типа float.

Как мы знаем такие числа занимают 2 слова или же 4 байта. Поэтому у следующего регистра смещение уже не +1, а +2 адреса.

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

Представления

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

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

Представление последнего запроса

Название следующего представления говорит само за себя. Из интересного можно отметить разве только время отправки запроса / получения ответа. Иногда бывает полезно посмотреть при подключении по последовательному порту.

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

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

Бинарное представление

И пожалуй, пока что самое полезное представление - это представление числа типа float. Для каждых двух слов представлены все комбинации. Если же среди всех четырех вариантов не нашлось "нормального" числа (например, как в 4 адресе), то скорее всего эта пара слов не содержит float числа или же оно вот такое странное.

Представление числа типа float

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

Немного о разработке

С точки зрения кода основное нововведение это миграция проекта с WPF на Avalonia UI.

Вот основные причины на это:

  • Кроссплатформенность. Это, пожалуй, самая главная причина :) Программа теперь запускается на Windows и Linux.

  • Современный дизайн и гибкость. Из коробки нам доступна тема Fluent, которая выглядит эстетично и современно. В сети можно найти и другие темы, что позволяет нам делать красивый дизайн. Также встроенные контролы имеют более широкие настройки. Например, чтобы сделать кнопку со скругленными краями в WPF мне пришлось переопределять шаблон кнопки, а в Avalonia UI я просто задал CornerRadius у самой кнопки.

  • Возможности стилизации. В Avalonia UI используются CSS-подобные селекторы. Сразу после перехода с WPF это довольно непривычно, но со временем оказывается, что применение таких селекторов очень удобно. С помощью них, можно создавать типовые стили для контролов.

  • Меньший размер проекта. Приведу небольшое сравнение версий для Windows.

    • Версия 2.7.0 WPF: инсталлер - 47 Мб, на диске - 160 Мб.

    • Версия 3.0.0 Avalonia UI: инсталлер - 32 Мб, на диске - 103 Мб.

  • Живое сообщество. Avalonia UI активно развивается сообществом. В проект добавляется новый функционал, правятся баги. Ознакомится с проектом можно в репозитории на GitHub, а попросить помощи или просто обсудить можно в русскоязычном чате в Telegram.

Далее хочу поделиться личным опытом переноса проектов с WPF на Avalonia UI.

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

Для успешной миграции нам нужно заранее выделить всё что связанно с WPF в отдельные проекты.

Важно отметить, что в Avalonia нет стандартного MessageBox, как в WPF. Поэтому логику работы с ним тоже выносим в отдельный проект. Или же, как вариант, можно найти реализацию MessageBox на GitHub.

Следующим шагом мы просто удаляем все проекты с WPF. В том числе и из папки с решением.

Теперь собираем решение. Если все прошло успешно, то это значит, что у нас нет лишних зависимостей, и мы все сделали правильно.

Далее добавляем новый проект Avalonia UI в свое решение. Проводим стандартные манипуляции. Не забываем проверить версию .NET во всех проектах, а также удалить теперь ненужные NuGet пакеты связанные с WPF. Например, ReactiveUI.WPF заменяем на Avalonia.ReactiveUI.

Теперь выбираем в качестве запускаемого проект Desktop (моем случае это TerminalProgram.Desktop) и запускаем его. Появляется окошко. Ура! Мы все сделали правильно.

Настала очередь переноса UI. Важно помнить, что некоторые контролы из WPF отсутствуют в Avalonia UI. Но как правило можно найти аналог. Например, вместо Frame и Page можно использовать ContentControl и UserControl соответственно.

Также приведу несколько полезных ссылок:

Как уже было написано выше, Avalonia активно развивается сообществом. Важно понимать, что это сравнительно молодой GUI фреймворк. Поэтому в нем можно наткнуться на баги. Чаще всего они не доставляют проблем, но бывают и исключения.

Приведу пример. Я хотел, чтобы мое приложение выглядело одинаково на всех ОС. Поэтому мне пришлось сделать свой вариант окна. В Avalonia есть классная возможность отключить неклиентскую часть окна (WindowChrome). Но при этом оставить его границы, с помощью которых можно масштабировать окно (SystemDecorations="BorderOnly"). В версии 11.2.0 эта функция замечательно себя чувствует на Windows 10/11, и совершенно отказывается работать на дистрибутивах Linux и внезапно на Windows 7. Это не критичный баг. Но он хорошо иллюстрирует, что на них можно наткнуться при разработке. Надеюсь, его исправят в ближайших обновлениях.

В своем приложении я решил просто создать аналог ResizeGrip из WPF.

Вообще для разработки кастомных окон вам будут полезны два метода класса Window:

  • BeginMoveDrag(PointerPressedEventArgs e) - для перетаскивания окна вслед за курсором мыши.

  • BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) - для масштабирования окна вслед за курсором мыши.

Читая этот раздел, у вас может возникнуть вопрос: «А что же в итоге выбрать — Avalonia UI или WPF?» «Все зависит от задачи», — отвечу я вам. Если вам нужна кроссплатформенность, гибкость, красивый дизайн, и вы готовы мериться с редкими небольшими багами, то смотрите в сторону Avalonia UI. А если же у вас корпоративный софт на Windows машинах с дизайном "чтобы просто было", то может проще использовать Windows Forms? :)

Итого

Версия приложения 3.0.0 писалась довольно долго. Основные фичи этого обновления - это все же добавление кроссплатформенности и новый дизайн. Также я прислушался к пожеланиям пользователей в комментариях к предыдущей статье. Часть из них совпадали с моими пожеланиями и возможностями. Что и вылилось в новую версию терминала. Надеюсь, вам понравилось мое приложение. Буду рад обратной связи в комментариях.

Приложение тестировалось на Windows 10/11, Ubuntu и Astra Linux.

Смотрите также: