Skip to content

Commit

Permalink
Merge pull request #240 from Cysharp/IReadOnlyBindableReactiveProperty_T
Browse files Browse the repository at this point in the history
Add IReadOnlyBindableReactiveProperty<T>
  • Loading branch information
neuecc authored Aug 6, 2024
2 parents 57abddc + ac5974d commit 3b2570d
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ public class ValidationViewModel : IDisposable

![image](https://github.com/Cysharp/R3/assets/46207/f80149e6-1573-46b5-9a77-b78776dd3527)

There is also `IReadOnlyBindableReactiveProperty`, which is preferable when ReadOnly is required in binding. However, unless there are special circumstances, it is recommended to use `BindableReactiveProperty<T>`, which allows mutability.
There is also `IReadOnlyBindableReactiveProperty<T>`, which is preferable when ReadOnly is required in binding, can create from `IObservable<T>.ToReadOnlyBindableReactiveProperty<T>`.

### ReactiveCommand

Expand Down
2 changes: 1 addition & 1 deletion sandbox/WpfApp1/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ protected override void OnClosed(EventArgs e)
public class BasicUsagesViewModel : IDisposable
{
public BindableReactiveProperty<string> Input { get; }
public IReadOnlyBindableReactiveProperty Output { get; }
public IReadOnlyBindableReactiveProperty<string> Output { get; }

public BasicUsagesViewModel()
{
Expand Down
61 changes: 59 additions & 2 deletions src/R3/BindableReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,38 @@ public interface IReadOnlyBindableReactiveProperty : INotifyPropertyChanged, INo
object? Value { get; }
}

public interface IReadOnlyBindableReactiveProperty<T> : IReadOnlyBindableReactiveProperty
{
new T Value { get; }
IReadOnlyBindableReactiveProperty<T> EnableValidation();
IReadOnlyBindableReactiveProperty<T> EnableValidation(Func<T, Exception?> validator);
IReadOnlyBindableReactiveProperty<T> EnableValidation<TClass>([CallerMemberName] string? propertyName = null!);
IReadOnlyBindableReactiveProperty<T> EnableValidation(Expression<Func<IReadOnlyBindableReactiveProperty<T>?>> selfSelector);
Observable<T> AsObservable();
}

public interface IBindableReactiveProperty : IReadOnlyBindableReactiveProperty
{
new object? Value { get; set; }
void OnNext(object? value);
}

public interface IBindableReactiveProperty<T> : IBindableReactiveProperty, IReadOnlyBindableReactiveProperty<T>
{
new T Value { get; set; }
void OnNext(T value);
new IBindableReactiveProperty<T> EnableValidation();
new IBindableReactiveProperty<T> EnableValidation(Func<T, Exception?> validator);
new IBindableReactiveProperty<T> EnableValidation<TClass>([CallerMemberName] string? propertyName = null!);
IBindableReactiveProperty<T> EnableValidation(Expression<Func<IBindableReactiveProperty<T>?>> selfSelector);
}

// all operators need to call from UI Thread(not thread-safe)

#if NET6_0_OR_GREATER
[System.Text.Json.Serialization.JsonConverter(typeof(BindableReactivePropertyJsonConverterFactory))]
#endif
public class BindableReactiveProperty<T> : ReactiveProperty<T>, IBindableReactiveProperty
public class BindableReactiveProperty<T> : ReactiveProperty<T>, IBindableReactiveProperty<T>
{
IDisposable? subscription;

Expand Down Expand Up @@ -260,12 +280,49 @@ void IBindableReactiveProperty.OnNext(object? value)
OnNext((T)value!);
}

// IBindableReadOnlyReactiveProperty
IBindableReactiveProperty<T> IBindableReactiveProperty<T>.EnableValidation() => EnableValidation();

IBindableReactiveProperty<T> IBindableReactiveProperty<T>.EnableValidation(Func<T, Exception?> validator) => EnableValidation(validator);

IBindableReactiveProperty<T> IBindableReactiveProperty<T>.EnableValidation<TClass>(string? propertyName) => EnableValidation<TClass>(propertyName);

IBindableReactiveProperty<T> IBindableReactiveProperty<T>.EnableValidation(Expression<Func<IBindableReactiveProperty<T>?>> selfSelector)
{
var memberExpression = (MemberExpression)selfSelector.Body;
var propertyInfo = (PropertyInfo)memberExpression.Member;
SetValidationContext(propertyInfo);

enableNotifyError = true;
return this;
}

// IReadOnlyBindableReactiveProperty

object? IReadOnlyBindableReactiveProperty.Value
{
get => Value;
}

IReadOnlyBindableReactiveProperty<T> IReadOnlyBindableReactiveProperty<T>.EnableValidation() => EnableValidation();

IReadOnlyBindableReactiveProperty<T> IReadOnlyBindableReactiveProperty<T>.EnableValidation(Func<T, Exception?> validator) => EnableValidation(validator);

IReadOnlyBindableReactiveProperty<T> IReadOnlyBindableReactiveProperty<T>.EnableValidation<TClass>(string? propertyName) => EnableValidation<TClass>(propertyName);

IReadOnlyBindableReactiveProperty<T> IReadOnlyBindableReactiveProperty<T>.EnableValidation(Expression<Func<IReadOnlyBindableReactiveProperty<T>?>> selfSelector)
{
var memberExpression = (MemberExpression)selfSelector.Body;
var propertyInfo = (PropertyInfo)memberExpression.Member;
SetValidationContext(propertyInfo);

enableNotifyError = true;
return this;
}

public Observable<T> AsObservable()
{
return this;
}
}

internal sealed class PropertyValidationContext(ValidationContext context, ValidationAttribute[] attributes)
Expand Down
5 changes: 3 additions & 2 deletions src/R3/ReactivePropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public static BindableReactiveProperty<T> ToBindableReactiveProperty<T>(this Obs
return new BindableReactiveProperty<T>(source, initialValue, equalityComparer);
}

public static IBindableReactiveProperty ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, T initialValue = default!)
public static IReadOnlyBindableReactiveProperty<T> ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, T initialValue = default!)
{
return new BindableReactiveProperty<T>(source, initialValue, EqualityComparer<T>.Default);
}

public static IBindableReactiveProperty ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, IEqualityComparer<T>? equalityComparer, T initialValue = default!)
public static IReadOnlyBindableReactiveProperty<T> ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, IEqualityComparer<T>? equalityComparer, T initialValue = default!)
{
return new BindableReactiveProperty<T>(source, initialValue, equalityComparer);
}
Expand Down Expand Up @@ -74,3 +74,4 @@ protected override void OnCompletedCore(Result result)
}
}
}

0 comments on commit 3b2570d

Please sign in to comment.