CommunityToolkit / dotnet

.NET Community Toolkit is a collection of helpers and APIs that work for all .NET developers and are agnostic of any specific UI platform. The toolkit is maintained and published by Microsoft, and part of the .NET Foundation.
https://docs.microsoft.com/dotnet/communitytoolkit/?WT.mc_id=dotnet-0000-bramin
Other
2.99k stars 294 forks source link

.net 4.7.2 Accessing properties causing compilation error #643

Open chocobot opened 1 year ago

chocobot commented 1 year ago

Describe the bug

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    public string _title = "Window Name";

    [ObservableProperty] 
    public string _buttonCaption = "This is a button";

    [RelayCommand(CanExecute = nameof(CanRunTestButton))]
    public void RunTestButton()
    {
        Title = "The window name has changed";
    }

    public bool CanRunTestButton()
    {
        return Title == "Window Name";
    }     
}

When running this example, I am getting a compile error stating

Rebuild started... 1>------ Rebuild All started: Project: LearningFramework, Configuration: Debug Any CPU ------ Restored C:\Users\iifuz\source\repos\LearningFramework\LearningFramework\LearningFramework.csproj (in 10 ms). 1>C:\Users\iifuz\source\repos\LearningFramework\LearningFramework\Windows\Main\MainViewModel.cs(26,13,26,18): error CS0103: The name 'Title' does not exist in the current context 1>C:\Users\iifuz\source\repos\LearningFramework\LearningFramework\Windows\Main\MainViewModel.cs(31,20,31,25): error CS0103: The name 'Title' does not exist in the current context ========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ========== ========== Rebuild started at 7:58 AM and took 00.578 seconds ==========

Without accessing the Title property, data binding is working fine in the XAML.

I did see a separate closed issue on this github regarding a IncludePackageReferencesDuringMarkupCompilation property to set within the csproj, however this is not available in 4.7.2 from what I can tell?

Steps to reproduce

Compile the code in the description.

Expected behavior

That the code compiles and binds accordingly.

Visual Studio Version

2022

Help us help you

Yes, I'd like to be assigned to work on this item.

ghost commented 1 year ago

Hello chocobot, thank you for opening an issue with us!

I have automatically added a "needs triage" label to help get things started. Our team will analyze and investigate the issue, and escalate it to the relevant team if possible. Other community members may also look into the issue and provide feedback 🙌

Sergio0694 commented 1 year ago

Hey @chocobot, are you using packages.config by any chance? Or did you reference the MVVM Toolkit through PackageReference?

chocobot commented 1 year ago

Yes I did, I switched to package reference and switched the c# version to 11 in the csproj..

I can databind the Title property to the window title in the XAML I can bind the button command and it triggers properly..

However, as soon as I try to reference the Title property within the view model, nothing will compile.

Sergio0694 commented 1 year ago

Is this using the MVVM Toolkit 8.1? Does it also repro with 8.0?

Sergio0694 commented 1 year ago

Hey @chocobot, friendly ping, we need your feedback to be able to properly triage this 🙂 Are you never able to compile when directly referencing those properties in code? What version of VS are you using? And is this with the MVVM Toolkit 8.0 or 8.1? If with the 8.1, do you also repro the same issue if you try going back to 8.0?

Thank you! 🙂

iBoundary commented 1 year ago

I am using the latest version 8.1.0 and I have also encountered this problem. Is there a solution? @Sergio0694

akarboush commented 1 year ago

@Sergio0694 I'm having the same problem myself with all versions actually 7.1.2, 8.0.0, 8.1.0 and 8.2.0. I tried 4.8 and 4.7.2 also but without success. The wired thing is that accessing a generated property will only cause the build to fail if the generation happens in the WPF project, if it's in a class library (4.8) it won't cause any problems and you can access it in both the class library and the WPF project referencing it.

@iBoundary @chocobot might be a workaround for you.

MH-ZShearer commented 1 year ago

Here is a minimal reproducible solution. https://github.com/MH-ZShearer/SourceGeneratorTest

The same exact code in a .NET 7.0 application works, but this .NET Framework 4.8 fails to compile with:

error CS0103: The name 'TestCommand' does not exist in the current context

I have tried v8.0, v8.1, and v8.2 and all of them provide the same issue. I am currently using VS v17.6.3.

It is worth noting that the generators are generating the expected code and the application works as expected, but only if there are no references in C# to the generated properties or commands. In this case, if we replace nameof(TestCommand) with the string literal "TestCommand", the application compiles as expected, but this is an unsustainable workaround.

VergilGao commented 1 year ago

@Sergio0694 I'm having the same problem myself with all versions actually 7.1.2, 8.0.0, 8.1.0 and 8.2.0. I tried 4.8 and 4.7.2 also but without success. The wired thing is that accessing a generated property will only cause the build to fail if the generation happens in the WPF project, if it's in a class library (4.8) it won't cause any problems and you can access it in both the class library and the WPF project referencing it.

@iBoundary @chocobot might be a workaround for you.

add <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> into your PropertyGroup like this

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <UseWPF>true</UseWPF>
    <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
  </PropertyGroup>
VergilGao commented 1 year ago

Here is a minimal reproducible solution. https://github.com/MH-ZShearer/SourceGeneratorTest

