dotnet / dotnet/wpf

Application.Resources assignments do not trigger InitializeComponent() method to be code generated

Open
#7,702 0 comments 1 reaction 0 assignees View on GitHub
Investigate
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

### Description

When resources are assigned to `Application.Resources` for an Application definition XAML file, this alone does not cause the code generator to generate an `InitializeComponent()` method, which results in these resource never being loaded by an `Application.LoadComponent()` call . If the `InitializeComponent()` method is generated due to other pieces of XAML code, the `Application.LoadComponent()` call is added to `InitializeComponent()` as expected, but in scenarios where the `Application.LoadComponent()` would be the only thing within the `InitializeComponent()` method, the method is omitted entirely.

### Reproduction Steps

Create a new project from the "WPF Application" template, and find the "App.xaml" file, and modify it to include a resource definition, and remove the `StartupUri` assignment, as follows:

```xml



```

### Expected behavior

The code required to load the resource defined in the "App.xaml" file should be included in the "App.g.i.cs" file generated from "App.xaml", as follows:

```cs
#pragma checksum "..\..\..\App.xaml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "E17BFDDF1F61F1827E1EC88A436BDD15F0EECF2C"
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Controls.Ribbon;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
using WpfTest;

namespace WpfTest {


///
/// App
///
public partial class App : System.Windows.Application {

private bool _contentLoaded;

///
/// InitializeComponent
///
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.4.0")]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;

#line default
#line hidden
System.Uri resourceLocater = new System.Uri("/WpfTest;component/app.xaml", System.UriKind.Relative);

#line 1 "..\..\..\App.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);

#line default
#line hidden
}

///
/// Application Entry Point.
///
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.4.0")]
public static void Main() {
WpfTest.App app = new WpfTest.App();
app.InitializeComponent();
app.Run();
}
}
}
```

### Actual behavior

The "App.g.i.cs" file that actually gets generated does not include the `Application.LoadComponent()` call necessary to load the resource, and even omits the `InitializeComponent()` method entirely.

```cs
#pragma checksum "..\..\..\App.xaml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "02DBBD13FE26481FB35ED11F73BD07378D520AF0"
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Controls.Ribbon;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
using WpfTest;

namespace WpfTest {


///
/// App
///
public partial class App : System.Windows.Application {

///
/// Application Entry Point.
///
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.4.0")]
public static void Main() {
WpfTest.App app = new WpfTest.App();
app.Run();
}
}
}
```

### Regression?

Unsure if this is a regression from .NET Framework.

### Known Workarounds

I was unable to work around this issue by manually adding an `Application.LoadComponent()` call to the `App` class constructor, in `App.xaml.cs`. The only workaround I was able to achieve was by adding a dummy attribute assignment to "App.xaml", to replace the `StartupUri` assignment, thus triggering the `InitializeComponent()` method to generate normally, for example `ShutdownMode="OnLastWindowClose"`.

### Impact

Minimal impact. This is likely an uncommon scenario, and the workaround is trivial, if a bit smelly.

### Configuration

SDK Version: 7.0.202

### Other information

At a glance, it looks like there is a flaw in the logical calculation of [`MarkupCompiler.IsBamlNeeded`](https://github.com/dotnet/wpf/blob/341c0fb1b6a55b397f4ad29aaa8cd66e8f3e5196/src/Microsoft.DotNet.Wpf/src/PresentationBuildTasks/MS/Internal/MarkupCompiler/MarkupCompiler.cs#L3069), which is used to trigger the generation of the `InitializeComponent()` method, or not, within the `PresentationBuildTasks` assembly.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.