Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WPF .NET Core 3 (SDK styled) project: Images (.png, .jpg etc) don't get correct Build Action when added to project #4534

Open
vsfeedback opened this issue Feb 4, 2019 · 16 comments
Labels
Feature-XAML Features related to the XAML designer and display and manipulation of XAML files. Parity-Legacy-Feature Missing features from the legacy project system. Triage-Approved Reviewed and prioritized
Milestone

Comments

@vsfeedback
Copy link

When you have a .NET Core 3 WPF project in Visual Studio 2019 and you add a .png or a .jpg file, these files have the Build Action "None". That means if you use the image with an Image element in XAML, the Image won't be displayed at runtime, as it is not available at runtime.

The Build Action should be set to "Resource" when adding such an image. This happens, if you have a WPF project with the old .csproj format.

This problem is directly related to this issue on Github: dotnet/wpf#292

Thanks a lot,
Thomas

This issue has been moved from https://developercommunity.visualstudio.com/content/problem/440436/wpf-net-core-3-sdk-styled-project-images-png-jpg-e.html
VSTS ticketId: 781517

These are the original issue comments:

Thomas Claudius Huber on 30/01/2019, 09:16 PM (4 days ago): Note: This happens with SDK-styled projets. It is not directly related to .NET Core 3. When you create an SDK styled project with WPF that targets .NET Framework 4.7.2, you have the same issue that images added to the project have the Build Action "None" instead of Resource.
These are the original issue solutions:
(no solutions)

@davidwengier
Copy link
Contributor

The WPF flavor currently does this in ModifyBuildAction called by OnAfterAddFilesEx but it fails with the simplified project system here.

@davidwengier davidwengier added Parity-Legacy-Feature Missing features from the legacy project system. Feature-XAML Features related to the XAML designer and display and manipulation of XAML files. labels Feb 4, 2019
@davidwengier davidwengier added this to the 16.1 milestone Feb 4, 2019
@davkean
Copy link
Member

davkean commented Feb 4, 2019

Why is WPF flavor even involved in this?

@Pilchie
Copy link
Member

Pilchie commented Feb 4, 2019

@nguerrera @dsplaisted - should this be handled by globs in the WPF SDK in the new world?

@davkean
Copy link
Member

davkean commented Feb 4, 2019

The concern with this would be that switching globs by opting in "WPF" would be a fairly disruptive and likely breaking change of the project.

@jjmew jjmew added the Triage-Approved Reviewed and prioritized label Mar 5, 2019
@davidwengier davidwengier added this to Winforms/WPF in David Wengier Mar 26, 2019
@davidwengier davidwengier modified the milestones: 16.1, 16.X Apr 2, 2019
@davidwengier
Copy link
Contributor

Discussed this at the CPS meeting and adding a new glob to the WPF SDK, but not removing the items from None, seems like the best solution. @davkean we can discuss offline if you still have concerns.

@dsplaisted
Copy link
Member

I don't think having globs for different item types (ie Resource and None) cover the same files works well. I think Visual Studio ends up doing weird things to your project file.

@tannergooding
Copy link
Member

Right, and some things in VS may break entirely (T4 templates fail to work if both None and Content for example).

@davidwengier
Copy link
Contributor

The idea behind using globs was to keep the project file clean, as distinct from changing the item type automatically which would have no option but to specify each file in the project file.

T4 templates should work after this change in CPS I imagine.

@davidwengier
Copy link
Contributor

I tested this and adding <Resource Include="**\*.xml;... more extensions ...;" /> seems to work fine in general, though CPS is adding an unnecessary <None Remove="..." /> when a file is added, which I will look into.

@davidwengier
Copy link
Contributor

davidwengier commented May 31, 2019

Current proposal is to implement something akin to this in the SDK:

  <ItemGroup Condition="'$(UseWPF)' == 'true' And $(UseWindowsForms) != 'true'">
    <None Exclude="**\*.xml;**\*.xsl;**\*.xslt;**\*.txt;**\*.bmp;**\*.ico;**\*.cur;**\*.gif;**\*.jpeg;**\*.jpe;**\*.jpg;**\*.png;**\*.dib;**\*.tiff;**\*.tif;**\*.inf;**\*.compositefont;**\*.otf;**\*.ttf;**\*.ttc;**\*.tte" />
    <Resource Include="**\*.xml;**\*.xsl;**\*.xslt;**\*.txt;**\*.bmp;**\*.ico;**\*.cur;**\*.gif;**\*.jpeg;**\*.jpe;**\*.jpg;**\*.png;**\*.dib;**\*.tiff;**\*.tif;**\*.inf;**\*.compositefont;**\*.otf;**\*.ttf;**\*.ttc;**\*.tte" />
  </ItemGroup>

@dsplaisted
Copy link
Member

