Прошло уже достаточно времени с публикации моей предыдущей статьи. За это время я значительно улучшил приложение. Миграция проекта с WPF на Avalonia UI, обновленный дизайн, работа с числами типа float, а также другие возможности появились в новой версии моего Modbus терминала.
Начнем с главного. Теперь программа работает и под Windows, и под Linux. Windows версия распространяется как обернутой в инсталлер, так и portable. А Linux версия обычным zip-архивом.
Основные нововведения:
Проект перенесен с WPF на AvaloniaUI.
Изменен дизайн.
Добавлен Modbus сканер.
Modbus: для каждой функции записи сделан свой вариант дизайна.
Modbus: добавлено ведение истории обмена.
Modbus: добавлена возможность работы с бинарными данными.
Modbus: добавлена возможность работы с данными типа float.
Исправлены ошибки версии 2.7.0.
Ссылки для скачивания вы можете найти в конце статьи. Но не спешите перематывать :) Советую сначала ознакомиться с материалом ниже.
Инструкция
Для режима работы "Без протокола", думаю, пояснения не нужны. Он работает как текстовый терминал. Просто и пока без изысков.
Из прошлой версии приложения перекочевали два способа взаимодействия с хостом: "Обычный" и "Цикличный опрос". Между ними можно переключаться во время работы. Данные на вкладках не теряются при переключении.
Важно: если переключиться в обычный режим пока идет цикличный опрос, то сам опрос прекратится.
Версия для режима "Без протокола":
Версия для режима Modbus:
Теперь давайте поподробнее рассмотрим обычный режим работы Modbus. В этом режиме все сводится к чтению и записи регистров.
Чтение регистров Modbus
С чтением все просто. Выбираем функцию, начальный адрес, количество регистров и нажимаем кнопку «Прочитать»
Запись регистров Modbus
С записью все интереснее. Для каждой функции предусмотрен свой вариант дизайна.
Начальным адресом для всех функций является значение из поля «Адрес».
0x05 Запись одного флага
Согласно документации на протокол, в поле данных должно находится только одно из двух значений. 0x0000 – это логический ноль, а 0xFF00 – это логическая единица. Поэтому выбираем желаемое значение и нажимаем кнопку «Записать».
0x0F Запись нескольких флагов
Похожая функция, но в отличии от предыдущей позволяет записать сразу несколько флагов. С помощью кнопки «Добавить регистр» создаем нужное количество флагов, задаем значение и нажимаем кнопку «Записать».
Слева от значений регистров у нас находятся значения смещения относительно начального адреса.
Справа находятся кнопки удаления для каждого регистра.
0x06 Запись одного регистра
С помощью этой функции мы можем записывать в 16-ти разрядные регистры.
Формат записываемого числа выбирается в выпадающем списке справа от поля ввода. При смене формата число автоматически преобразуется.
0x10 Запись нескольких регистров
Управление тут аналогично функции «0x0F Запись нескольких флагов».
Из интересного у нас появляется возможность записи чисел типа float.
Как мы знаем такие числа занимают 2 слова или же 4 байта. Поэтому у следующего регистра смещение уже не +1, а +2 адреса.
Иногда бывает, что устройство может использовать нетипичный формат для расшифровки чисел типа float. И чтобы подстроиться под конкретное устройство в настройках можно выбрать нужный формат записи.
Представления
Просто значения регистров можно посмотреть в табличном представлении. Но, к сожалению, в этих числах не всегда есть смысл. И иногда их требуется "расшифровать". Поэтому для интерпретации данных в терминале предусмотрена область с представлениями.
Первым идет представление последнего запроса. Тут можно увидеть просто байты запроса и ответа. Это удобно использовать, например, когда идет отладка устройства с самодельной реализацией протокола. Или же когда полученный результат показался сомнительным, и хочется посмотреть детали обмена.
Название следующего представления говорит само за себя. Из интересного можно отметить разве только время отправки запроса / получения ответа. Иногда бывает полезно посмотреть при подключении по последовательному порту.
Бинарное представление в основном нужно для удобной работы с масками. А чтобы в конце рабочего дня единицы не сливались с нулями, я решил помимо группировки, разделить биты цветом, в зависимости от их значения.
И пожалуй, пока что самое полезное представление - это представление числа типа float. Для каждых двух слов представлены все комбинации. Если же среди всех четырех вариантов не нашлось "нормального" числа (например, как в 4 адресе), то скорее всего эта пара слов не содержит 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.
Смотрите также:
Терминал Modbus TCP / RTU / ASCII с открытым исходным кодом: Часть 1
AngryPinguin
А не пробовали на андроиде запустить? Авалония просто это вроде как позволяет.
AndreyAbdulkayumov Автор
Нет, не пробовал) Я проектировал дизайн под десктоп. На мобильных устройствах будет мелковато.
checkpoint
Под FreeBSD можете собрать ? Готов потестировать. :)
AndreyAbdulkayumov Автор
К сожалению, под FreeBSD собрать не получится. Ни Avalonia, ни .NET официально не поддерживают эту ОС. И при разработке я все же ориентировался на версии только для Windows/Linux.
Но вы можете попробовать это сделать сами :) Код лежит в свободном доступе.