Перенос классического приложения Windows Forms в .NET 5

В этой статье описывается, как перенести классическое приложение Windows Forms из .NET Framework в .NET 5 или более поздней версии. В пакет SDK для .NET включена поддержка приложений Windows Forms. Windows Forms — это платформа, которая по-прежнему поддерживается и функционирует только в ОС Windows.

Для переноса приложения из .NET Framework в .NET 5, как правило, требуется создать новый файл проекта. В .NET 5 используются файлы проектов в стиле пакета SDK, а в .NET Framework обычно используется более старый формат файлов проектов Visual Studio. Если вы когда-либо открывали файл проекта Visual Studio в текстовом редакторе, вы знаете, насколько он подробный. Проекты в стиле пакета SDK меньше по размеру, и для них не требуется такое количество записей, как в файлах проектов старого формата.

Дополнительные сведения о .NET 5 см. в статье Введение в .NET.

Пробное использование помощника по обновлению

Помощник по обновлению .NET — это средство командной строки, которое можно запускать для различных приложений платформы .NET Framework. Это средство поможет вам в обновлении приложений .NET Framework до .NET 5. После запуска средства в большинстве случаев для завершения миграции приложения потребуются дополнительные действия. Средство включает установку анализаторов, которые могут помочь в завершении миграции.

Дополнительные сведения см. в статье Обновление приложения WPF до .NET 5 с помощью помощника по обновлению .NET.

Предварительные требования

  • Visual Studio 2019 версии 16.11 или более поздней.

  • Предварительная версия конструктора WinForms в Visual Studio.

    Чтобы включить конструктор, последовательно выберите Сервис>Параметры>Среда>Функции предварительной версии, а затем выберите параметр Use the preview Windows Forms designer for .NET Core apps (Использовать конструктор Windows Forms предварительной версии для приложений .NET Core).

  • В этой статье используется пример приложения Matching game. Если вы хотите в точности выполнять инструкции данной статьи, скачайте и откройте это приложение в Visual Studio. В противном случае используйте собственное приложение.

Consider

При переносе приложения Windows Forms из .NET Framework необходимо учесть ряд аспектов.

  1. Удостоверьтесь, что ваше приложение подходит для переноса.

    Чтобы выяснить, можно ли перенести проект в .NET 5, используйте анализатор переносимости .NET. Если у проекта есть проблемы с .NET 5, анализатор поможет их обнаружить. Анализатор переносимости .NET можно установить как расширение Visual Studio или вызвать из командной строки. См. дополнительные сведения об анализаторе переносимости .NET.

  2. Вы используете другую версию Windows Forms.

    После выпуска .NET Core 3.0 открытый код Windows Forms был размещен на GitHub. Код Windows Forms для .NET 5 образует вилку с базой кода Windows Forms для .NET Framework. Возможно, существуют некоторые различия, и ваше приложение будет затруднительно перенести.

  3. Помочь с переносом может пакет обеспечения совместимости Windows.

    Некоторые API, существующие в .NET Framework, недоступны в .NET 5. Пакет обеспечения совместимости Windows добавляет многие из этих API, помогая обеспечить совместимость приложения Windows Forms с .NET 5.

  4. Обновите пакеты NuGet, используемые в проекте.

    Рекомендуется обновить пакеты NuGet до последней версии перед переносом. Если ваше приложение ссылается на пакеты NuGet, обновите их до последней версии. Убедитесь, что сборка приложения выполняется успешно. Если после обновления возникают ошибки пакетов, установите предыдущую версию пакетов, которая не нарушает работу вашего кода.

Резервное копирование проектов

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

Пакеты NuGet

Если проект обращается к пакетам NuGet, возможно, в папке проекта имеется файл packages.config. В проектах в стиле пакета SDK ссылки на пакеты NuGet настраиваются в файле проекта. В проектах Visual Studio пакеты NuGet также могут дополнительно определяться в файле проекта. В .NET 5 файлы packages.config для пакетов NuGet не используются. Перед миграцией необходимо перенести ссылки на пакеты NuGet в файл проекта.

Чтобы перенести файл packages.config, выполните следующие действия.

  1. В обозревателе решений найдите проект, который требуется перенести.
  2. Щелкните правой кнопкой мыши packages.config>Перенести packages.config в PackageReference.
  3. Выберите все пакеты верхнего уровня.

Будет создан отчет о сборке, из которого вы сможете узнать о любых проблемах переноса пакетов NuGet.

Файл проекта

Следующим шагом при переносе приложения является преобразование файла проекта. Как было сказано выше, в .NET 5 используются файлы проектов в стиле пакета SDK и не загружаются файлы проектов Visual Studio, которые используются в .NET Framework. Однако вполне возможно, что вы уже используете проекты в стиле пакета SDK. Вы можете с легкостью выявить разницу в Visual Studio. Щелкните правой кнопкой мыши файл проекта в обозревателе решений и попробуйте найти пункт меню Изменить файл проекта. Если этот пункт меню отсутствует, то вы используете старый формат проекта Visual Studio, и его необходимо обновить.