The list of file extensions comes from the legacy WPF flavor. If you add a file with one of these extensions (via an item template or "add existing item"), the WPF flavor would use the Resource item type / Build action.

@dsplaisted
Copy link
Member

  • Fix None so VS doesn't need to add None Remove
  • Explicit includes for each file
  • Conventions (folders) for Resources
    • Explicitly in project file via project templates
    • <Resource Include="Resources\**\*.*" />
    • Compare to Xamarin AndroidResourcePrefix property
    • Consider implicit convention, based on property similar to Xamarin property

@vatsan-madhavan
Copy link
Member

I'm not convinced that <Resource Include=... is a good default. <Content ...> is a common alternative.

In fact <Content might be preferable - it doesn't add a surprise embedded-resource into the assembly.

/cc @rladuca

@dsplaisted
Copy link
Member

My comment above was written while we were discussing this in a meeting, and doesn't really capture what we concluded.

We concluded there's not a good default for a build action / item type to use for image, Xml, and other extensions listed here, because they might be Resource, EmbeddedResource, or Content/None with CopyToOutputFolder, even in a WPF project.

The consensus was that we should fix the experience issues with None items. IE if you set the build action of a file that is in the None glob to Resource, then VS should add an include for the Resource, but shouldn’t also add a <None Remove="foo.png" />.

Once the “None” issue is fixed, it may be fine to have the “resource-type” items listed explicitly in the project file with the appropriate build action / item type. We may also want to use a convention, such as that all files in the “resources” folder are included as resources, and all files in the "content" folder are included as content which is copied to the output folder. These conventions could either be implicit in the SDK, or explicitly part of the new project templates.

@verelpode
Copy link

verelpode commented Dec 28, 2020

"Build Action" = "Resource" is also for non-WPF projects

Sometimes people are surprised to hear that actually "Build Action" = "Resource" is not only for WPF projects!
@davkean wrote:

Why is WPF flavor even involved in this?

I think @davkean made an important point there. This issue is not really about WPF projects. The biggest problem is that if you make ANY .csproj that targets .NET 5 SDK (such as a non-WPF Console or ASP.NET 5 project) then "Build Action" = "Resource" fails to build correctly, whereas it did (and still does) build successfully in projects targeting .NETFW 4.8. (I tested this again today with Visual Studio 16.8.3.)

I use "Build Action" = "Resource" in multiple non-WPF .csproj's of these kinds:

  • Windows Services (as in "services.msc"), therefore a "Console" project in Visual Studio.
  • ASP.NET 5 (again a "Console" project in Visual Studio).
  • Actual console programs.
  • Stuff for MS Azure.

In NETFW 4.8 Console .csproj's, when you use "Build Action" = "Resource", Visual Studio bundles all those resources into a .resources file named like "MyNamespace.g.resources" and stores it in an assembly manifest resource.

.resources files are not only readable in WPF apps. Any app, including Console programs, can use System.Resources.ResourceManager (alternatively System.Resources.ResourceReader) to read these resources at runtime.

System.Resources.ResourceManager and ResourceReader also exist in .NETFW 5.0 in the DLL System.Runtime.dll:

C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0\System.Runtime.dll

Note System.Resources.ResourceManager/ResourceReader aren't located in WPF's PresentationFramework.dll, rather they're in System.Runtime.dll and they work without WPF.

So currently (VS 16.8.3) the situation is, although you can use ResourceManager and ResourceReader in NETFW 5 and NETFW 4.8 Console projects without WPF, the "Build Action" = "Resource" was broken for NET Core / 5. Even if you manually edit the XML inside a SDK/5 .csproj to make it correct, and try to build the .csproj, then the .resources file fails to be produced. Currently it only works correctly in NETFW 4.8 projects.

I would greatly appreciate this feature being restored. Currently I'm trying to update several non-WPF .csproj's to NETFW 5 (from NETFW 4.8) but these programs fail at runtime because the necessary resources are missing because Visual Studio 16.8.3 basically ignores files marked "Build Action" = "Resource" in SDK/5 projects.

Regarding the other option: "Build Action" = "Embedded Resource"

I suggest renaming "Build Action" = "Embedded Resource" to "Assembly Manifest Resource" or "Manifest Resource", because that's what it actually produces. Currently the name "Embedded Resource" is confusing because both of "Build Action" = "Resource" and "Embedded Resource" produce kinds of resources that are embedded in the output .exe or .dll.

Actually all resources in an app are usually embedded in the app -- "embedded" is the general meaning of any resource in an app. So it'd be great if "Embedded Resource" could be renamed to something clear such as "Assembly Manifest Resource" or "Manifest Resource".

Where the resources show up:

