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
3.08k stars 300 forks source link

[AOT/Trim Support] ObservableRecipient.IsActive does not work #962

Open ghost1372 opened 1 month ago

ghost1372 commented 1 month ago

Describe the bug

i always use ObservableRecipient and its IsActive property, now it seems that does not support AOT/Trim.

Solution: i created a new property for this: [ObservableProperty] public bool isProcessActive;

Image

Regression

CommunityToolkit.Mvvm 8.3.2

Steps to reproduce

  1. Use ObservableRecipient and IsActive property
  2. Run app with PublishTrimmed and AOT

Expected behavior

Support AOT/Trim

Screenshots

No response

IDE and version

VS 2022

IDE version

No response

Nuget packages

Nuget package version(s)

8.3.2

Additional context

No response

Help us help you

No, just wanted to report this

ghost1372 commented 1 month ago

@Sergio0694

hawkerm commented 6 days ago

IsActive just calls either RegisterAll or UnregisterAll, these are not AOT safe, so that's the core issue.

Sergio had mentioned these should probably just end up being another source generator instead, so you don't have to manually register each interface either.

Could be a good, isolated generator issue for someone to pick up?

public partial class MyViewModel : ObservableRecipient, // or ObservableObject, etc...
    IRecipient<MyMessage1>,
    IRecipient<MyMessage2>
{
}

@Sergio0694 were you thinking it'd work like the DependencyInjection API and would there just be a partial RegisterMessages method or something added to OO?

public ObservableObject
{
    // New generated helper injection points
    partial RegisterMesssages();
    partial UnregisterMesssages();
}

Maybe these would be on OR, but in OO, the Messenger.RegisterAll method could then just go call RegisterMessages internally or something, right?

The generator would write these methods:

private void RegisterMessages()
{
    Register<MyMessage1>(this);
    Register<MyMessage2>(this);
}

private void UnregisterMessages()
{
   Unregister<MyMessage1>(this);
   Unregister<MyMessage2>(this);
}

Then IsActive would be:

public bool IsActive
{
    get;
    set
    {
        value ? RegisterMessages() : UnregisterMessages();
    }
}

It's late, so this is really rough, but it's just an initial thought to get things rolling.