-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Summary
When using a custom class that derives from Application as the root element in App.xaml, the XAML compiler generates a lowercase resource URI (app.xaml) instead of preserving the actual file name case (App.xaml). This causes a runtime error because the resource cannot be located.
Environment
- .NET Version: 10.0
- WPF Version: 10.0
- OS: Windows 11
- SDK Style Project: Yes
Steps to Reproduce
- Create a custom class that inherits from
Application:
// CustomStartup.cs
using System.Windows;
namespace ReproApp
{
public class CustomStartup : Application
{
}
}- Create
App.xamlusing the custom class as root element:
<!-- App.xaml -->
<local:CustomStartup
x:Class="ReproApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ReproApp">
<Application.Resources>
</Application.Resources>
</local:CustomStartup>- Create code-behind:
// App.xaml.cs
namespace ReproApp
{
public partial class App : CustomStartup
{
}
}- Build the project - Builds successfully without errors
- Run the application - Runtime error occurs
Expected Behavior
The application should start successfully, with the XAML compiler generating the correct resource URI matching the actual file name: /ReproApp;component/App.xaml
Actual Behavior
Runtime error occurs:
System.IO.IOException: Cannot locate resource 'app.xaml'.
at MS.Internal.AppModel.ResourcePart.GetStreamCore(FileMode mode, FileAccess access)
at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at ReproApp.App.InitializeComponent() in App.xaml:line 1
The generated code in obj/.../App.g.cs contains a lowercase URI:
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/ReproApp;component/app.xaml", System.UriKind.Relative);
// ^^^^^^^^
// lowercase - should be App.xaml!
System.Windows.Application.LoadComponent(this, resourceLocater);
}Key Observations
-
No
App.bamlfile is generated in the obj folder during build- Other XAML files (like
MainWindow.xaml) are correctly compiled to.baml - This suggests the ApplicationDefinition is not being processed correctly
- Other XAML files (like
-
When using
<Application>as the root element (standard approach), everything works correctly -
The issue only occurs when using a custom
Application-derived class as the root element -
The XAML compiler appears to not recognize the custom Application class as a valid ApplicationDefinition
-
The lowercase URI in the generated code doesn't match the actual file name, which could cause issues on case-sensitive file systems
Workaround
Remove App.xaml entirely and manually create the entry point:
public partial class App : CustomStartup
{
[STAThread]
public static void Main()
{
var app = new App();
app.Run();
}
}Root Cause Analysis
The XAML compiler (MarkupCompilePass1 task) seems to have issues when:
- The root element of
App.xamlis not<Application> - A custom class derived from
Applicationis used instead
This results in:
- The
App.bamlresource not being generated - An incorrect lowercase resource URI being generated
- A mismatch between the expected and actual resource location at runtime
Proposed Fix
The XAML compiler should either:
- Properly support custom Application-derived classes as root elements in ApplicationDefinition files, OR
- Provide a clear compile-time error indicating that only
<Application>is supported as the root element in App.xaml
Additional Context
This issue was discovered while working with a framework that uses a custom Startup class derived from Application to provide additional initialization logic. The workaround of removing App.xaml works but is not intuitive and requires manual Main() method creation.
Related WPF build targets: Microsoft.WinFX.targets (MarkupCompilePass1 task)