Use source generators to generate ReactiveUI objects.
These Source Generators were designed to work in full with ReactiveUI V19.5.31 and newer supporting all features, currently:
- [Reactive]
- [ObservableAsProperty]
- [ObservableAsProperty(PropertyName = "ReadOnlyPropertyName")]
- [ReactiveCommand]
- [ReactiveCommand(CanExecute = nameof(IObservableBoolName))] with CanExecute
- [ReactiveCommand][property: AttribueToAddToCommand] with Attribute passthrough
- [IViewFor(nameof(ViewModelName))]
Versions older than V19.5.31 to this:
- [Reactive] fully supported,
- [ObservableAsProperty] fully supported,
- [ReactiveCommand] all options supported except Cancellation Token asnyc methods.
Typically properties are declared like this:
private string _name;
public string Name
{
get => _name;
set => this.RaiseAndSetIfChanged(ref _name, value);
}
Before these Source Generators were avaliable we used ReactiveUI.Fody.
With ReactiveUI.Fody the [Reactive]
Attribute was placed on a Public Property with Auto get / set properties, the generated code from the Source Generator and the Injected code using Fody are very similar with the exception of the Attributes.
[Reactive]
public string Name { get; set; }
Similarly, to declare output properties, the code looks like this:
public partial class MyReactiveClass : ReactiveObject
{
ObservableAsPropertyHelper<string> _firstName;
public MyReactiveClass()
{
_firstName = firstNameObservable
.ToProperty(this, x => x.FirstName);
}
public string FirstName => _firstName.Value;
private IObservable<string> firstNameObservable() => Observable.Return("Test");
}
With ReactiveUI.Fody, you can simply declare a read-only property using the [ObservableAsProperty] attribute, using either option of the two options shown below.
[ObservableAsProperty]
public string FirstName { get; }
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
[Reactive]
private string _myProperty;
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
[ObservableAsProperty]
private string _myProperty = "Default Value";
public MyReactiveClass()
{
_myPrpertyHelper = MyPropertyObservable()
.ToProperty(this, x => x.MyProperty);
}
IObservable<string> MyPropertyObservable() => Observable.Return("Test Value");
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
public MyReactiveClass()
{
// Initialize generated _myObservablePropertyHelper
// for the generated MyObservableProperty
InitializeOAPH();
}
[ObservableAsProperty]
IObservable<string> MyObservable => Observable.Return("Test Value");
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
public MyReactiveClass()
{
// Initialize generated _testValuePropertyHelper
// for the generated TestValueProperty
InitializeOAPH();
}
[ObservableAsProperty(PropertyName = TestValueProperty)]
IObservable<string> MyObservable => Observable.Return("Test Value");
}
NOTE: This does not support methods with parameters
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
public MyReactiveClass()
{
// Initialize generated _myObservablePropertyHelper
// for the generated MyObservableProperty
InitializeOAPH();
}
[ObservableAsProperty]
IObservable<string> MyObservable() => Observable.Return("Test Value");
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass : ReactiveObject
{
public MyReactiveClass()
{
// Initialize generated _testValuePropertyHelper
// for the generated TestValueProperty
InitializeOAPH();
}
[ObservableAsProperty(PropertyName = TestValueProperty)]
IObservable<string> MyObservable() => Observable.Return("Test Value");
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private void Execute() { }
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private void Execute(string parameter) { }
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private string Execute(string parameter) => parameter;
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private async Task<string> Execute(string parameter) => await Task.FromResult(parameter);
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private IObservable<string> Execute(string parameter) => Observable.Return(parameter);
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private async Task Execute(CancellationToken token) => await Task.Delay(1000, token);
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
public MyReactiveClass()
{
InitializeCommands();
}
[ReactiveCommand]
private async Task<string> Execute(string parameter, CancellationToken token)
{
await Task.Delay(1000, token);
return parameter;
}
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
private IObservable<bool> _canExecute;
[Reactive]
private string _myProperty1;
[Reactive]
private string _myProperty2;
public MyReactiveClass()
{
InitializeCommands();
_canExecute = this.WhenAnyValue(x => x.MyProperty1, x => x.MyProperty2, (x, y) => !string.IsNullOrEmpty(x) && !string.IsNullOrEmpty(y));
}
[ReactiveCommand(CanExecute = nameof(_canExecute))]
private void Search() { }
}
using ReactiveUI.SourceGenerators;
public partial class MyReactiveClass
{
private IObservable<bool> _canExecute;
[Reactive]
private string _myProperty1;
[Reactive]
private string _myProperty2;
public MyReactiveClass()
{
InitializeCommands();
_canExecute = this.WhenAnyValue(x => x.MyProperty1, x => x.MyProperty2, (x, y) => !string.IsNullOrEmpty(x) && !string.IsNullOrEmpty(y));
}
[ReactiveCommand(CanExecute = nameof(_canExecute))]
[property: JsonIgnore]
private void Search() { }
}
IVIewFor is used to link a View to a ViewModel, this is used to link the ViewModel to the View in a way that ReactiveUI can use it to bind the ViewModel to the View. The ViewModel is passed as a string to the IViewFor Attribute. The class must inherit from a UI Control from any of the following platforms and namespaces:
- Maui (Microsoft.Maui)
- WinUI (Microsoft.UI.Xaml)
- WPF (System.Windows or System.Windows.Controls)
- WinForms (System.Windows.Forms)
- Avalonia (Avalonia)
- Uno (Windows.UI.Xaml).
using ReactiveUI.SourceGenerators;
[IViewFor(nameof(MyReactiveClass))]
public partial class MyReactiveControl : UserControl
{
public MyReactiveControl()
{
InitializeComponent();
MyReactiveClass = new MyReactiveClass();
}
}
using ReactiveUI.SourceGenerators.WinForms;
[RoutedControlHost("YourNameSpace.CustomControl")]
public partial class MyCustomRoutedControlHost;
using ReactiveUI.SourceGenerators.WinForms;
[ViewModelControlHost("YourNameSpace.CustomControl")]
public partial class MyCustomViewModelControlHost;
- Add ObservableAsProperty to generate from a IObservable method with parameters.