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

.Net Core 3.0 WPF Resource doesn't work in project #2258

Closed
getandplay opened this issue Nov 28, 2019 · 10 comments

Comments

@getandplay
Copy link

@getandplay getandplay commented Nov 28, 2019

  • .NET Core Version: (e.g. 3.0 Preview1, or daily build number, use dotnet --info)

    .Net Core 3.0 netcoreapp3.0

  • Windows version: (winver)

    win10

  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes/No

    The bug can reproduce in WPF .Net Core but it works fine in .NET Framework 4.7

  • Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc...)? If yes, please file the issue via the instructions here.

No, I think it is .Net Core Bug

Problem description:

In my solution there are three projects all base on .Net Core 3.0.
- WpfApp1(exe project)
- WpfLibrary1
- Wpf.app.test
And I add an image as Resource in Wps.app.test (I have set the image's build action to Resource), then in WpfLibrary1 I add a ResourceDictionary ,

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <BitmapImage x:Key="Hello" UriSource="pack://application:,,,/Wpf.app.test;component/calendar.png"/>
    
</ResourceDictionary>

In WpfApp1 I use this BitmapImage in my xaml

 <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/WpfLibrary1;component/Test/Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <!--It works Fine-->
        <!--It will throw Exception, but .Net FrameWork works fine-->
        <Image Width="200" Height="200" Source="{StaticResource Hello}" HorizontalAlignment="Right"/>
    </Grid>

when I run WpfApp1 I got an error:
image
And we decompile the Wpf.app.test.dll found that there is no Image in the Dll. ( I have set image's build action to Resource )
The Wpf.app.test.project code

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <None Remove="calendar.png" />
  </ItemGroup>

  <ItemGroup>
    <Resource Include="calendar.png" />
  </ItemGroup>

</Project>

The Decompile result:
image

Actual behavior:

Throw an exception: System.Windows.Markup.XamlParseException: ''Initialization of 'System.Windows.Media.Imaging.BitmapImage' threw an exception.' Line number '4' and line position '32'.'
Inner Exception
IOException: Cannot locate resource 'calendar.png'.

Expected behaviour:

No Error, No exception

Minimal repro:
Here is the demo for this bug
WpfApp1.zip

@weltkante

This comment has been minimized.

Copy link

@weltkante weltkante commented Nov 28, 2019

You need to add <UseWPF>true</UseWPF> in the PropertyGroup to make it a WPF project and support <Resource> tags.

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 28, 2019

<Project Sdk="Microsoft.NET.Sdk"

In addition to UseWPF, you have to use an altogether different SDK - Microsoft.NET.Sdk.WindowsDesktop.

You are not building a WPF or WinForms application yet - what you are building is just a .NET Core library with a name like WpfApp.

Microsoft.NET.Sdk.WindowsDesktop is where WPF and WinForms functionality lives. In order to get WPF specific functionality from this SDK, one must set <UseWpf>true</UseWpf> as @weltkante has rightly observed.

You can type dotnet new wpf to create a new WPF project in the commandline to see what a basic WPF project should look like.

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 28, 2019

We have tried to help users who get into these sorts of situations by showing warnings.
If someone were to try setting <UseWpf>true</UseWpf> or <UseWindowsForms>true</UseWindowsForms> in a Microsoft.NET.Sdk project today, it will offer a friendly warning and suggest that the developer ought to switch over to the WindowsDesktop SDK (so my additional comment at #2258 (comment) was nice to add, but the SDK would have offered the same hint anyway).

I wonder if it might be worthwhile to look for common WPF items like Page, ApplicationDefinition , SplashScreen and Resource in a Microsoft.NET.Sdk project, and add warnings similar to what we added in https://github.com/dotnet/sdk/pull/3315/files#diff-9c308b83aa992e66e6b5a0e0d935d471. @nguerrera , @dsplaisted, @rladuca thoughts?

@walterlv

This comment has been minimized.

Copy link
Contributor

@walterlv walterlv commented Nov 29, 2019

@weltkante @vatsan-madhavan After adding the <UseWpf>True</UseWpf> into the test project, the error disappears. But how can we explain that there is no exception running in net48?


We can add both net48 and netcoreapp3.0 into all the project csproj files and then we can choose which TargetFramework to run. But if we run in net48, no Exception occurs but in netcoreapp3.0, there will be an IOException. Only compiling in netcoreapp3.0 the Resource is not build into the assembly.

image

image

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 29, 2019

The attached repro "works" when building for net48 (or any .NET Framework target) due to a bug - it's not supposed to work (I'll explain the bug in detail further down).

In fact, having a .NET Framework TargetFramework is not sufficient, MSBuildRuntimeType==Full must also be satisfied (which occurs when the project is built using Visual Studio or MSBuild).

If we attempt to build the project using dotnet (where MSBuildRuntimeType==core), you will not encounter the bug that is observable when TargetFramework==net48 (which, ironically, implies that the project will "work"; OTOH when the bug is not present, the project will fail with an exception)

The "bug" is this: In SDK style projects, we didn't intend for WPF specific functionality to be present unless Microsoft.NET.Sdk.WindowsDesktop SDK is used. Contrary to this intention, when MSBuild/Visual Studio is used for builds, .NET Framework's copy of WinFX.targets gets imported by default irrespective of the SDK being used. This happens even for Microsoft.NET.Sdk projects.

image

In the attached project, Wpf.app.test.csproj is a Microsoft.NET.Sdk project with a Resource item that includes calendar.png. Normally, we'd expect this item to be ignored (since Microsoft.NET.Sdk doesnn't include Microsoft.WinFX.targets where targets related to Resource processing normally reside). Due to this bug, .NET Frameworks's copy of WinFX.targets comes into play, and FileClassification and MainResourcesGeneration targets come into play - which embeds the image into the DLL (wpf.app.test.dll).

This bug doesn't present itself when building .NET Core TargetFrameworks, and so when building netcoreapp3.0 the corresponding wpf.app.test.dll doesn't have an embedded calendar.png in it (thus an exception is encountered eventually).

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 29, 2019

@nguerrera, @dsplaisted can we do something to prevent inclusion of .NET Framework's WinFX.targets from sdk.targets? For e.g., set some property in sdk.targets, and conditionally leave out importing of $(MSBuildFrameworkToolsPath)\Microsoft.WinFx.targets in $(MSBuildToolsPath)\Microsoft.WinFX.targets ?

@getandplay

This comment has been minimized.

Copy link
Author

@getandplay getandplay commented Nov 29, 2019

I have just reset the project with and Microsoft.NET.Sdk.WindowsDesktop ,it works fine. So, is there a way to share the resource between WPF .Net Core and Asp .Net Core?

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 29, 2019

So, is there a way to share the resource between WPF .Net Core and Asp .Net Core?

Can you elaborate a bit?

@getandplay

This comment has been minimized.

Copy link
Author

@getandplay getandplay commented Nov 29, 2019

Oh, sure. Like I have two projects, one is WPF .Net Core and the other is WindowsForm .Net Core ( or ASP .Net Core ). An image is needed by both projects. So I want to add a project which is based on .Net Core to manage this image. But how I can make this works for both projects?

@vatsan-madhavan

This comment has been minimized.

Copy link
Member

@vatsan-madhavan vatsan-madhavan commented Nov 29, 2019

<Resource> is a WPF speciifc concept - it compiles the image into the DLL in a very specific way that's unique to how WPF accesses resources. See https://docs.microsoft.com/en-us/dotnet/framework/wpf/app-development/wpf-application-resource-content-and-data-files for a detailed discussion. In general, you can access these resources using Uri's. Also see https://wpf.2000things.com/2014/07/03/1107-accessing-an-embedded-resource-using-a-uri/.

If you want to use image resources a bit more generally, you might want to investigate EmbeddedResource (https://docs.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items?view=vs-2019).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.