dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.42k stars 985 forks source link

Resources For Icon/Bitmap Not Strongly Typed In ClassLibrary Project #7525

Open lonitra opened 2 years ago

lonitra commented 2 years ago

.NET version

Version: 6.0.400-preview.22330.6 Commit: da7c9ccceb

.NET SDKs installed: 6.0.400-preview.22330.6 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.0-preview.6.22324.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 6.0.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 6.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 7.0.0-preview.6.22351.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

Not sure, but I don't believe so.

Issue description

In Framework, resource images/icons added get generated as type System.Drawing.Bitmap/System.Drawing.Icon respectively. In core the type is System.Byte[] thus no longer being strongly typed. We need images/icons to be strongly typed in Core as they were in Framework. The following are the .resx and .designer files for framework and core when an image/icon is added.

Framework: .resx

  <data name="Icon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>..\Resources\Icon1.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
  </data>
  <data name="Image1" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>..\Resources\Image1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
  </data>

.designer

 /// <summary>
 ///   Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
 /// </summary>
 internal static System.Drawing.Icon Icon1 {
     get {
            object obj = ResourceManager.GetObject("Icon1", resourceCulture);
            return ((System.Drawing.Icon)(obj));
       }
 }

 /// <summary>
 ///   Looks up a localized resource of type System.Drawing.Bitmap.
 /// </summary>
 internal static System.Drawing.Bitmap Image1 {
     get {
            object obj = ResourceManager.GetObject("Image1", resourceCulture);
             return ((System.Drawing.Bitmap)(obj));
       }
 }

Core: .resx

  <data name="Icon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>Resources\Icon1.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </data>
  <data name="Image1" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>Resources\Image1.bmp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </data>

.designer

 /// <summary>
 ///   Looks up a localized resource of type System.Byte[].
 /// </summary>
 internal static byte[] Icon1 {
     get {
            object obj = ResourceManager.GetObject("Icon1", resourceCulture);
            return ((byte[])(obj));
       }
 }

 /// <summary>
 ///   Looks up a localized resource of type System.Byte[].
 /// </summary>
 internal static byte[] Image1 {
     get {
            object obj = ResourceManager.GetObject("Image1", resourceCulture);
            return ((byte[])(obj));
       }
 }

Background: .resx files in the .csproj file are marked as an EmbeddedResource item type. This is picked up by targets and passed to ResGen.exe where it will convert the .resx file to a .resources file. Additionally, the .resx files in .csproj has a generator attribute attached that runs ResXFileCodeGenerator.cs, which we own, and calls to StronglyTypedResourceBuilder to produce the strongly typed resource file, i.e. resource.designer file.

An initial idea to fix this issue is, in ResXFileRef, track some meta data about the type converter that was utilized to serialize the data so that when we de-serialize it later, we can get the correct type. However, more exploring needs to be done.

After some investigating, this issue does not occurs in a WinForms projects. Some investigation needs to be done as to why this occurs for ClassLibrary projects and possibly other projects.

Steps to reproduce

  1. Create VS ClassLibrary project (one in Framework and one in Core)
  2. Add a resource file to the project and add an icon/image to .resx file
  3. Open .designer file and observe difference in type
elachlan commented 1 year ago

As apart of this, could ResourceManager have a GetIcon/GetBitmap or alternatively Get<T>?

Then the code becomes:

 internal static Icon Icon1 => ResourceManager.Get<Icon>(name(of Icon1), resourceCulture);

 internal static Icon Icon1 => ResourceManager.GetIcon(name(of Icon1), resourceCulture);