Преобразуйте каждый проект в вашем решении. Если вы используете упомянутый выше пример приложения, то необходимо преобразовать проекты MatchingGame и MatchingGame.Logic.

Чтобы преобразовать проект, выполните следующие действия.

  1. В обозревателе решений найдите проект, который требуется перенести.

  2. Щелкните проект правой кнопкой мыши и выберите Выгрузить проект.

  3. Щелкните проект правой кнопкой мыши и выберите Изменить файл проекта.

  4. Скопируйте XML-код проекта и вставьте его в текстовый редактор. Копия нужна, чтобы было проще переместить содержимое в новый проект.

  5. Очистите содержимое файла и вставьте следующий XML-код:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0-windows</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
      </PropertyGroup>
    
    </Project>
    

    Важно!

    Для библиотек не требуется определять параметр <OutputType>. Если вы обновляете проект библиотеки, удалите эту запись.

Этот XML-код представляет базовую структуру проекта. Однако в нем нет никаких параметров из старого файла проекта. Используя старые сведения о проекте, скопированные ранее в текстовый редактор, выполните следующие действия.

  1. Скопируйте следующие элементы из старого файла проекта в элемент <PropertyGroup> в новом файле проекта:

    • <RootNamespace>
    • <AssemblyName>

    Теперь XML-код в файле проекта должен выглядеть следующим образом:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0-windows</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    
        <RootNamespace>MatchingGame</RootNamespace>
        <AssemblyName>MatchingGame</AssemblyName>
      </PropertyGroup>
    
    </Project>
    
  2. Скопируйте из старого файла проекта элементы <ItemGroup>, которые содержат <ProjectReference> или <PackageReference>, и вставьте их в новый файл после закрывающего тега </PropertyGroup>.

    Теперь XML-код в файле проекта должен выглядеть следующим образом:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        (contains settings previously described)
      </PropertyGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\MatchingGame.Logic\MatchingGame.Logic.csproj">
          <Project>{36b3e6e2-a9ae-4924-89ae-7f0120ce08bd}</Project>
          <Name>MatchingGame.Logic</Name>
        </ProjectReference>
      </ItemGroup>
      <ItemGroup>
        <PackageReference Include="MetroFramework">
          <Version>1.2.0.3</Version>
        </PackageReference>
      </ItemGroup>
    
    </Project>
    

    В элементах <ProjectReference> не нужны дочерние элементы <Project> и <Name>, поэтому эти параметры можно удалить:

    <ItemGroup>
      <ProjectReference Include="..\MatchingGame.Logic\MatchingGame.Logic.csproj" />
    </ItemGroup>
    

Ресурсы и параметры

Необходимо отметить, что разница между проектами платформы .NET Framework и проектами в стиле SDK, используемыми в .NET 5, заключается в том, что проекты платформы .NET Framework используют модель согласия для файлов кода. Любой файл кода, который нужно скомпилировать, должен быть явным образом определен в файле проекта. В проектах в стиле SDK, напротив, по умолчанию используется поведение отказа: Все файлы кода, начиная с каталога проекта и ниже, автоматически включаются в проект. Эти записи не нужно переносить, если они являются простыми и не содержат параметров. То же относится к другим общим файлам, например, к файлам resx.

Проекты Windows Forms могут также ссылаться на следующие файлы:

  • Properties\Settings.settings
  • Properties\Resources.resx
  • Properties\app.manifest

Ваш проект ссылается на файл app.manifest автоматически, и никаких специальных действий для его миграции не требуется.

Все файлы *.resx и *.settings в папке Properties в проекте должны быть перенесены. Скопируйте эти записи из старого файла проекта в элемент <ItemGroup> в новом проекте. После копирования записей измените все элементы <Compile Include="value">, указав Update вместо Include.

  • Импортируйте конфигурацию для файла Settings.settings.

    <ItemGroup>
      <None Update="Properties\Settings.settings">
        <Generator>SettingsSingleFileGenerator</Generator>
        <LastGenOutput>Settings.Designer.cs</LastGenOutput>
      </None>
      <Compile Update="Properties\Settings.Designer.cs">
        <AutoGen>True</AutoGen>
        <DependentUpon>Settings.settings</DependentUpon>
        <DesignTimeSharedInput>True</DesignTimeSharedInput>
      </Compile>
    </ItemGroup>
    

    Важно!

    В проектах Visual Basic файл параметров проекта обычно по умолчанию находится в папке My Project, а в проектах C# — в папке Properties.

  • Импортируйте конфигурацию для любого RESX-файла, например для properties\Resources.resx. Обратите внимание, что для атрибута Include было задано значение Update в <Compile> и элементе <EmbeddedResource>, а <SubType> был удален из <EmbeddedResource>:

    <ItemGroup>
      <EmbeddedResource Update="Properties\Resources.resx">
        <Generator>ResXFileCodeGenerator</Generator>
        <LastGenOutput>Resources.Designer.cs</LastGenOutput>
      </EmbeddedResource>
      <Compile Update="Properties\Resources.Designer.cs">
        <AutoGen>True</AutoGen>
        <DependentUpon>Resources.resx</DependentUpon>
        <DesignTime>True</DesignTime>
      </Compile>
    </ItemGroup>
    

    Важно!

    В проектах Visual Basic файл ресурсов проекта обычно по умолчанию находится в папке My Project, а в проектах C# — в папке Properties.

