В мире кроссплатформенной разработки WPF (Windows Presentation Foundation) долгое время оставался эксклюзивной технологией Microsoft, доступной только на Windows. Однако с развитием контейнеризации и инструментов совместимости, таких как Wine, появляется возможность запускать WPF-приложения в изолированных средах Linux. Эта статья рассказывает о моем опыте запуска WPF-приложений внутри Docker-контейнеров с использованием Wine — решения.

Важное предупреждение: WPF официально не поддерживается на Linux. Данное решение является экспериментальным и рекомендуется в первую очередь для тестирования, образовательных целей или специфических сценариев. Простые приложения могут работать, но сложные интерфейсы со сложной графикой, скорее всего, столкнутся с ограничениями.

Предыстория: Путь к решению

Почему вообще стоит задумываться о запуске WPF в Docker, когда существуют современные кроссплатформенные фреймворки вроде Avalonia? Честно не знаю, но вы же читаете эту статью? Значит вам оно нужно, мне оно тоже было нужно в качестве дополнительного задания, которое мне выдали в моем техникуме по дисциплине Docker. И мне было принципиально сделать его.

Просто написав запрос в поисковик: "Как запустить WPF в Docker" я столкнулся с тем, что многие источники категорично утверждали: «You cannot run a WPF application in docker». StackOverflow пестрел ответами о невозможности такой задачи, YouTube-ролики не предлагали рабочих решений, а попытки поиска на разных языках не приносили результата.

Алиса говорит, что не возможно.
Алиса говорит, что не возможно.
Stackoverflow считает так же.
Stackoverflow считает так же.

В своих поисках я наткнулся на образ dockur/windows, но требования к KVM и огромный размер образа делали это решение непрактичным. Прорыв произошел благодаря образу docker-wine от Scotty Hardy. После многочисленных попыток, перезапусков контейнеров и анализа ошибок удалось добиться работоспособности как для .NET Framework (версии 4.7.2 и 4.8), так и для .NET Core.

Требования к системе

Для воспроизведения этого эксперимента вам понадобится:

  • Docker Desktop — демон Docker для управления контейнерами

  • X-сервер (например, Xming) — для отображения графического интерфейса приложения

  • Скомпилированное WPF-приложение с исполняемым .exe файлом

  • Dotnet - установленный dotnet на хост машине нужной версии (той же что и ваше приложение). Этот пункт нужен только если вы запускаете .NET Core.

Подготовка к запуску

  1. Убедитесь, что ваше WPF-приложение скомпилировано и содержит исполняемый файл (например, WpfApp.exe)

  2. Можете перейти в мой репозиторий на GitHub, чтобы взять оттуда тестовые WPF приложения на Core и Framework.

  3. Разместите ваше приложение в корневой директории проекта рядом с Dockerfile

  4. Запустите Docker Desktop и X-сервер (Xming)

Сборка и запуск Docker-образа

В зависимости от типа вашего приложения (.NET Framework или .NET Core) используйте соответствующие инструкции.

Для .NET Framework приложений

Начнем с .NET Framework'а, так как он проще. Я смог запустить двумя разными способами через образ scottyhardy/docker-wine и через Alpine.

Начнем с образа scottyhardy/docker-wine. Скачать Dockerfile и тестовое приложение Biorhythms можно в репозитории.

FROM scottyhardy/docker-wine

# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0

# Копируем скомпилированное WPF-приложение из локальной директории в корень контейнера
#! Мое приложение - NET Framework 4.8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /Biorhythms/bin/Debug/Biorhythms.exe .

# Запускаем приложение через Wine при старте контейнера
CMD ["wine", "Biorhythms.exe"]   

После этого можно сбилдить контейнер.

docker build -f Dockerfile.docker-wine -t wpf-app .

После этого через настроенный X-сервер, появится окно с Wine. Просто подождем.

Wine обновляет свою конфигурацию.
Wine обновляет свою конфигурацию.

После ожидани�� окно закроется и откроется новое, уже с нашим WPF приложением.

Запущенное WPF приложение.
Запущенное WPF приложение.

Рассмотрим второй способ через Alpine. Преимущество этого способа перед первым, в том, что он меньше по размеру. Скачать Dockerfile и тестовое приложение Biorhythms можно все так же в репозитории.

# Используем образ ориентированный на легковесность и нетребовательность к ресурсам
FROM alpine:latest

# Устанавливаем Wine
RUN apk add --no-cache wine

# Копируем скомпилированное WPF-приложение из локальной директории в папку /app
#! Мое приложение - NET Framework 4.8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /Biorhythms/bin/Debug/Biorhythms.exe ./app/Biorhythms.exe

# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0

CMD ["wine", "/app/Biorhythms.exe"]

После этого можно сбилдить контейнер.

docker build -f Dockerfile.alpine -t wpf-app .

После запуска видим то же окно с Wine, которое обновляет конфигурацию. Отличие в том, что в данном образе по умолчанию не установлен Wine Mono, который нужен для запуска WPF. Следовательно соглашаемся на просьбу его установить и нажимаем кнопку Install.

