WPF приложение на десктопе, планшете, телефоне
WPF приложение на десктопе, планшете, телефоне

Уже более пяти лет мы занимаемся разработкой OpenSilveropen-source фреймворка, который позволяет переносить приложения на базе WPF и Silverlight в современный веб. Проект стабильно развивается, активно используется в корпоративной среде, и недавно мы задумались о том, как расширить возможности наших пользователей и запустить существующие приложения ещё и на iOS и Android.

Поскольку под капотом OpenSilver использует платформу Blazor, логичным шагом стала интеграция с .NET MAUI Blazor Hybrid. В этой статье я расскажу, как прошла интеграция и какие результаты мы получили на практике. Забегая вперёд, скажу, что результатом мы остались очень довольны!

Краткий обзор MAUI Blazor Hybrid и OpenSilver

.NET MAUI Blazor Hybrid позволяет запускать Blazor веб-приложения в нативной оболочке для Windows, macOS, iOS и Android. Технически это реализовано благодаря компоненту WebView, встроенному в нативный MAUI-контейнер. Таким образом, приложение выглядит и ощущается нативным, сохраняя пользовательский интерфейс и логику, созданные на HTML, CSS и C#.

Основное преимущество Blazor Hybrid — отсутствие необходимости в отдельном сервере или WebAssembly: весь код выполняется локально в единой среде .NET. Это упрощает разработку и позволяет использовать все возможности .NET MAUI, включая доступ к API платформы, работу с файлами, GPS, уведомления и другие нативные функции устройств.

OpenSilver занимается транспиляцией XAML (подмножество WPF) в C#, выполнением кода, а затем генерацией HTML, CSS и JavaScript для отображения интерфейса во время выполнения программы. И тут пазл сложился! Мы берем платформу MAUI Blazor Hybrid, запускаем там C# код и показываем наш интерфейс в предоставленном WebView.

Вроде бы все идеально, однако здесь нас ожидал первый сюрприз.

Проблемы с потоками

Нам критично в некоторых случаях выполнять JavaScript-код синхронно. К сожалению, WebView поддерживает только асинхронные вызовы. Чтобы решить этот вопрос мы были вынуждены создать отдельный поток для OpenSilver-части приложения, поэтому формально у нас теперь два UI-потока: основной UI-поток MAUI и UI-поток OpenSilver.

Достаточно скоро становится очевидно, что для OpenSilver потока нам требуется собственный Dispatcher. Поскольку MAUI не позволяет создать два потока с Dispatcher'ом, мы интегрировали свою реализацию.

Другая важная задача — обращение к системным API, которые требуют выполнения из главного MAUI UI-потока. Здесь MAUI предоставляет стандартный путь и мы можем смело сделать такой вызов. Правда, нам нужно понимать, где какой код будет выполнен.

Давайте рассмотрим этот вопрос на примере получения координат:

//Переключаемся на MAUI UI поток
MainThread.BeginInvokeOnMainThread(async () =>
{
    //Получаем необходимый доступ
    var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();

    if (status != PermissionStatus.Granted)
    {
        status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
    }

    if (status == PermissionStatus.Granted)
    {
        //Получаем координаты
        var request = new GeolocationRequest(GeolocationAccuracy.Medium);
        var location = await Geolocation.Default.GetLocationAsync(request);

        if (location != null)
        {
            //Переключаемся назад на OpenSilver UI поток
            Dispatcher.BeginInvoke(() =>
            {
                TB.Text = location.ToString();
            });
        }
    }
    else
    {
        //Переключаемся назад на OpenSilver UI поток
        Dispatcher.BeginInvoke(() =>
        {
            MessageBox.Show("Location permission denied.");
        });
    }
});

Переключение между потоками — пожалуй, единственное серьёзное неудобство этого подхода. Однако, поняв идею двух потоков и Dispatcher'ов, работать становится вполне комфортно.

Нативные API

Одно из главных преимуществ MAUI Blazor Hybrid — это простой и прямой доступ к нативным API устройств на всех поддерживаемых платформах. Ваше приложение, написанное на OpenSilver, теперь легко может использовать такие функции, как работа с файлами и папками устройства, доступ к камере, геолокации и датчикам, отправка локальных уведомлений, а также взаимодействие с системными диалогами и буфером обмена, как любое полноценное нативное приложение!

Например, вы можете быстро интегрировать функциональность съемки фотографий или сканирования QR-кодов, используя камеру устройства. Или предоставить пользователям возможность сохранять файлы напрямую на диск смартфона или компьютера. Вся работа с этими возможностями происходит непосредственно из C# кода, без необходимости писать специфические реализации отдельно под каждую платформу. Это существенно ускоряет разработку и делает ваши OpenSilver-приложения по-настоящему универсальными.