"Build Action" Where resource shows up
"Embedded Resource" This actually means "assembly manifest resource". Resources of this kind show up in System.Reflection.Assembly.GetManifestResourceNames and can be read using System.Reflection.Assembly.GetManifestResourceStream.
"Resource" In NETFW 4.8 projects (either Console or WPF), Visual Studio bundles all files marked "Build Action" = "Resource" into a file named like "MyNamespace.g.resources" and stores it in an assembly manifest resource. At runtime, the ".resources" can be read using System.Resources.ResourceManager (alternatively System.Resources.ResourceReader).
"Content" Keeps the file as a standalone file. In the case of WPF apps, "Content" makes a resource/association that refers to the file, without embedding/copying the file into the ".exe". Good for very large files, and optionally-installed files.
".resx" Resources File A ".resx" file with "Build Action" = "Embedded Resource" and "Custom Tool" = "ResXFileCodeGenerator". If the ".resx" file is named for example "Localizations.resx" then it is compiled/built to an assembly manifest resource named like "MyNamespace.Localizations.resources".

Currently "Build Action" = "Embedded Resource" builds correctly in SDK/5 .csproj's, whereas "Build Action" = "Resource" is broken.

A question may be raised:
Can you workaround the problem by changing all files in a .csproj to use "Embedded Resource" instead of "Resource"? No, because "Embedded Resource" (meaning assembly manifest resource) provides less functionality than ".g.resources"/ResourceManager/ResourceReader. For example, manifest resources lack the content type string (such as "image/svg+xml") and culture/localization abilities provided by System.Resources.ResourceManager.

Regarding ".resx" Resources File

RESX is a separate-but-related issue to the issue of the broken "Build Action" = "Resource".

Make a new .csproj targeting NETFW 5, such as a Console project, and use Visual Studio (16.8.3) to open the Project Properties GUI, then click "Resources" on the left, then click "Click here to create a default resources file", and then VS creates a file named "Resources.resx" in a folder named "Properties" in the same folder as the .csproj.

Alternatively, in VS 16.8.3, you can also use the template named "Resources File" to add a new ".resx" file to a .csproj, including a SDK/NETFW/5 .csproj. Visual Studio has a nice GUI/Designer for .resx files. Inside the .resx file is XML.

Although resx does not require WinForms, unfortunately currently the resx Designer/GUI in VS 16.8.3 produces resx files that do contain references to WinForms. For example:

<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="DgmlGraph" type="System.Resources.ResXFileRef, System.Windows.Forms">
	<value>Resources\DgmlGraph.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>

It would be great if sometime the Designer/GUI for .resx could be modernized to be independent of WinForms.

Re location in the output Assembly, if the ".resx" file is named for example "Localizations.resx" then it is compiled/built to an assembly manifest resource named like "MyNamespace.Localizations.resources".

Suggested plan

  1. Restore/unbreak the preexisting ability to use "Build Action" = "Resource" in non-WPF and WPF .csproj's. It should work in SDK/5 projects like how it works in NETFW 4.8 projects, regardless of whether WPF is involved or not. Note System.Resources.ResourceManager/ResourceReader are in System.Runtime.dll not in WPF's PresentationFramework.dll.
  2. Retain the necessary "Build Action" = "Embedded Resource" feature as-is but rename it to eliminate the confusion. I suggest renaming it to either "Assembly Manifest Resource" or "Manifest Resource". See System.Reflection.Assembly.GetManifestResourceNames.
  3. As a totally separate issue, it would be nice if sometime .resx could be updated/modernized. resx does not require WinForms, but currently the Designer/GUI for it is creating resx files that do contain references to "System.Windows.Forms.dll", although resx could also be used outside of WinForms. Ideally the resx Designer/GUI should only produce WinForms references when it is for a project targeting WinForms, not when it is used in a SDK/NETFW/5 project or a Console project.
  4. Regardless of whether resx is ever updated, the separate issue of "Build Action" = "Resource" needs to be fixed to restore the same behavior as in NETFW 4.8 projects.

@dsplaisted
Copy link
Member

@verelpode It sounds like your main issue is that setting Build Action to Resource doesn't work in non-WPF SDK-style projects. I would suggest filing a new issue about that in the dotnet/sdk repo. This issue is about what the default build action should be, either when a new file is added via VS, or if a file isn't specified explicitly in the project but is in the project folder.

Thanks.

Captain456 added a commit to Captain456/MyFirstRPG that referenced this issue Feb 21, 2021
@drewnoakes drewnoakes modified the milestones: 16.x, 17.x Oct 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature-XAML Features related to the XAML designer and display and manipulation of XAML files. Parity-Legacy-Feature Missing features from the legacy project system. Triage-Approved Reviewed and prioritized
Projects
No open projects
David Wengier
  
Blocked / Waiting
Development

No branches or pull requests

10 participants