Установка Wine Mono.
Установка Wine Mono.

Дожидаемся установки.

Загрузка...
Загрузка...

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

Проверка программы.
Проверка программы.

Программа работает, можно идти дальше.

Перейдем к .NET Core, его запустить сложнее, потому что нам понадобится dotnet, при установке dotnet внутри контейнера в Linux скачивается версия именно для Linux, а нам нужна версия для Windows, поэтому мы будем копировать dotnet с хост машины, в контейнер в wine.

Скачать Dockerfile и тестовое приложение WPFCore можно в репозитории.

FROM alpine:latest

# Устанавливаем Wine
RUN apk add --no-cache wine

# Копируем скомпилированное WPF-приложение из локальной директории в папку /app
#! Мое приложение - NET Core 8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /WPFCore/bin/Debug/net8.0-windows ./app/

# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0

Перейдем к запуску, тут он сложнее, чем в .NET Framework'е.

# Сначала сбилдим проект
docker build -f Dockerfile.alpine-core -t core-alpine .

# Запускаем контейнер в интерактивном режиме
docker run -it --rm --name core-alpine-container core-alpine /bin/sh

# Внутри контейнера инициализируем Wine в sh, который открылся у вас в терминале
winecfg

После этого запустится знакомое окно с установкой Wine Mono. Просто устанавливаем.

Установка Mono.
Установка Mono.

Откроем отдельный терминал и скопируем dotnet с хоста в контейнер.

#! Моя версия dotnet на хост машине - NET Core 8
docker cp "C:\Program Files\dotnet" core-alpine-container:"/root/.wine/drive_c/Program Files/dotnet"

Откроется окно с Wine configuration, просто жмем OK и идем дальше.

Конфигурация Wine.
Конфигурация Wine.

Теперь ожидаем, когда появится надпись, что наш dotnet был успешно скопирован в контейнер.

Копирование dotnet'а.
Копирование dotnet'а.

Возвращаемся в терминал с контейнером и в sh запускаем следующую команду:

wine /app/WPFCore.exe

После этого у вас должен запустится WPF на .NET Core.

WPF на .NET Core.
WPF на .NET Core.

Особенности и ограничения

При работе с WPF в Wine через Docker следует учитывать следующие особенности:

  • Графический интерфейс может отображаться с задержками или некорректно

  • Ввод с клавиатуры и мыши может быть нестабильным. Рекомендуется использовать клавиши Tab и Enter для навигации по элементам интерфейса

  • Ограниченная поддержка функци�� — Wine не реализует все возможности WPF. Приложения с:

    • Сложной анимацией

    • Тяжелой 2D/3D графикой

    • Сторонними UI-библиотеками

    • Специфическими Windows API

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

Советы по отладке

Если ваше приложение не запускается или работает некорректно:

  • Используйте winetricks для установки дополнительных компонентов Windows, которые могут потребоваться вашему приложению

  • Проверяйте логи Wine для выявления отсутствующих DLL или COM-компонентов

  • Начинайте с простейшего WPF-приложения (одно окно с кнопкой) и постепенно усложняйте

  • Для .NET Core убедитесь, что версия .NET на хосте точно совпадает с требуемой версией приложения

Альтернативные решения

Хотя эксперимент с Wine и Docker может быть интересен с технической точки зрения, для реальных проектов рекомендуется рассмотреть современные кроссплатформенные альтернативы:

  • Avalonia UI — мощный фреймворк для создания .NET-приложений с нативным интерфейсом на Windows, Linux и macOS

  • .NET MAUI — официальное решение Microsoft для кроссплатформенной разработки мобильных и десктоп-приложений

Заключение

Как показала практика запуск WPF-приложений в Docker возможен, в этом нам помог Wine. Я же доволен, что смог противостоять фразам "это не возможно" и все же запустить в контейнере приложение. Однако не для учебных целей, кроме отдельных случаев такой подход вряд ли подойдет из-за множества ограничений и нестабильности.

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

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


  1. crackedmind
    10.12.2025 08:01

    #? Cкопируем наш dotnet с хост машины в контейнер диска C созданный wine при winecfg
    #! Моя версия dotnet на хост машине - NET Core 8
    # docker cp "C:\Program Files\dotnet" core-alpine-container:"/root/.wine/drive_c/Program Files/dotnet"
    #? После чего запускаем приложение через wine, которое подтянет NET Core, который мы переместили в Program Files
    # wine /app/WPFCore.exe

    для таких целей проще сделать self-contained publish, тогда в папке с приложением будет лежат копия дотнета.


  1. eeeeeeeeeeee
    10.12.2025 08:01

    Очень хотелось бы прочитать историю, как всё к этому пришло )

    И если уже речь пошла о "нестандартных решениях", не пробовали запускать .NET MAUI на Linux? (вроде как без вайна его даже запускают)