Visual Basic

Для проектов на языке Visual Basic требуется дополнительная настройка.

  1. Импортируйте параметр файла конфигурации My Project\Application.myapp. Обратите внимание, что элемент <Compile> использует атрибут Update вместо атрибута Include.

    <ItemGroup>
      <None Include="My Project\Application.myapp">
        <Generator>MyApplicationCodeGenerator</Generator>
        <LastGenOutput>Application.Designer.vb</LastGenOutput>
      </None>
      <Compile Update="My Project\Application.Designer.vb">
        <AutoGen>True</AutoGen>
        <DependentUpon>Application.myapp</DependentUpon>
        <DesignTime>True</DesignTime>
      </Compile>
    </ItemGroup>
    
  2. Добавьте параметр <MyType>WindowsForms</MyType> в элемент <PropertyGroup>:

    <PropertyGroup>
      (contains settings previously described)
    
      <MyType>WindowsForms</MyType>
    </PropertyGroup>
    

    Этот параметр импортирует элементы пространства имен My, знакомого программистам Visual Basic.

  3. Импортируйте пространства имен, определенные в вашем проекте.

    Проекты Visual Basic могут автоматически импортировать пространства имен в каждый файл кода. Скопируйте из старого файла проекта элементы <ItemGroup>, содержащие <Import>, и вставьте их в новый файл после закрывающего тега </PropertyGroup>.

    <ItemGroup>
      <Import Include="Microsoft.VisualBasic" />
      <Import Include="System" />
      <Import Include="System.Collections" />
      <Import Include="System.Collections.Generic" />
      <Import Include="System.Data" />
      <Import Include="System.Drawing" />
      <Import Include="System.Diagnostics" />
      <Import Include="System.Windows.Forms" />
      <Import Include="System.Linq" />
      <Import Include="System.Xml.Linq" />
      <Import Include="System.Threading.Tasks" />
    </ItemGroup>
    

    Если вы не можете найти никакие инструкции <Import>, или не удается скомпилировать проект, проверьте, определены ли в проекте следующие инструкции <Import>:

    <ItemGroup>
      <Import Include="System.Data" />
      <Import Include="System.Drawing" />
      <Import Include="System.Windows.Forms" />
    </ItemGroup>
    
  4. Скопируйте параметры <Option*> и <StartupObject> из исходного проекта в элемент <PropertyGroup>:

    <PropertyGroup>
      (contains settings previously described)
    
      <OptionExplicit>On</OptionExplicit>
      <OptionCompare>Binary</OptionCompare>
      <OptionStrict>Off</OptionStrict>
      <OptionInfer>On</OptionInfer>
      <StartupObject>MatchingGame.My.MyApplication</StartupObject>
    </PropertyGroup>
    

Перезагрузка проекта

После преобразования проекта в новый формат в стиле пакета SDK перезагрузите проект в Visual Studio, выполнив следующие действия.

  1. В обозревателе решений найдите преобразованный вами проект.

  2. Щелкните проект правой кнопкой мыши и выберите Перезагрузить проект.

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

Изменение файла App.config

Если в вашем приложении имеется файл App.config, удалите элемент <supportedRuntime>:

<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

При работе с файлом App.config необходимо учитывать некоторые аспекты. Файл App.config в .NET Framework использовался не только для настройки приложения, но и для настройки параметров и режима функционирования среды выполнения, например, для включения ведения журнала. В .NET 5+ (и .NET Core) файл App.config больше не используется для конфигурации среды выполнения. Если ваш файл App.config содержит эти разделы, они не будут учитываться.

Добавление пакета совместимости

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

  • Не удалось найти тип или пространство имен <имя объекта>
  • Имя <имя объекта> не существует в текущем контексте

Может потребоваться добавить в ваше приложение пакет Microsoft.Windows.Compatibility. Этот пакет добавляет около 21 000 API из .NET Framework, например, класс System.Configuration.ConfigurationManager и интерфейсы API для взаимодействия с реестром Windows. Добавьте пакет Microsoft.Windows.Compatibility.

Измените файл проекта, добавив в него следующий элемент <ItemGroup>:

<ItemGroup>
  <PackageReference Include="Microsoft.Windows.Compatibility" Version="5.0.0" />
</ItemGroup>

Тестирование приложения

После завершения переноса приложения протестируйте его!

Дальнейшие действия