CommunityToolkit / CommunityToolkit/dotnet
Cannot override Broadcast when using ObservableRecipient attribute
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 400
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the bug
Documentation of `ObservableRecipient.Broadcast` indicate that Broadcast(...) should be overridden in order to use a custom channel (token). If we need to use the features of `ObservableValidator` and need to use `[NotifyPropertyChangedRecipients]`, then we need to use `[ObservableRecipient]` on the class in order to have the missing pieces. I couldn't read online the documentation of the `ObservableRecipient.Broadcast` method generated by the attribute since the API docs for this dotnet CommunityToolkit aren't published on Microsoft Learn, only the old Windows Community Toolkit 7.0.0 are available (https://learn.microsoft.com/en-us/dotnet/api/communitytoolkit.mvvm.componentmodel.observablerecipient?view=win-comm-toolkit-dotnet-7.0) (and it didn't exist). So I referred to the XML docs in the SourceLink using F12 in Visual Studio.
### Regression
_No response_
### Steps to reproduce
I made a new empty WPF project, and created a little sample pointing out what works and also the problem when wanting to add ObservableValidator in the mix.
```csharp
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using System;
using System.ComponentModel.DataAnnotations;
namespace WpfApp3
{
public partial class MyFirstObservableClass : ObservableRecipient
{
[ObservableProperty]
[NotifyPropertyChangedRecipients]
private int myFirstIntProperty;
[ObservableProperty]
[NotifyPropertyChangedRecipients]
private int myFirstIntProperty2;
protected override void Broadcast(T oldValue, T newValue, string? propertyName)
{
var message = new PropertyChangedMessage(this, propertyName, oldValue, newValue);
_ = Messenger.Send(message, $"{nameof(MyFirstObservableClass)}.{propertyName}");
}
}
[ObservableRecipient]
public partial class MySecondObservableClass : ObservableValidator
{
[ObservableProperty]
[Range(1, 21)]
[NotifyPropertyChangedRecipients]
private int mySecondIntProperty;
//// Severity Code Description Project File Line Suppression State
//// Error CS0111 Type 'MySecondObservableClass' already defines a member called 'Broadcast' with the same parameter types WpfApp3 CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.ObservableRecipientGenerator\WpfApp3.MySecondObservableClass.g.cs 111 Active
//protected virtual void Broadcast(T oldValue, T newValue, string? propertyName)
//{
// var message = new PropertyChangedMessage(this, propertyName, oldValue, newValue);
// _ = Messenger.Send(message, nameof(MySecondIntProperty));
//}
//// Same error CS0111 at build, but also the following IntelliSense when writing:
////
//// Severity Code Description Project File Line Suppression State
//// Error CS0115 'MySecondObservableClass.Broadcast(T, T, string?)': no suitable method found to override WpfApp3 C:\Users\\WpfApp3\WpfApp3\MyObservableClass.cs 49 Active
//protected override void Broadcast(T oldValue, T newValue, string? propertyName)
//{
// var message = new PropertyChangedMessage(this, propertyName, oldValue, newValue);
// _ = Messenger.Send(message, nameof(MySecondIntProperty));
//}
}
public partial class MyFirstRecipient
: ObservableRecipient,
IRecipient>
{
public MyFirstRecipient()
{
IsActive = true;
}
public void Receive(PropertyChangedMessage message)
{
throw new NotImplementedException();
}
}
public partial class MySecondRecipient
: ObservableRecipient,
IRecipient>
{
public MySecondRecipient()
{
IsActive = true;
}
protected override void OnActivated()
{
Messenger.RegisterAll(
this,
$"{nameof(MyFirstObservableClass)}.{nameof(MyFirstObservableClass.MyFirstIntProperty2)}"
);
}
public void Receive(PropertyChangedMessage message)
{
throw new NotImplementedException();
}
}
public partial class MyThirdRecipient : ObservableRecipient
{
[ObservableProperty]
private int fromMyFirstIntProperty;
public MyThirdRecipient()
{
IsActive = true;
}
protected override void OnActivated()
{
// Using a method group...
Messenger.Register, string>(
this,
$"{nameof(MyFirstObservableClass)}.{nameof(MyFirstObservableClass.MyFirstIntProperty)}",
(r, m) => r.Receive1(m)
);
Messenger.Register, string>(
this,
$"{nameof(MyFirstObservableClass)}.{nameof(MyFirstObservableClass.MyFirstIntProperty2)}",
(r, m) => r.Receive2(m)
);
base.OnActivated();
}
public void Receive(PropertyChangedMessage message)
{
throw new NotImplementedException();
}
public void Receive1(PropertyChangedMessage message)
{
if (
message.Sender.GetType() == typeof(MyFirstObservableClass)
&& message.PropertyName == nameof(MyFirstObservableClass.MyFirstIntProperty)
)
{
FromMyFirstIntProperty = message.NewValue;
}
}
public void Receive2(PropertyChangedMessage message)
{
if (
message.Sender.GetType() == typeof(MyFirstObservableClass)
&& message.PropertyName == nameof(MyFirstObservableClass.MyFirstIntProperty2)
)
{
FromMyFirstIntProperty = message.NewValue;
}
}
}
}
```
### Expected behavior
Be able to use the token feature with `[NotifyPropertyChangedRecipients]` when using an `ObservableValidator` class, thus I must be able to override the `Broadcast` method.
### Screenshots
_No response_
### IDE and version
VS 2022
### IDE version
VisualStudio.17.Release/17.6.4+33815.320
### Nuget packages
- [ ] CommunityToolkit.Common
- [ ] CommunityToolkit.Diagnostics
- [ ] CommunityToolkit.HighPerformance
- [X] CommunityToolkit.Mvvm (aka MVVM Toolkit)
### Nuget package version(s)
8.2.0
### Additional context
In the source generator ObservableRecipientGenerator.cs, there is already some logic to not generate some methods if it already exists.
https://github.com/CommunityToolkit/dotnet/blob/e071ed22b379f904820475db827be3ad04d3e96e/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs
What I would see as a solution would be to have the same kind of checks, for other methods, like `Broadcast`, and we would probably see this file have a new field in the record:
https://github.com/CommunityToolkit/dotnet/blob/e071ed22b379f904820475db827be3ad04d3e96e/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/ObservableRecipientInfo.cs
### Help us help you
No, just wanted to report this
Contributor guide
Assessment
This issue has not been assessed yet.