Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot compile when using a Source Generated View-Model property with a TwoWay x:Bind #12073

Open
alove-kahua opened this issue Apr 25, 2023 · 10 comments
Labels
area/code-generation Categorizes an issue or PR as relevant to code generation area/xBind 🪢 Categorizes an issue or PR as relevant to x:Bind difficulty/medium 🤔 Categorizes an issue for which the difficulty level is reachable with a good understanding of WinUI kind/bug Something isn't working project/binding 🪢 Categorizes an issue or PR as relevant to the binding engine

Comments

@alove-kahua
Copy link
Contributor

Current behavior

Fails to compile with an error that it cannot find the ViewModel property. Note, this does work with a OneTime or OneWay x:Bind.

Expected behavior

Compiles and works at runtime.

How to reproduce it (as minimally and precisely as possible)

Use this repro project:
SourceGeneratorTwoWayBind.zip

In the MainPage.xaml, the OneWay is uncommented and the TwoWay is commented out. Uncomment the TwoWay to cause the build error.

Workaround

Do not use the generator and manually define the View-Model property.

Works on UWP/WinUI

Yes

Environment

Uno.WinUI / Uno.WinUI.WebAssembly / Uno.WinUI.Skia

NuGet package version(s)

No response

Affected platforms

WebAssembly, Build tasks

IDE

Visual Studio 2022

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

No response

@alove-kahua alove-kahua added difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification labels Apr 25, 2023
@jeromelaban jeromelaban added area/code-generation Categorizes an issue or PR as relevant to code generation and removed triage/untriaged Indicates an issue requires triaging or verification labels Apr 25, 2023
@cconner100
Copy link

any update on this item. It has me stuck now, i will have to re-write a lot of code if I cant use the generators. Really a high priority for me

@jeromelaban
Copy link
Member

This is a limitation of the C# generators (dotnet/roslyn#57239), unfortunately, as generators cannot depend on each other's output.

The only way around it is to explicitly provide properties in C# files before the compilation can happen, using T4 templates for instance.

Otherwise, you'll need to use standard {Binding} expressions, for which the evaluation happens at runtime.

@alove-kahua
Copy link
Contributor Author

I had hope considering it works in a OneWay bind. What makes it not work in the TwoWay scenario?

@jeromelaban
Copy link
Member

OneWay mostly works because the bound property does not need to be analyzed, while the TwoWay needs type conversions for the code to work properly.

@cconner100
Copy link

cconner100 commented May 4, 2023

OK not to question your response but if i create a standard WinUI3 project and add say a TextBox with the x:Bind mode=twoway it seems to work correctly.

Is there something changed in the xaml compiler for this that you guys have yet to implement.

Take a look at https://github.com/cconner100/CommunityToolkitTest
I added the code generation to the SettingsViewModel and edited the SettingsPage

Yeah its not pretty but a quick test was all i was looking for

@jeromelaban
Copy link
Member

jeromelaban commented May 4, 2023

The Microsoft WinUI toolchain does not use C# generators. It is able to introspect generated code because an intermediate assembly is generated then analyzed in a second pass.

Uno is not built using this generation sequence, and it's not something we can change easily.

There are multiple choices at this time:

  • Use {Binding }
  • Generate your partial classes based on T4 templates.
  • Use a generic base class for all your views, which implements your InitializeData methods and provides a ViewModel property.
  • Wait for Roslyn to implement generator dependencies, but it is not likely to happen soon.

@alove-kahua
Copy link
Contributor Author

A generic base view doesn't work. WPF had that limitation as well.

Would be cool if Uno could provide a hook for us to use our own generators that run first. Some specialized attribute that Uno could provide the context when its generator runs to call ours.

@jeromelaban
Copy link
Member

Indeed, that's correct, the generic base class does not work.

About having an extension, attributes probably would not cut it, though we've added internal support for MVVM Toolkit, and we've wondered if it would be useful for others to allow for extensibility points there.

@Youssef1313, that's the kind plug-in extensibility that may be useful, where a msbuild-provided registration of an additional externally-built assembly for ITypeProvider. I would guess that we'd return the generic parameter of the ViewAttribute type when TryGetType is called with the ViewModel property.

@Youssef1313
Copy link
Member

If an external assembly is provided via MSBuild, I think we will have to do some kind of assembly loading. At this point, this breaks the compiler, especially when UseSharedCompilation is true.

@jaredpar Sorry for the ping, but is there a way we can do assembly loading properly without breaking the compiler? The scenario here is we try to workaround dotnet/roslyn#57239. For our generator, all we need is the type of a generated symbol. For CommunityToolkit.Mvvm generators, we added this hack where we anticipate what will be generated. What we would like to do here is to let external consumers being able to plug in a similar implementation. I think this is not possible without loading external assemblies in the generator. So is there a way we can safely load such assemblies?

@Youssef1313
Copy link
Member

@alove-kahua For your specific scenario, would this hack work out?

- <TextBlock Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />
+ <TextBlock Text="{x:Bind _viewModel.Name, Mode=TwoWay}" />

and add private MainViewModel? _viewModel => ViewModel; in page's code behind.

@MartinZikmund MartinZikmund added area/xBind 🪢 Categorizes an issue or PR as relevant to x:Bind project/binding 🪢 Categorizes an issue or PR as relevant to the binding engine difficulty/medium 🤔 Categorizes an issue for which the difficulty level is reachable with a good understanding of WinUI and removed difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. labels Sep 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/code-generation Categorizes an issue or PR as relevant to code generation area/xBind 🪢 Categorizes an issue or PR as relevant to x:Bind difficulty/medium 🤔 Categorizes an issue for which the difficulty level is reachable with a good understanding of WinUI kind/bug Something isn't working project/binding 🪢 Categorizes an issue or PR as relevant to the binding engine
Projects
None yet
Development

No branches or pull requests

5 participants