Currently, WPF projects for .NET Core 3.0 include explicit items for xaml files. We should include these items implicitly if possible. Though there are a bunch of different item templates (user control, page, window, etc), it looks like they all end up as Page items. So probably we can just include App.xaml as an ApplicationDefinition item, and all other xaml files as Page items.
<Project Sdk="Microsoft.NET.Sdk.Wpf">โ
โ
<PropertyGroup>โ
<OutputType>WinExe</OutputType>โ
<TargetFramework>netcoreapp3.0</TargetFramework>โ
</PropertyGroup>โ
โ
<ItemGroup>โ
<ApplicationDefinition Include="App.xaml" />โ
<Page Include="MainWindow.xaml" />โ
</ItemGroup>โ
โ
<ItemGroup>โ
<FrameworkReference Include="Microsoft.DesktopUI"/>โ
</ItemGroup>โ
โ
</Project>
In WPF SDK .props:
ApplicationDefinition item if it exists on disk, unless EnableDefaultApplicationDefinition is set to falsePage items (unless EnableDefaultPageItems property is set to false)In WPF SDK .targets:
Resource, Content, and None items from the Page items. IE: <Page Remove="@(Resource);@(Content);@(None)" /> (unless EnableDefaultPageItems property is set to false)This would mean that by default, there wouldn't be any Page or ApplicationDefinition items defined in the project file. If you wanted to use a xaml file as a different item type, you could explicitly include it in the project file, e.g. <Resource Include="MyResource.xaml" />. The WPF SDK .targets would then remove that file from the Page item.
We think that the project system currently would not understand the removal in the .targets file, which would mean that if you changed the build action of a Xaml file from Page to Resource in VS, you'd get something like the following in your project:
<Page Remove="MyResource.xaml" />
<Resource Include="MyResource.xaml" />
Not sure if it's in the scope of this issue, but it would also be nice to have automatic nesting, currently I'm using this (for .NET Framework WPF projects):
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<!-- Maybe Exclude="@(ApplicationDefinition) is more correct. -->
<Page Include="**\*.xaml" Exclude="App.xaml" />
<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
</ItemGroup>
@jp2masa We do expect to have automatic nesting. We expect for it to be handled by Visual Studio instead of having to apply this metadata with MSBuild.
BTW we can only have one ApplicationDefinition item - we enforce it during build. @jp2masa's idea of excluding @(ApplicationDefinition) makes more sense to me BTW.
This is a very good idea, and we are going to have to think about it a bit so we have reasonably good _defaults_ for this. A .xaml file can also be used as a _Resource_, or a _Content_, or a _site of origin_ file. See WPF Application Resource, Content and Data Files. They are going to be predominantly Page files though, but we can't just _assume_ that they will be all Page files.
Assuming we can satisfactorily figure out the non-Page file scenarios, here are some thoughts:
PropertyGroup analogous to EnableDefaultCompileItems - let's call it EnableDefaultPageItems or EnableDefaultXamlItems, that would control the implicit page-include behavior. ApplicationDefinition by the developer. Since this is a singleton, they should just be able to supply an override to it via an ItemGroup value. If an ApplicationDefinition is already set, then you know that there is no need to guess that App.xaml* is probably the rightApplicationDefinition* - just proceed without trying to intelligently supply the value for `ApplicationDefinition. cc @rladuca, @sambent
I was wondering if it would be feasible to allow the ApplicationDefinition to be in @(Page) and have the tasks/targets locate it via its <Application>...</Application> content.
Likewise for the other items, but it seems some of the others can be arbitrary xaml.
@nguerrera, I suspect that detecting ApplicationDefinition would be prone to errors. I can't think of any other reason why _PresentationBuildTasks.dll_ doesn't attempt to do this already during markup compilation. The XAML in a typical _App.xaml_ can vary a lot, it can contain boilerplate content that is added by third party libraries (for e.g., MVVM libraries can do this), and the _App.xaml.cs_ file can also change in form and content quite a bit from the default one generated by Visual Studio.
@vatsan-madhavan Can any of the xaml files besides the ApplicationDefinition have Application as the root element?
A XAML file that is marked as ApplicationDefinition doesn't appear in the resources of the executable as far as I know. Allowing it to be included as a Page would mean we'd have to do extra work to exclude that file from being processed into BAML and put into the resources.
@dsplaisted You can have Application in the XAML and include that additional file as a Page even though it's not the real ApplicationDefinition file.
@dsplaisted Actually, I think I am wrong about that, I am getting multiple definitions in a test project.
It's not enough to check for <Application>, you'll have to check for types that might have been derived from System.Windows.Application, for example. I have an application that runs fine with an app definition in Mickey.xaml (and Mickey.xaml.cs) that looks like this:
<local:Mickey
x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
StartupUri="MainWindow.xaml">
<local:Mickey.Resources>
</local:Mickey.Resources>
</local:Mickey>
I can do this because Mickey is an Application :-)
I worry that trying to eliminate ApplicationDefinition as an msbuild targets or task magic might cause us to miss an important corner-case somewhere. The right place where this optimization should be happen is _PresentationBuildTasks_. We can look into it again as a future work item, and perhaps then, we will be able to eliminate the need for a separate ApplicationDefinition. For now, I think we should just keep it.
The right place where this optimization should be happen is PresentationBuildTasks
This is what I was asking about. I think I wasn't clear. I was wondering if PresentationBuildTasks could be changed to take all of the xaml in one item set, and not proposing that we write some other new tasks/targets that sniff xaml content.
I was wondering if PresentationBuildTasks could be changed to take all of the xaml in one item set'
We should be able to investigate this anew, but this is proably not in scope for 3.0.
Some additional background FYI.
Today, we depend on the PBT (PresentationBuildTasks.dll) that is installed as part of .NET Framework, and servicing it with a feature update or a new Task is almost out of question. Even if we got permission to update it, the turnaroung time for releasing an update to it would be many months. As things stand, changing PBT that is currently in use is a non-starter.
We are porting PBT to .NET Core, and are in the process of creating a separate version. This would allow us to separate our builds away from the version that is installed as part of the .NET Framework. The porting of PBT to .NET Core is proving to be somewhat time-intensive, given the extensive differences in reflection capabilities between .NET Framework and .NET Core. We have made significant headway on this project already though. Once we have a working PBT for .NET core, we also need a new version of PBT that can be used for .NET Framework based toolchains (Visual Studio builds, for e.g.) that build .NET Core based WPF projects. This should not be too difficult, but it is still work that needs to be done yet.
All of these are prerequisites for even considering anything like adding additional intelligence in PBT to auto-detect ApplicationDefinition (or any other fundamental enhancements).
Once we have switched over successfully to a new PBT stack that is built entirely out of the .NET Core codebase for both (netcore and .NET Framework) toolchains, we can look into additional capabilities like this. I expect that stabilizing the new versions of PBT will take up most of our focus during 3.0, and we'll be able to look into enhancements during 3.1 timeframe.
I've updated the issue description to include a proposal. Basically we would use App.xaml as the ApplicationDefinition if it existed on disk, and we would assume that Xaml files in the project folder should be Page items unless the project file includes them as Resource, Content, or None items.
@davkean See the note in the proposal about what we think the project system behavior would be.
@dsplaisted
We should support a .xaml analogue of EnableDefaultCompileItems - something like EnableDefaultPageItems. When set to false, this would permit the developer to take full control over how the xaml files are incorporated into Page items in a project.
We would also want to enable developers to override the "_App.xaml is where the ApplicationDefinition lives_" presumption by explicitly setting ApplicationDefinition in the project. If this is already set, then the build system should not try to override it further.
Would you mind incorporating these into your proposal?
cc @SamBent, @rladuca
@vatsan-madhavan I've updated the proposal. I've proposed an EnableDefaultApplicationDefinition property to opt out of the default ApplicationDefinition item. It would be possible to only include the default item if another ApplicationDefinition is not defined in the project, but there are trade-offs. For example, it would be harder to apply metadata to the default item.
This is now part of the latest build of the .NET Core SDK.