[Feature] Being able to subscribe actions when RelayCommand is executed
Overview
Context
I'm using Avalonia UI for a simple project where the MainWindow opens a dialog window. When the dialog closes, I want to get back the dialog result, which in my case is the dialog window view model. To be able to return an object when the dialog closes, I need a way to tell the OK/CANCEL buttons in the dialog to execute the Avalonia window's Close(object dialogResult) method.
To achieve that, I need to put inside the dialog view model an action like public Action<DialogWindowViewModel>? Close { get; set; }, and call it when the related command gets triggered like this:
public partial class DialogWindowViewModel : ObservableObject
{
[RelayCommand]
private void Ok()
{
Result = "OK";
Close?.Invoke(this);
}
}
In order for it to work, I need to "subscribe" to the Close action inside the view model from the dialog window code-behind:
public partial class DialogWindow : Window
{
public DialogWindow()
{
InitializeComponent();
Activated += (_, _) => ((DialogWindowViewModel)DataContext!).Close = Close;
}
}
This is the only way I found to implement it, without involving third-party frameworks like ReactiveUI, but I feel like it's leaking some View logic inside the ViewModel.
API breakdown
public sealed class RelayCommand : IRelayCommand, IObservable<Object>
{
// implements the Subscribe method
}
Then we can use the public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext) extension method to add the action we want to be invoked when the command is executed.
Usage example
public partial class DialogWindow : Window
{
public DialogWindow()
{
InitializeComponent();
Activated += (_, _) => ((DialogWindowViewModel)DataContext!).OkCommand.Subscribe(Close);
}
}
Breaking change?
I'm not sure
Alternatives
Use the ReactiveCommand from ReactiveUI instead of the CommunityTollkit's RelayCommand, and subscribe from dialog's code-behind:
public partial class DialogWindow : ReactiveWindow<DialogWindowViewModel>
{
public DialogWindow()
{
InitializeComponent();
this.WhenActivated(d => d(ViewModel!.OkCommand.Subscribe(Close)));
}
}
Additional context
No response
Help us help you
Yes, but only if others can assist