An MVVM library, based on ReactiveUI, using SourceGenerator and Fody for mixed source code generation.
Adding Notifications to Properties Using Fody and SourceGenerator
partial class MyViewModel : ReactiveObject
{
[ReactiveProperty]
public string Name { get; set; } = string.Empty;
}
Generated code
partial class MyViewModel : ReactiveObject
{
private string $Name;
[ReactiveProperty]
public string Name
{
get => $Name;
set => RaiseAndSetName(ref $Name, value, true);
}
private void RaiseAndSetName(ref string backingField, string newValue, bool check = true)
{
if (!check || !EqualityComparer<string>.Default.Equals(backingField, newValue))
{
string oldValue = backingField;
this.RaisePropertyChanging("Name");
OnNameChanging(oldValue, newValue);
backingField = newValue;
this.RaisePropertyChanged("Name");
OnNameChanged(oldValue, newValue);
}
}
}
Adding Command Properties to Methods Using the Source Generator
partial class MyViewModel : ReactiveObject
{
[ReactiveCommand]
public void Test() { }
[ReactiveCommand]
public async Task TestAsync() { }
}
Generated code
partial class MyViewModel : ReactiveObject
{
private ReactiveCommand<Unit, Unit> _testCommand;
public ReactiveCommand<Unit, Unit> TestCommand =>
_testCommand ?? (_testCommand = ReactiveCommand.Create(Test));
private ReactiveCommand<Unit, Unit> _testAsyncCommand;
public ReactiveCommand<Unit, Unit> Test1AsyncCommand =>
_testAsyncCommand ?? (_testAsyncCommand = ReactiveCommand.CreateFromTask(TestAsync));
[ReactiveCommand]
public void Test() { }
[ReactiveCommand]
public async Task TestAsync() { }
}
Notify property when target property changed
A field is generated to cache the value when EnableCache
is true
partial class MyViewModel : ReactiveObject
{
[NotifyPropertyChangeFrom(nameof(ID), nameof(Name))]
public bool IsSame => ID == Name;
protected void InitializeReactiveObject() { }
}
Generated code
partial class MyViewModel : ReactiveObject
{
private bool _isSame;
[NotifyPropertyChangeFrom(nameof(ID), nameof(Name))]
public bool IsSame => _isSame;
protected void InitializeReactiveObject()
{
// InitializeInInitializeObject = true
_isSame = Name == ID;
}
protected void RaiseIsSameChange()
{
this.RaiseAndSetIfChanged(ref _isSame, Name == ID, "IsSame");
}
private void RaiseAndSetName(ref string backingField, string newValue, bool check = true)
{
...
this.RaisePropertyChanged("Name");
RaiseIsSameChange();
}
private void RaiseAndSetID(ref string backingField, string newValue, bool check = true)
{
...
this.RaisePropertyChanged("ID");
RaiseIsSameChange();
}
}
When EnableCache
is false
partial class MyViewModel : ReactiveObject
{
[NotifyPropertyChangeFrom(nameof(ID), nameof(Name), EnableCache = false)]
public bool IsSame => ID == Name;
protected void InitializeReactiveObject() { }
}
Generated code
partial class MyViewModel : ReactiveObject
{
private bool _isSame;
[NotifyPropertyChangeFrom(nameof(ID), nameof(Name), EnableCache = false)]
public bool IsSame => Name == ID;
protected void InitializeReactiveObject()
{
// InitializeInInitializeObject = true
_isSame = Name == ID;
}
protected void RaiseIsSameChange()
{
this.RaiseAndSetIfChanged(ref _isSame, Name == ID, "IsSame");
}
private void RaiseAndSetName(ref string backingField, string newValue, bool check = true)
{
...
this.RaisePropertyChanging("Name");
this.RaisePropertyChanging("IsSame");
backingField = newValue;
this.RaisePropertyChanged("Name");
this.RaisePropertyChanged("IsSame");
...
}
private void RaiseAndSetID(ref string backingField, string newValue, bool check = true)
{
...
this.RaisePropertyChanging("ID");
this.RaisePropertyChanging("IsSame");
backingField = newValue;
this.RaisePropertyChanged("ID");
this.RaisePropertyChanged("IsSame");
...
}
}