Сторонние библиотеки

Возникает вопрос, как работать со сторонними библиотеками в данном подходе.

Библиотеки без UI-компонентов используются без проблем как есть.

С UI-библиотеками сложнее — их требуется предварительно мигрировать на OpenSilver. Сначала проверьте доступность уже смигрированных библиотек в NuGet, если таких нет, придётся мигрировать самостоятельно. Для этого нужен исходный код, и собрать библиотеку как OpenSilver версию.

Как попробовать?

Пожалуй, проще всего будет попробовать в Visual Studio 2022 на Windows:

  1. Установите расширение OpenSilver SDK.

  2. Убедитесь, что в Visual Studio установлен .NET MAUI компонент.

    .NET MAUI компонент
    .NET MAUI компонент
  3. Создайте новый OpenSilver-проект, добавив поддержку дополнительных платформ (например, Windows и Android) во время создания в окне конфигурации.

    Создание OpenSilver проекта
    Создание OpenSilver проекта
  4. В созданном решении разрабатывайте в основном проекте аналогично обычному WPF-приложению. Можно использовать наш Drag'n'Drop UI дизайнер.

    Работа над приложением
    Работа над приложением
  5. Запускайте проект либо в браузере (.Browser проект), либо как нативное приложение (.MauiHybrid проект).

    Запуск приложения
    Запуск приложения

Также можно использовать Visual Studio Code на Mac и Windows, подробнее описано в документации.

Реальный пример

Чтобы протестировать идею, мы взяли давнишнее WPF-приложение компании — календарь с событиями на месяц вперёд, и полностью мигрировали его на OpenSilver.

Миграция прошла относительно легко, поскольку проект не имел сторонних зависимостей. Однако потребовались небольшие изменения в реализации, так как OpenSilver пока не обеспечивает стопроцентную совместимость с WPF.

Дополнительным преимуществом использования MAUI является встроенная возможность публикации приложений во всех популярных магазинах приложений.

Теперь вы можете попробовать реальное смигрированное WPF-приложение:

Исходный код проекта также доступен: ToDoCalendar.

Заключение

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

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


  1. peacemakerv
    12.05.2025 06:34

    А Линух ?


    1. TerekhinSergey
      12.05.2025 06:34

      так поверх MAUI же, а там линукс не завезли и не завезут походу


    1. JacobL Автор
      12.05.2025 06:34

      Мы тоже пришли к этому вопросу! Поэтому сделали еще один способ запуска. Через Photino. Мне Photino очень понравился. Единственное - нельзя использовать нативные MAUI API, так что придется это еще дополнительно реализовать под линукс. Кстати, пример с ToDoCalendar также имеет возможность запускаться на линуксе через Photino.


  1. MagMagals
    12.05.2025 06:34

    Зачем, когда есть AvaloniaUI?


    1. JacobL Автор
      12.05.2025 06:34

      Чтобы не было монополии. У пользователя должен быть выбор :)


      1. MagMagals
        12.05.2025 06:34

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


  1. Einherjar
    12.05.2025 06:34

    Я не очень понял чем это лучше чем просто MAUI as is?


    1. JacobL Автор
      12.05.2025 06:34

      Самое большое преимущество — возможность запускать приложение еще в браузере! Для кого-то плюс это то, что версия XAML из WPF. И, в целом, принципиально другая реализация рендеринга, чем в MAUI. Так что, если по каким-то причинам не устраивает рендеринг в MAUI, то можно воспользоваться нашей реализацией.


      1. Einherjar
        12.05.2025 06:34

        Для кого-то плюс это то, что версия XAML из WPF

        XAML из WPF это нигде не самоцель. Любое легаси на нем держат две вещи - сторонние библиотеки (зачастую платные/закрытые) и обилие всяких костылей и хаков. Если при переходе на что то "похожее на WPF"/"якобы совместимое c WPF"/whatever что-либо из этого отваливается, то количество трудозатрат становится сравнимо с переписыванием с нуля на любой другой фреймворк. А различия в синтаксисе это не самая большая проблема.


  1. HOMPAIN
    12.05.2025 06:34

    Слишком много одинаковых UI для C#. Непонятно что выбрать и все проекты сырые с кучей багов.


  1. Siemargl
    12.05.2025 06:34

    Что с производительностью визуала?


    1. JacobL Автор
      12.05.2025 06:34

      Зависит от интерфейса. Можно сверстать интерфейс, который будет медленно работать. В этом плане приложение календарь из статьи — хороший пример. Там много ячеек, которые надо отрисовать. Можете попробовать на разных платформах!


  1. IL_Agent
    12.05.2025 06:34

    Было бы здорово увидеть статью, в которой проводится сравнение актуальных кроссплатформенных xaml фреймворков