Closed srivatsn closed 5 years ago
From @tannergooding on February 3, 2017 22:56
FYI. @srivatsn, @jinujoseph, @nguerrera
From @tannergooding on February 3, 2017 22:57
This completely blocks the porting of WPF based applications to CPS (I imagine it would also block UWP and anything else that uses XAML).
Yes WPF and any other desktop projects are not supported yet. Currently only .NET Core projects are supported.
This should work with the right LanguageTargets
, shouldn't it?
For me it works good with VS2017 RC and the class library project (.NET Framework, not .NET Standard). I can include XAML files and everything is properly compiled, Intellisense works, etc.
The only issue I have is when I use globbing - the dependent .xaml.cs
files are not nested. Reported there https://github.com/Microsoft/VSProjectSystem/issues/169
UPD. I also checked default class library project (the template with .NET Standard). After switching target to net461 it works but indeed it treats XAML as None
... and manual setting it to Page
leads to The target "CoreCompile" does not exist in the project
error.
I was able to properly setup XAML files building with CPS for VS2017.
@onovotny was right, with proper targets it works. I've added <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
. Also I added missing XAML rule for Page
. And I've found a workaround for the issue with the dependent .xaml.cs
files for files globbing (see link above).
Ok. I now understand this much better (@srivatsn).
WPF (and some other project types) generate a temporary project file that does not use the same extension as the original (WPF uses .tmp_proj, for example).
The SDK.targets uses the project extension to set LanguageTargets
(provided LanguageTargets
has not already been set). It then imports whatever LanguageTargets
is set to (C# should be setting it to $(MSBuildToolsPath)\Microsoft.CSharp.targets
, for example).
So the workaround is to ensure that LanguageTargets
is set on any project type that hits the above issue.
I would think the proper fix, however, is to get the XAML targets (and any other targets that generate temporary projects) to use the original project extension.
@tannergooding, WPF is using temporary project because it need two-pass building to properly process XAML markup as described in this article on MSDN. So I'm afraid it might not be possible to avoid .tmp_proj
.
@aienabled Keep any bugs you file for managed concepts on this repro.
@aienabled, i wasn't indicating it should avoid .tmp_proj, I'm saying t should usee the original projects file extension when doing so. Meaning instead of .tmp_proj, it should use .tmp_proj.csproj or just .csproj.
@tannergooding can you file that as an internal bug on XAML?
@srivatsn, I have logged VSO Bug: 382095 (not sure if the area path is correct, it seemed to be the best fit though).
XAML needs PresentationBuildTasks, right, so is it correct that making this work in the SDK won't automatically make it work with dotnet build
?
Workaround in RepoToolset (included via Directory.Build.props):
<Choose>
<When Condition="'$(MSBuildProjectExtension)' != '.csproj' and '$(MSBuildProjectExtension)' != '.vbproj'">
<PropertyGroup>
<LanguageTargets Condition="Exists('$(MSBuildProjectDirectory)\$(AssemblyName).csproj')">$(MSBuildToolsPath)\Microsoft.CSharp.targets</LanguageTargets>
<LanguageTargets Condition="Exists('$(MSBuildProjectDirectory)\$(AssemblyName).vbproj')">$(MSBuildToolsPath)\Microsoft.VisualBasic.targets</LanguageTargets>
</PropertyGroup>
</When>
</Choose>
Turns out the XAML build sets the AssemblyName
property to the original value.
Anyone got this working? I'm able to compile it but I lost intellisense in VS 2017.
This is my csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LanguageTargets>$(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets</LanguageTargets>
<OutputType>winexe</OutputType>
<TargetFramework>net462</TargetFramework>
<DebugType>Full</DebugType>
<ApplicationIcon>res\ico\icon.ico</ApplicationIcon>
<OutputTypeEx>winexe</OutputTypeEx>
<StartupObject />
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TransformOnBuild>True</TransformOnBuild>
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
<ItemGroup>
<!-- App.xaml -->
<ApplicationDefinition Include="App.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
<!-- XAML elements -->
<Page Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" Exclude="App.xaml" />
<Compile Update="**\*.xaml.cs" SubType="Designer" DependentUpon="%(Filename)" />
<Compile Include="$(IntermediateOutputPath)**\*.g.cs" Visible="false" />
<None Include="$(ProjectDir)obj" Visible="false" />
<!-- Resources -->
<EmbeddedResource Update="Properties\Resources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Resources.Designer.cs" />
<Compile Update="Properties\Resources.Designer.cs" AutoGen="True" DependentUpon="Resources.resx" DesignTime="True" />
<!-- Settings -->
<None Update="Properties\Settings.settings" Generator="SettingsSingleFileGenerator" LastGenOutput="Settings.Designer.cs" />
<Compile Update="Properties\Settings.Designer.cs" AutoGen="True" DependentUpon="Settings.settings" />
<None Update="App.config">
<TransformOnBuild>true</TransformOnBuild>
</None>
<None Update="App.Debug.config">
<IsTransformFile>True</IsTransformFile>
</None>
<None Update="App.Release.config">
<IsTransformFile>True</IsTransformFile>
</None>
</ItemGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System.Xaml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Publish\**" />
<EmbeddedResource Remove="Publish\**" />
<None Remove="Publish\**" />
<Page Remove="Publish\**" />
</ItemGroup>
<PropertyGroup>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
</PropertyGroup>
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
</Project>
❓ @bdovaz I notice you have Generator="MSBuild:UpdateDesignTimeXaml"
. Is there a reason you aren't using Generator="MSBuild:Compile"
?
Here's one project that I've been working on that uses XAML. I need to look back and see if IntelliSense is working properly.
@sharwell to be honest I don't know, my csproj is being written by seeing other people examples that are trying to achieve the same goal.
Also when I mean intellisense I mean that I can't reference almost anything. Example:
Note: The code that is not recognizing it's in another referenced project.
I really want to use the new format but I need a working example that works. One example that:
I've tried to update my csproj seeing that example but I have the same problem: it compiles but I have no Intellisense.
Any help?
@bdovaz, I'm using it successfully for WPF (multiple projects referencing each other) and IntelliSense works well (in C# and XAML files).
Do you need this for WPF/UWP or Xamarin project?
Are you able to see XAML files in the solution explorer? I'm asking because there is no Page
item type rule in netstandard
and without it XAML files added as Page
are not visible in the solution explorer but you didn't mention about it. To workaround this, I'm using custom targets which add the Page
rule.
I will prepare a small sample.
@aienabled in my case I'm using it with WPF. Thanks I'm also looking forward to that example.
Done https://github.com/aienabled/WpfNetStandardSample but it has a problem with VS IntelliSense for WPF generated code (from intermediate folder) as I've described in the readme there. I hope someone from the Project System team will take a look at that sample and figure out why VS IntelliSense doesn't work properly. Meanwhile, I'm using it with ReSharper without any issues.
@bdovaz I figured out the problem. You need to apply a workaround for #2488, as seen in icsharpcode/ILSpy#847.
@aienabled Your solution includes some workarounds that I haven't done yet. Maybe we can put together a NuGet package that someone can install to "just work"?
@sharwell Please add that to the MSBuild.Sdk.Extras
package as that's the goal of the project. Sounds like a perfect addition.
@sharwell, you can go ahead. Unfortunately, I don't have time now to pack this into a NuGet package and ensure it works properly. UPD. I can confirm the fix for VS IntelliSense works properly. I've updated my repository to include this workaround.
I'm still having problems with this.
I randomly lost intellisense and to get it back it's a combination of making a change on the project (for example: deleting a file) or closing and opening VS 2017 or unloading or loading the project...
It's a nightmare...
Also on stackoverflow someone called RB had the same problem:
@bdominguez Did you apply this workaround as well?
Yes, I already included it.
FWIW, Xamarin Forms targets now have a XAML wildcard that handles nesting:
https://github.com/xamarin/Xamarin.Forms/blob/master/.nuspec/Xamarin.Forms.DefaultItems.props https://github.com/xamarin/Xamarin.Forms/blob/master/.nuspec/Xamarin.Forms.DefaultItems.targets
We been trying a lot of different solutions but we been having issues using the WPF with the CI engine for the first build. Eg we get a lot of errors where it mentioned it can't find the .g.cs files, then subsequent builds it works. It seems like the xaml parsing happens after the build stage or something? Eg we get errors like:
CSC : error CS2001: Source file 'dialogs\newworlddialog.g.cs' could not be found.
80>CSC : error CS2001: Source file 'dialogs\openworlddialog.g.cs' could not be found.
80>CSC : error CS2001: Source file 'editors\worldeditor.g.cs' could not be found.
80>CSC : error CS2001: Source file 'dialogs\assetpickerdialog.g.cs' could not be found.
80>CSC : error CS2001: Source file 'bookmarkpropertiesview.g.cs' could not be found.
The MSBuild.Sdk.Extras supports this now with changes based on @sharwell's work
@onovotny what do we need to do in our csproj files to get it working with WPF projects? Is there any official docs on this? I only want to use new csproj format with WPF projects.
@bdovaz, a few months ago I've made this repository https://github.com/aienabled/WpfNewProjectSystemSample I've just updated it to support latest version of VS2017 and include my latest workarounds. Maybe it will be helpful to you.
@aienabled there's a bit more to it than that, unfortunately. You have to deal with the tmp_proj
2-pass of WPF.
Using MSBuild.Sdk..Extras, I have an example here:
Note the workarounds currently needed at the top/bottom of the csproj.
I'll get some updated docs on the project that show how.
We need an official response on this otherwise we will be really lost...
@bdovaz at this point, I think what I have in my Extras is as good as it gets. Official word is that it's not supported in VS 2017 and it's on the roadmap for the next release: https://github.com/dotnet/project-system/blob/master/docs/repo/roadmap.md
If you don't want to wait, as I don't, then everything is on a best-effort "we'll try to find workarounds" basis.
@bdovaz, the workarounds @onovotny has looks correct.
Any project containing XAML files (with the appropriate ItemGroup
) will undergo a two-pass compilation.
Said two pass compilation ends up creating a
The primary issue with this approach is that anything that relies on the original project name or extension can/will break.
For example, with SDK based projects the different extension prevents the SDK from automatically determining what language your project is targeting and so the Default props/targets are imported rather than the C# props/targets (for example). The workaround for this issue is to set the language targets in your projects: https://github.com/dotnet/project-system/issues/1467#issuecomment-278180128
For both SDK and non-SDK projects, this can interfere with NuGet, which automatically imports props/targets based on the name of the project file. @onovotny has worked around this with <Import Project="obj\*.props" Condition=" '$(MSBuildProjectExtension)' == '.tmp_proj'" />
and <Import Project="obj\*.targets" Condition=" '$(MSBuildProjectExtension)' == '.tmp_proj'" />
.
I believe there has been some investigation into resolving the issues, but they are non-trivial.
The XAML props/targets actually exist as part of the Desktop framework and are therefore part of Windows(C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Xaml.targets
, for example). This makes the barrier to fixing the issue at the source already much higher (it requires updating "core" system files).
It also has a risk of being a breaking change, as anyone dependent on the tmp_proj
being created, or doing something special as part of the tmp_proj
build could potentially break or have different behavior. WPF has been around for over 10 years and is a fairly popular framework, so that is a lot of code that could potentially break.
@tannergooding We've been working on our WPF application for several years and are still creating new ones. We (can't speak for others...) would prefer, by far, a breaking change than not having CPS support. A breaking change we can deal with. We notice it, we learn about it, we apply the changes and we move on. The split between CPS and old style projects has already created issues for us several times as we've also got .net core frontends. Using CPS everywhere would enable us to share more of our build chain and make our build chain/infrastructure simpler, too. Currently we have to duplicate quite some code and that creates continuous friction - much worse than a breaking change.
That said, however, we'd also be fine with CPS WPF support being an opt-in. Let's say you could add a *.targets import to every WPF csproj or something like that.
I'm in exactly the same position - tons of old wpf, tons of new asp.net core, we want interoperability and can accept breaking changes to achieve it, whether they require an opt-in or not.
Same here, If we have that breaking changes documented, there is no problem.
bear in mind that for anyone using wpf clickonce, the last couple of .net framework and visual studio releases have already been massively breaking :)
@sharwell the last bit of that .csproj file in the link you referenced, it will break loading of the Assemblies. Doesn't work! I am using v4.7.1 w/ CPS build configs.
<!--
Work around to fix Intellisense file generation for XAML projects https://github.com/dotnet/project-system/issues/2488
-->
<Target Name="WorkaroundForXAMLIntellisenseBuildIssue" AfterTargets="_CheckCompileDesignTimePrerequisite">
<PropertyGroup>
<BuildingProject>false</BuildingProject>
</PropertyGroup>
</Target>
Reverting to using this instead:
<!-- App.xaml -->
<ApplicationDefinition Include="App.xaml" SubType="Designer" Generator="MSBuild:XamlIntelliSenseFileGenerator" />
<!-- XAML elements -->
<Page Include="**\*.xaml" SubType="Designer" Generator="MSBuild:XamlIntelliSenseFileGenerator" Exclude="App.xaml" />
<Compile Update="**\*.xaml.cs" SubType="Designer" DependentUpon="%(Filename)" />
<Compile Include="$(IntermediateOutputPath)**\*.g.cs" Visible="false" />
<None Include="$(ProjectDir)obj" Visible="false" />
@everyone as for the expected abstract target for CoreCompile
, Adding the target Imports for old conventions do not work for me. It is very problematic and doesn't appear to be correct anyway.
I recommend using a pseudo target to get around it asking for the built-in default target for now.
<Target Name="CoreCompile" />
@Latency Can you be more specific? The code you referenced as broken is currently used in several projects, including Roslyn where I spend the most time. We have observed a few rare edge cases where things don't work right, but generally that appears to be a required inclusion.
@sharwell I managed to get something to work within the past 24 hrs.. but it does not contain that target rule like mentioned in my previous thread. That target breaks my project.
Here is what I have:
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<LanguageTargets Condition="Exists('$(MSBuildProjectDirectory)\$(AssemblyName).csproj')">$(MSBuildToolsPath)\Microsoft.CSharp.targets</LanguageTargets>
<OutputType>WinExe</OutputType>
<TargetFramework>net471</TargetFramework>
<StartupObject>HearthStone.UnInstaller.App</StartupObject>
<PackageId>HearthStone.UnInstaller</PackageId>
<AssemblyName>HearthStone.UnInstaller</AssemblyName>
<RootNamespace>HearthStone.UnInstaller</RootNamespace>
<Version>1.0.0</Version>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System.Xaml" />
<Reference Include="WindowsBase" />
<!-- App.xaml -->
<ApplicationDefinition Include="App.xaml" SubType="Designer" Generator="MSBuild:XamlIntelliSenseFileGenerator" />
<!-- XAML elements -->
<Page Include="**\*.xaml" SubType="Designer" Generator="MSBuild:Compile" Exclude="App.xaml" />
<Compile Update="**\*.xaml.cs" SubType="Designer" DependentUpon="%(Filename)" />
<Compile Update="$(IntermediateOutputPath)**\*.g.cs" Visible="false" />
</ItemGroup>
</Project>
The <LanguageTargets ...>
seems to be a key component to getting this to work, along with using the appropriate referenced assemblies to be included for XAML.
Could you replace your <LanguageTargets ...>
with <LanguageTargets>$(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets</LanguageTargets>
It makes it compile on my machine, maybe it helps you, too.
@DNF-SaS Interesting, I missed that difference. I use the same form you did: https://github.com/sharwell/ILSpy/blob/88616e828f7721fa793b3a551667984dceda5bcb/ILSpy/ILSpy.csproj#L37-L40
@Latency I would strongly suggest you use my MSBuild.Sdk.Extras
package instead of adding that code to your own project. I have the WPF workarounds/"stuff" in there based on @sharwell and others' work. If there's other issues/enhancements, I'm happy to take PR's to fix.
My objective with that package is to fill the box and make it clean/simple to use with SDK style projects until there's direct support from Microsoft.
@sharwell I'll give you the same advice too for ILSpy ;) Iet's keep our efforts/workarounds consolidated if we can.
@onovotny I will be happy to give that a try.. It looks solid!
To be clear, I am removing the entire <ItemGroup>
section and the <LanguageTargets>
line also as shown in my snip-it with this?
On initial compile.. it appears to pass the pre-checks. Since, my project is broke down for reconstruction on a major build ATM, I have lots of debugging to do.. and can not validate this!
What I can tell you is that something is missing from being able to compile the XAML files now after using your .nupkg.
I am getting missing references to override OnClosing() in a few of my XAML files and about 100 less errors than my version which seems suspicious. I am not sure what order the compiler is checking things here.
Q: I assume that I would need to resolve these OnClosing() issues before seeing the other 100 problems with the project that still remain to be debugged?
Q: What am I missing now and which of these rules I posted redundant in your package? (too busy to investigate)
I have had to revert to keeping the rules from my above listed example to finish debugging my project until I can get a more clarity on which rules I must keep in conjunction with your Extensions
package.
Q: Is the Workaround
.nupkg of yours deprecated and been replaced with the Extensions
one now?
Q: For Blend 2017, it appears it is not supporting the new build configuration formats. Any thoughts regarding that? Are we supposed to wait for a fix from Microsoft on this?
Tried to convert a XAML project to the new project format today and neither the LanguageTargets
nor the MSBuild.Sdk.Extras
worked although I also use the latest SDK. Given that .Net Core 3.0 is going to come soon, when are we going to see support for this?
From @tannergooding on February 3, 2017 22:56
Attached is a simple repro solution. WpfCps.zip
Issue 1: XAML files are treated as
None
, when they should be treated asPage
withGenerator=MSBuild:Compile
andSubType=Designer
metadata. Issue 2:Page
items are not visible in the Solution Explorer Issue 3: xaml.cs files are not properly nested under the xaml file Issue 4: Compilation fails with:1>C:\windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets(419,45): error MSB4057: The target "CoreCompile" does not exist in the project.
Copied from original issue: dotnet/sdk#810