The same exact code in a .NET 7.0 application works, but this .NET Framework 4.8 fails to compile with:

error CS0103: The name 'TestCommand' does not exist in the current context

I have tried v8.0, v8.1, and v8.2 and all of them provide the same issue. I am currently using VS v17.6.3.

It is worth noting that the generators are generating the expected code and the application works as expected, but only if there are no references in C# to the generated properties or commands. In this case, if we replace nameof(TestCommand) with the string literal "TestCommand", the application compiles as expected, but this is an unsustainable workaround.

This is because you used the old csproj file when building the netFramework project, and the easiest way to build the project is to build a net7 project first, and then manually modify the .csproj file to change 'TargetFramework' to net48

akarboush commented 1 year ago

add <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> into your PropertyGroup like this

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <UseWPF>true</UseWPF>
    <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
  </PropertyGroup>

Appreciate it @VergilGao . It works

Edit: no It's not working. It could be that I tried with an another project, not sure how.

It seems like the IncludePackageReferencesDuringMarkupCompilation is completely ignored in the GenerateTemporaryTargetAssembly - where the problem occurs according to the binlog file - target task

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (used in .net 48)

 <GenerateTemporaryTargetAssembly
          CurrentProject="$(MSBuildProjectFullPath)"
          MSBuildBinPath="$(MSBuildBinPath)"
          ReferencePathTypeName="ReferencePath"
          CompileTypeName="Compile"
          GeneratedCodeFiles="@(_GeneratedCodeFiles)"
          ReferencePath="@(ReferencePath)"
          IntermediateOutputPath="$(IntermediateOutputPath)"
          AssemblyName="$(AssemblyName)"
          CompileTargetName="$(_CompileTargetNameForLocalType)"
          GenerateTemporaryTargetAssemblyDebuggingInformation="$(GenerateTemporaryTargetAssemblyDebuggingInformation)"
                 >

the corresponding for .net 7

 <GenerateTemporaryTargetAssembly
                CurrentProject="$(MSBuildProjectFullPath)"
                MSBuildBinPath="$(MSBuildBinPath)"
                ReferencePathTypeName="ReferencePath"
                CompileTypeName="Compile"
                AnalyzerTypeName="Analyzer"
                GeneratedCodeFiles="@(_GeneratedCodeFiles)"
                ReferencePath="@(ReferencePath)"
                BaseIntermediateOutputPath="$(BaseIntermediateOutputPath)"
                IntermediateOutputPath="$(_IntermediateOutputPathNoTargetFrameworkOrRID)"
                AssemblyName="$(AssemblyName)"
                CompileTargetName="$(_CompileTargetNameForLocalType)"
                GenerateTemporaryTargetAssemblyDebuggingInformation="$(GenerateTemporaryTargetAssemblyDebuggingInformation)"
                IncludePackageReferencesDuringMarkupCompilation="$(IncludePackageReferencesDuringMarkupCompilation)"
                Analyzers="@(Analyzer)"
                TemporaryTargetAssemblyProjectName="$(_TemporaryTargetAssemblyProjectName)"
                MSBuildProjectExtensionsPath="$(MSBuildProjectExtensionsPath)"
                 >
MH-ZShearer commented 1 year ago

This is because you used the old csproj file when building the netFramework project, and the easiest way to build the project is to build a net7 project first, and then manually modify the .csproj file to change 'TargetFramework' to net48

@VergilGao while that works for this scenario, it does not work for our monolithic legacy application. The SDK style csproj format for .NET Framework 4.8 does not support ClickOnce, for example. I did verify this solution works for new projects, however, but it cannot be used to retrofit legacy applications.

If you have any other suggestions, I'd be glad to give it a go.

abdes commented 1 year ago

Adding <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> results in new errors due to the task GenerateTemporaryTargetAssembly being executed. This particular task was responsible for creating the *_wpftmp.csproj.

It seems that these temporary assemblies, project names, or what-have-you were also perhaps in part responsible for failure to resolve types defined in the same assembly.

Apparently, this setting defaulted to false in .NET 5.0, however that is no longer the case in .NET 6.0. Indeed, it is on by default, and it would appear that this option, when enabled, is what is responsible for generating all those temporary assemblies and causing resolution errors as well warnings due to underscores in the file names of these temporary assemblies.

Adding <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> does not really resolve the issue.

HppZ commented 4 months ago

Here is a minimal reproducible solution. https://github.com/MH-ZShearer/SourceGeneratorTest

The same exact code in a .NET 7.0 application works, but this .NET Framework 4.8 fails to compile with:

error CS0103: The name 'TestCommand' does not exist in the current context

I have tried v8.0, v8.1, and v8.2 and all of them provide the same issue. I am currently using VS v17.6.3.

It is worth noting that the generators are generating the expected code and the application works as expected, but only if there are no references in C# to the generated properties or commands. In this case, if we replace nameof(TestCommand) with the string literal "TestCommand", the application compiles as expected, but this is an unsustainable workaround.

SAME here!

HppZ commented 4 months ago

1, migrate packages.config file 2, migrate csproj file using CsprojToVs2017 3, done!

akarboush commented 4 months ago

@HppZ exactly, the problem seems to exist only in the legecy csproj style, using the upgrade-assistant tool to upgrade the project to the SDK style solved the problem for me too